Instalacja Discourse na VPS z Docker krok po kroku
Dowiedz się, jak poprawnie zainstalować Discourse na własnym VPS przy użyciu oficjalnego skryptu launcher. Instrukcja obejmuje konfigurację app.yml, SMTP, TLS oraz swap.
Instalacja Discourse na VPS: jeden kontener, jeden plik konfiguracyjny
Aby zainstalować Discourse na serwerze VPS, należy uruchomić własny instalator projektu, odpowiedzieć na pytania krótkiego kreatora i poczekać na zakończenie budowania. Discourse jest dostarczany jako pojedynczy kontener Docker zawierający aplikację Rails, PostgreSQL, Redis oraz nginx. Wszystkie późniejsze zmiany wprowadza się w jednym pliku, /var/discourse/containers/app.yml, a każda modyfikacja wymaga przebudowania instancji.
Oficjalna metoda instalacji to discourse_docker: skrypt powłoki launcher oraz zestaw szablonów YAML. Discourse nie obsługuje samodzielnie tworzonych plików Compose, a kontenera nie należy dzielić ręcznie. Jeśli użytkownik jest przyzwyczajony do uruchamiania usług na VPS za pomocą Docker Compose, należy spodziewać się innej struktury. W tym przypadku nie używa się docker compose up -d, a procesem wdrażania zarządza ./launcher rebuild app.
Wymagania wstępne dla Discourse
Cztery wymagania często sprawiają trudności, a każde z nich staje się przeszkodą jeszcze przed dotarciem do strony logowania.
- Pamięć RAM. Jeden kontener uruchamia PostgreSQL, Redis, Sidekiq oraz serwer WWW Ruby. Proces budowania kompiluje zasoby i wymaga więcej pamięci niż działająca witryna.
- Prawdziwa nazwa domeny. Dostarczona przykładowa konfiguracja jasno to określa: "Discourse nie będzie działać z samym adresem IP".
- Ścieżka wychodzącej poczty elektronicznej. Aktywacja konta, resetowanie haseł, zaproszenia dla administratorów oraz podsumowania wiadomości są wysyłane przez SMTP (simple mail transfer protocol).
- Wolne porty 80 oraz 443 na hoście, chyba że świadomie umieścisz Discourse za już działającym proxy.
The data behind this chart
[
{
"label": "Documented minimum",
"ram_gb": 1,
"storage_gb": 10
},
{
"label": "Documented recommended",
"ram_gb": 2,
"storage_gb": 20
}
]Oficjalna dokumentacja instalacji określa dolną granicę na 1 GB pamięci RAM wraz z partycją wymiany (swap) oraz 10 GB miejsca na dysku, zalecając jednocześnie 2 GB pamięci RAM oraz 20 GB miejsca na dysku. Pierwszą wartość należy traktować jako minimum pozwalające na ukończenie instalacji, a nie jako konfigurację docelową dla działającej społeczności. Różnica jest istotna, ponieważ szczytowe zapotrzebowanie na pamięć występuje podczas budowania, a nie podczas obsługi ruchu.
Skieruj domenę na serwer przed instalacją
Utwórz rekord A dla używanej nazwy hosta, a następnie potwierdź go z poziomu serwera.
dig +short forum.example.com
curl -4 -s https://ifconfig.coOba polecenia muszą zwrócić ten sam adres. Muszą być zgodne, ponieważ kreator konfiguracji wykonuje test połączenia z nazwą hosta, a rekord wskazujący w inne miejsce spowoduje niepowodzenie tego testu. Rekord utworzony przed chwilą może być nadal w pamięci podręcznej, więc należy odczekać czas wygaśnięcia starego TTL (time to live), zamiast wymuszać działanie kreatora.
Zdecyduj teraz, czy rekord będzie obsługiwany przez CDN. Rekord z włączonym proxy ukrywa adres serwera, co powoduje niepowodzenie żądania certyfikatu dla kontenera, ponieważ wyzwanie ACME (automatic certificate management environment) jest odbierane przez proxy, a nie przez Discourse. Podczas pierwszej instalacji rekord powinien pozostać bez włączonego proxy.
Uruchomienie oficjalnego instalatora
Jedno polecenie instaluje git, instaluje Docker za pomocą oficjalnego skryptu instalacyjnego, klonuje discourse_docker do /var/discourse i uruchamia kreator konfiguracji.
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bashJeśli Docker jest już zainstalowany na serwerze i preferowana jest ręczna weryfikacja każdego kroku, należy wykonać te same czynności samodzielnie.
sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setupPolecenie należy uruchomić z uprawnieniami root. Uruchomienie przez zwykłego użytkownika powoduje natychmiastowe zatrzymanie discourse-setup z komunikatem This script must be run as root. Please sudo or log in as root first.. W przypadku braku Docker na serwerze proces zatrzymuje się z komunikatem Docker is not installed. Please install Docker first., ponieważ ręczne klonowanie nie przeprowadza żadnej automatycznej instalacji.
O co pyta kreator konfiguracji i co zapisuje
Według stanu na sierpień 2026 discourse-setup jest lekką nakładką. Uruchamia ona discourse/setup-wizard:release jako kontener z dostępem do sieci hosta oraz zamontowanym gniazdem Docker, dzięki czemu kreator może zbadać maszynę, którą konfiguruje. Narzędzie pyta o nazwę hosta i adresy e-mail administratora, a następnie o dane serwera SMTP. Zapisuje plik containers/app.yml, a następnie przebudowuje konfigurację.
Przed rozpoczęciem warto poznać dwa zachowania systemu. Jeśli maszynie brakuje pamięci RAM i nie posiada partycji wymiany (swap), kreator przerywa pracę i oferuje jej utworzenie: nakładka tworzy wtedy plik /swapfile o rozmiarze 2 GB, dodaje go do /etc/fstab, ustawia vm.swappiness = 10 w pliku /etc/sysctl.d/30-discourse-swap.conf i ponownie uruchamia kreatora. Po zakończeniu pracy kreator wyświetla komunikat Rebuilding app in 5 seconds (Ctrl+C to cancel)... i uruchamia ./launcher rebuild app na hoście. Budowanie trwa kilka minut na małym serwerze VPS, a pierwsze uruchomienie jest najwolniejsze, ponieważ wszystkie zasoby są kompilowane od zera.
./discourse-setup --help zawiera listę flag, które mają znaczenie w przypadku wystąpienia problemów. --skip-rebuild zapisuje konfigurację bez budowania, a --skip-connection-test pomija testy DNS oraz portów. Używaj --skip-connection-test tylko wtedy, gdy znasz przyczynę niepowodzenia testu, na przykład gdy host znajduje się za kontrolowanym przez Ciebie firewallem sieciowym.
Przed pierwszą przebudową przeczytaj plik app.yml
Kreator tworzy plik, za którego utrzymanie odpowiadasz teraz Ty. Otwórz go za pomocą sudo nano /var/discourse/containers/app.yml. Poniższe sekcje decydują o niemal wszystkich aspektach działania.
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
expose:
- "80:80" # http
- "443:443" # https
env:
DISCOURSE_HOSTNAME: "forum.example.com"
DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: user@example.com
DISCOURSE_SMTP_PASSWORD: "your-smtp-password"DISCOURSE_HOSTNAME to adres, pod którym odpowiada witryna; Discourse buduje na jego podstawie swoje odnośniki, więc błędna wartość spowoduje, że strona załaduje się raz, a następnie przekieruje użytkownika w inne miejsce. DISCOURSE_DEVELOPER_EMAILS to lista adresów rozdzielonych przecinkami; adresy te automatycznie uzyskują uprawnienia administratora przy pierwszej rejestracji. Wpisz tam swój adres i zarejestruj się za jego pomocą, ponieważ w ten sposób tworzone jest pierwsze konto administratora.
Plik przechowuje hasło SMTP w postaci jawnej, dlatego ogranicz dostęp do katalogu za pomocą sudo chmod 700 /var/discourse/containers. Jest to również format YAML, co oznacza, że białe znaki są częścią konfiguracji: źle wyrównany klucz spowoduje niepowodzenie budowania z błędem parsowania i brak działającej witryny. Jedna z pułapek została opisana w samym przykładowym pliku. Znak # wewnątrz nieobjętego cudzysłowem hasła rozpoczyna komentarz, dlatego każde hasło zawierające ten znak należy ująć w cudzysłów.
Konfiguracja poczty e-mail jest etapem, na którym zatrzymuje się większość instalacji
Od sierpnia 2026 roku kreator pozwala pominąć konfigurację SMTP i użyć logowania przez Discourse ID, a app.yml zawiera odpowiadający mu przełącznik DISCOURSE_SKIP_EMAIL_SETUP, opisany jako pominięcie walidacji konfiguracji poczty. Pominięcie tego kroku jest uzasadnione przy pierwszym zapoznaniu się z oprogramowaniem. Jest to jednak złe rozwiązanie dla społeczności, ponieważ bez wychodzącej poczty nikt nie aktywuje konta ani nie zresetuje hasła.
Praktycznym problemem jest fakt, że większość dostawców VPS blokuje wychodzący port 25, więc zwykły serwer pocztowy na maszynie nie będzie dostarczał wiadomości. Należy użyć uwierzytelnionego przekaźnika (relay) na porcie 587 lub na porcie 465 z użyciem implicit TLS (transport layer security). Dla portu 465 należy ustawić DISCOURSE_SMTP_FORCE_TLS: true, co jest zalecane w przykładowej konfiguracji dla tego portu. Przed przebudową (rebuild) należy przetestować dostępność z poziomu hosta.
nc -vz smtp.example.com 587Prawidłowy wynik to pojedyncza linia kończąca się ciągiem succeeded!. Polecenie, które zawiesza się, a następnie kończy przekroczeniem czasu oczekiwania, oznacza, że port jest blokowany na drodze wychodzącej z VPS i żadne ustawienie w Discourse tego nie naprawi. Należy zmienić port na taki, który jest dozwolony przez dostawcę, lub poprosić dostawcę o jego odblokowanie.
Gdy witryna będzie działać, należy wysłać wiadomość testową z poziomu strony Email w panelu Admin, a następnie sprawdzić zakładki Skipped oraz Bounced na tej samej stronie. W zakładkach tych Discourse rejestruje pocztę, której odmówił wysłania, oraz pocztę odrzuconą przez przekaźnik, wraz z podaniem przyczyny, co jest szybsze niż analiza logów.
TLS: pozwól kontenerowi na uzyskanie własnego certyfikatu
Jeśli Discourse obsługuje porty 80 oraz 443, należy skorzystać z wbudowanego mechanizmu wydawania certyfikatów. Odkomentuj dwie linie szablonu SSL pokazane powyżej, a następnie przebuduj aplikację. Szablon steruje acme.sh, przechowuje certyfikaty we współdzielonym wolumenie w lokalizacji /shared/ssl, odnawia je zgodnie z harmonogramem wewnątrz kontenera oraz konfiguruje Discourse tak, aby wymuszał HTTPS.
Aby to zadziałało, port 80 musi pozostać dostępny z Internetu, ponieważ to na nim następuje weryfikacja wyzwania HTTP (HTTP challenge). Firewall zezwalający wyłącznie na ruch na porcie 443 spowoduje, że proces budowy zakończy się sukcesem, ale certyfikat nigdy nie zostanie wydany. Sprawdź wynik operacji za pomocą ./launcher logs app bezpośrednio po przebudowie.
Czy należy umieścić Nginx lub Caddy przed aplikacją?
Jeśli Discourse jest jedyną usługą WWW na serwerze VPS, nie należy tego robić. Kontener zawiera już zoptymalizowany Nginx, a dodatkowe proxy wprowadza kolejny przeskok, konieczność odnawiania certyfikatu oraz nowe źródło błędów w nagłówkach.
Zastosuj proxy, gdy ten sam serwer VPS obsługuje inne witryny. Dodaj templates/web.socketed.template.yml do listy szablonów, zakomentuj obie linie expose i pozostaw oba szablony SSL zakomentowane. Kontener będzie wówczas nasłuchiwał na gnieździe unixowym pod adresem /var/discourse/shared/standalone/nginx.http.sock i nie zajmie żadnych portów, co zwolni porty 80 oraz 443 dla własnego proxy.
server {
listen 443 ssl;
server_name forum.example.com;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}Końcowy dwukropek po .sock jest częścią składni gniazd unixowych w Nginx, a sudo nginx -t odrzuci konfigurację bez niego. X-Forwarded-Proto również nie jest opcjonalne. Discourse generuje linki bezwzględne, więc bez tego nagłówka tworzy linki http:// na stronie HTTPS, co powoduje blokowanie ich przez przeglądarki jako treści mieszanych (mixed content). Gdy kontener korzysta z gniazda, obsługa TLS staje się zadaniem administratora, dlatego należy wydać certyfikat na hoście zgodnie z instrukcją Certbot w systemie Ubuntu 24.04 i Nginx. Jeśli wybór proxy nie został jeszcze dokonany, porównanie Nginx, Caddy i Traefik przedstawia kompromisy związane z każdą z tych opcji.
Przebudowy, aktualizacje i polecenia, które będą faktycznie używane
cd /var/discourse
./launcher rebuild apprebuild niszczy uruchomiony kontener, inicjuje nowy z app.yml i uruchamia go. Witryna jest niedostępna przez cały czas trwania procesu budowania, dlatego każdą zmianę konfiguracji należy traktować jako zaplanowaną przerwę techniczną trwającą kilka minut.
Zmiana wartości wyłącznie w sekcji env: nie wymaga tego procesu. ./launcher destroy app && ./launcher start app odtwarza kontener z już zbudowanego obrazu, co zajmuje kilka sekund. Każda zmiana w templates: lub hooks: modyfikuje sam obraz, co wymusza pełną przebudowę.
Aktualizacje są dostarczane na dwa sposoby. Wydania punktowe (point releases) są stosowane z poziomu interfejsu WWW pod adresem /admin/upgrade, co zapewnia wtyczka docker_manager, którą app.yml klonuje podczas budowania. Zmiany w obrazie bazowym lub szablonach pochodzą z git.
cd /var/discourse
git pull
./launcher rebuild appPrzebudowy to moment, w którym małe serwery ulegają awarii, ponieważ kompilacja zasobów stanowi szczytowe obciążenie pamięci dla całego systemu. Budowanie, które zatrzymuje się w trakcie, a dmesg wyświetla linię taką jak Out of memory: Killed process wskazującą na proces ruby, oznacza brak pamięci podczas budowania, nawet jeśli sama witryna działała wcześniej poprawnie. Należy dodać swap i ponownie uruchomić przebudowę.
./launcher logs app
./launcher enter app
./launcher cleanuplogs wyświetla wyjście kontenera, enter otwiera powłokę wewnątrz niego, a cleanup usuwa kontenery, które były zatrzymane przez ponad 24 godziny. Polecenie cleanup należy uruchamiać od czasu do czasu, ponieważ każda przebudowa pozostawia stary kontener, co prowadzi do cichego wyczerpania miejsca na dysku na małych serwerach VPS.
Kopie zapasowe oraz plik, którego kopia nie zawiera
Wykonaj kopie zapasowe z poziomu strony Backups w panelu Admin. Archiwum trafia na hosta do lokalizacji /var/discourse/shared/standalone/backups/default/. To samo zadanie można uruchomić z poziomu powłoki.
cd /var/discourse
./launcher enter app
discourse backupPolecenie discourse restore <filename> cofa ten proces, a przywracanie danych jest blokowane do momentu uruchomienia discourse enable_restore. To zabezpieczenie istnieje, aby przypadkowe polecenie nie nadpisało działającego forum.
Istnieją dwie luki, które należy zabezpieczyć samodzielnie. Archiwum zawiera bazę danych oraz przesłane pliki tylko wtedy, gdy włączone jest ustawienie kopii zapasowej uwzględniające pliki (uploads), dlatego sprawdź to ustawienie przed zaufaniem kopii. Archiwum nigdy nie zawiera pliku app.yml, więc przywrócenie danych na świeży serwer VPS nadal wymaga ręcznego skonfigurowania nazwy hosta oraz parametrów SMTP, co oznacza konieczność skopiowania tego pliku poza serwer.
Archiwum znajduje się również na tym samym dysku, co chroniona witryna, co nie stanowi pełnoprawnej kopii zapasowej. Należy regularnie pobierać je w inne miejsce zgodnie z harmonogramem.
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/Koszt aktywnego forum w pamięci RAM
Proces bootstrap ustawia UNICORN_WORKERS oraz db_shared_buffers na podstawie wykrytej pamięci i procesora, a przykładowa konfiguracja ogranicza shared buffers do jednej czwartej całkowitej pamięci. Każdy proces roboczy unicorn jest pełnym procesem Ruby, a Sidekiq wykonuje zadania w tle obok nich, więc zużycie pamięci zależy od liczby jednoczesnych żądań, a nie od liczby zarejestrowanych użytkowników. Ciche forum z kilkuset członkami nie stanowi dużego obciążenia.
Nie należy dobierać rozmiaru serwera na podstawie liczb z artykułów, w tym również tego. Należy dokonać własnych pomiarów.
free -m
docker stats --no-streamStałe użycie partycji swap w połączeniu z wolnym ładowaniem stron oznacza niedobór pamięci RAM. Stabilne zużycie pamięci przy wolnych stronach zazwyczaj oznacza inny problem, dlatego przed zakupem droższego planu należy przeczytać ./launcher logs app. Warto również dodać monitorowanie z zewnątrz, ponieważ forum, któremu zabraknie pamięci o godzinie 3 nad ranem, zawiesza się bez powiadomienia: samodzielnie hostowany monitor statusu Uptime Kuma na oddzielnym hoście poinformuje o awarii, zanim zrobią to użytkownicy.
Kiedy Discourse nie jest właściwym wyborem
Discourse to rozbudowana aplikacja o wymagającym procesie instalacji oraz konieczności przebudowy (rebuild) przy każdej zmianie ustawień zapisanych w app.yml. Koszt ten zapewnia zaawansowane narzędzia moderacji oraz wyszukiwarkę, która pozostaje wydajna przy dużych archiwach. Dla grupy trzydziestu osób potrzebujących miejsca do dyskusji, jest to rozwiązanie zbyt zasobożerne. W pierwszej kolejności należy zapoznać się z porównaniem oprogramowania forów z własnym hostingiem. Wybór Discourse powinien wynikać z potrzeby korzystania z jego funkcji, a nie z faktu, że jest to znana nazwa.
FAQ
Czy mogę zainstalować Discourse na VPS bez nazwy domenowej?
Nie. Dostarczona konfiguracja zakłada, że Discourse nie będzie działać z samym adresem IP, a DISCOURSE_HOSTNAME jest wymagane. Discourse tworzy bezwzględne linki na podstawie tej nazwy hosta, więc użycie adresu IP powoduje uszkodzenie odnośników i uniemożliwia wystawienie certyfikatu. Przed rozpoczęciem utwórz rekord A i potwierdź za pomocą dig +short forum.example.com, że wskazuje on na adres Twojego serwera.
Czy muszę skonfigurować SMTP, aby zakończyć instalację?
Od sierpnia 2026 roku można to pominąć. Kreator instalacji oferuje logowanie przez Discourse ID, a app.yml zawiera przełącznik pomijający walidację konfiguracji poczty. W przypadku użycia wykraczającego poza wstępne testy, należy ją skonfigurować, ponieważ aktywacja konta oraz resetowanie haseł odbywają się drogą mailową. Użyj uwierzytelnionego przekaźnika na porcie 587 lub 465, ponieważ większość dostawców VPS blokuje wychodzący port 25.
Dlaczego proces rebuild w Discourse kończy się niepowodzeniem w trakcie?
Najczęstszą przyczyną jest brak pamięci. Kompilacja zasobów podczas budowania wymaga więcej pamięci niż działająca witryna, więc serwer, który poprawnie obsługuje forum, może nie poradzić sobie z jego przebudową. Jeśli dmesg wskazuje Out of memory: Killed process w odniesieniu do procesu ruby, dodaj swap (domyślny plik wymiany kreatora ma 2 GB) i uruchom ./launcher rebuild app ponownie. Budowanie, które zatrzymuje się z powodu błędu YAML, wskazuje na błąd wcięć w app.yml.
Czy Discourse powinien działać za własnym Nginx lub Caddy?
Tylko jeśli VPS obsługuje również inne witryny. Jeśli serwer jest dedykowany, pozwól kontenerowi zająć porty 80 i 443 oraz samodzielnie wystawić certyfikat; ogranicza to liczbę ruchomych elementów. Aby współdzielić maszynę, dodaj templates/web.socketed.template.yml, zakomentuj linie expose i przekieruj ruch do gniazda unix pod adresem /var/discourse/shared/standalone/nginx.http.sock. Przekaż X-Forwarded-Proto, w przeciwnym razie Discourse wygeneruje linki http:// na stronie HTTPS.
Jak wykonać kopię zapasową samodzielnie hostowanego Discourse?
Użyj strony Backups w panelu administratora lub uruchom discourse backup po ./launcher enter app. Archiwa trafiają na hosta do /var/discourse/shared/standalone/backups/default/. Potwierdź, że ustawienie uwzględniające przesyłane pliki jest aktywne, skopiuj /var/discourse/containers/app.yml wraz z archiwum i przenieś oba elementy na inną maszynę, ponieważ kopia zapasowa na tym samym dysku co witryna nie przetrwa awarii, przed którą ma chronić.