SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-25

Discourse auf einem VPS mit Docker installieren

Installieren Sie Discourse mit dem offiziellen Docker-Launcher: Prüfen Sie RAM und Swap, richten Sie Domain und SMTP ein, bearbeiten Sie app.yml und aktivieren Sie TLS.

Discourse auf einem VPS installieren: ein Container, eine Konfigurationsdatei

Für die Installation von Discourse auf einem VPS führen Sie das vom Projekt bereitgestellte Installationsprogramm aus, beantworten einen kurzen Assistenten und warten auf den Build. Discourse wird als einzelner Docker-Container ausgeliefert, der die Rails-Anwendung, PostgreSQL, Redis und nginx enthält. Alle späteren Änderungen nehmen Sie in einer Datei vor, /var/discourse/containers/app.yml. Jede Änderung wird durch einen erneuten Build auf die Website angewendet.

Die offizielle Installation besteht aus discourse_docker: einem launcher-Shellskript und einer Reihe von YAML-Vorlagen. Discourse unterstützt keine Compose-Datei, die Sie selbst schreiben. Der Container ist außerdem nicht dafür vorgesehen, manuell in einzelne Bestandteile aufgeteilt zu werden. Wenn Sie daran gewöhnt sind, Dienste auf einem VPS mit Docker Compose zu betreiben, erwartet Sie hier eine andere Struktur. Es gibt hier kein docker compose up -d. ./launcher rebuild app ist der Deployment-Vorgang.

Was Discourse vor dem Start benötigt

Vier Voraussetzungen werden häufig übersehen. Jede davon führt zu Problemen, bevor Sie die Anmeldeseite erreichen.

  • Arbeitsspeicher. Ein Container führt PostgreSQL, Redis, Sidekiq und einen Ruby-Webserver aus. Beim Build-Schritt werden Assets kompiliert. Dafür wird mehr Arbeitsspeicher benötigt als für den laufenden Betrieb der Website.
  • Ein echter Domainname. Die mitgelieferte Beispielkonfiguration sagt es eindeutig: „Discourse funktioniert nicht mit einer reinen IP-Adresse.“
  • Ein ausgehender E-Mail-Versand. Kontenaktivierungen, Passwortzurücksetzungen, Einladungen durch Administratoren und Digest-E-Mails werden über SMTP (Simple Mail Transfer Protocol) versendet.
  • Die Ports 80 und 443 müssen auf dem Host frei sein, sofern Sie Discourse nicht bewusst hinter einem bereits betriebenen Proxy ausführen.
ChartDiscourse published hardware requirements (official install docs, August 2026)
The data behind this chart
[
  {
    "label": "Documented minimum",
    "ram_gb": 1,
    "storage_gb": 10
  },
  {
    "label": "Documented recommended",
    "ram_gb": 2,
    "storage_gb": 20
  }
]

Die offizielle Installationsdokumentation nennt 1 GB RAM mit Swap und 10 GB Speicherplatz als Mindestanforderung. Sie empfiehlt 2 GB RAM und 20 GB Speicherplatz. Lesen Sie die erste Zeile als den Wert, mit dem die Installation abgeschlossen werden kann, nicht als den Wert, mit dem Sie eine Community betreiben möchten. Der Unterschied ist relevant, weil der Speicherbedarf beim Build und nicht durch den Netzwerkverkehr seinen Höchststand erreicht.

Zeigen Sie die Domain auf den Server, bevor Sie die Installation starten

Erstellen Sie einen A-Record für den verwendeten Hostnamen. Prüfen Sie ihn anschließend direkt vom Server aus.

dig +short forum.example.com
curl -4 -s https://ifconfig.co

Beide Befehle müssen dieselbe Adresse ausgeben. Die Ergebnisse müssen übereinstimmen, weil der Einrichtungsassistent eine Verbindung zu Ihrem Hostnamen prüft. Ein Record, der noch auf eine andere Adresse zeigt, besteht diese Prüfung nicht. Ein vor zwei Minuten erstellter Record kann außerdem noch im Cache liegen. Warten Sie daher, bis die alte TTL (Time to Live) abgelaufen ist, statt den Assistenten vergeblich erneut auszuführen.

Entscheiden Sie jetzt, ob ein CDN den Record proxien soll. Ein proxierter Record verbirgt die Adresse Ihres Servers. Die Zertifikatanforderung des Containers schlägt dann fehl, weil der Proxy die ACME-(Automatic Certificate Management Environment-)Challenge beantwortet und nicht Discourse. Lassen Sie den Record für die erste Installation nicht proxien.

Offizielles Installationsskript ausführen

Ein Befehl installiert git und Docker mit dem Installationsskript von Docker, klont discourse_docker nach /var/discourse und startet den Einrichtungsassistenten.

wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash

Wenn Docker bereits auf dem Server installiert ist und Sie jeden Schritt einzeln ausführen möchten, erledigen Sie diese Arbeiten manuell.

sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setup

Führen Sie den Befehl als root aus. Wenn discourse-setup als normaler Benutzer gestartet wird, beendet es sich sofort mit This script must be run as root. Please sudo or log in as root first.. Wenn Docker nicht auf dem Server installiert ist, wird der Vorgang mit Docker is not installed. Please install Docker first. beendet, da der manuelle Clone keine Software für Sie installiert.

Was der Einrichtungsassistent abfragt und welche Dateien er schreibt

Stand August 2026 ist discourse-setup nur ein schlanker Wrapper. Er führt discourse/setup-wizard:release als Container mit dem Host-Netzwerk und einem eingebundenen Docker-Socket aus. Dadurch kann der Assistent den Rechner prüfen, den er konfiguriert. Er fragt nach dem Hostnamen und den E-Mail-Adressen der Administratoren. Danach fragt er nach Ihrem SMTP-Block. Er schreibt containers/app.yml und erstellt den Build anschließend neu.

Vor dem Start sollten Sie zwei Verhaltensweisen kennen. Wenn auf dem Rechner nicht genügend Arbeitsspeicher vorhanden ist und kein Swap existiert, wird der Assistent beendet und bietet an, Swap anzulegen. Der Wrapper erstellt dann eine 2-GB-/swapfile-Datei, fügt sie zu /etc/fstab hinzu, setzt vm.swappiness = 10 in /etc/sysctl.d/30-discourse-swap.conf und startet den Assistenten erneut. Nach Abschluss gibt der Assistent Rebuilding app in 5 seconds (Ctrl+C to cancel)... aus und führt ./launcher rebuild app auf dem Host aus. Dieser Build benötigt auf einem kleinen VPS mehrere Minuten. Der erste Build dauert am längsten, weil jedes Asset vollständig neu kompiliert wird.

./discourse-setup --help listet die relevanten Flags für den Fehlerfall auf. --skip-rebuild schreibt die Konfiguration, ohne den Build auszuführen. --skip-connection-test überspringt die DNS- und Portprüfungen. Verwenden Sie --skip-connection-test nur, wenn Sie bereits wissen, warum der Test fehlschlägt, beispielsweise wenn sich der Host hinter einer von Ihnen kontrollierten Netzwerk-Firewall befindet.

Vor dem ersten Rebuild app.yml lesen

Der Wizard schreibt eine Datei, die Sie nun selbst pflegen müssen. Öffnen Sie sie mit sudo nano /var/discourse/containers/app.yml. Diese Einstellungen bestimmen fast alles.

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 ist die Adresse, unter der die Site erreichbar ist. Discourse erstellt daraus seine Links. Ein falscher Wert führt daher dazu, dass die Site zunächst geladen wird und Sie anschließend an eine andere Stelle weiterleitet. DISCOURSE_DEVELOPER_EMAILS ist eine durch Kommas getrennte Liste. Die dort eingetragenen Adressen erhalten bei der ersten Registrierung automatisch Administratorrechte. Tragen Sie dort Ihre eigene Adresse ein und registrieren Sie sich damit. Auf diese Weise wird das erste Administratorkonto erstellt.

Die Datei enthält Ihr SMTP-Passwort im Klartext. Beschränken Sie daher den Zugriff auf das Verzeichnis mit sudo chmod 700 /var/discourse/containers. Die Datei verwendet außerdem YAML. Dort ist Leerraum Bestandteil der Konfiguration. Ein falsch eingerückter Schlüssel führt beim Build zu einem Analysefehler. Die Site wird dann nicht erstellt. Eine Besonderheit ist in der Beispieldatei selbst dokumentiert. Ein # in einem nicht quotierten Passwort leitet einen Kommentar ein. Setzen Sie daher jedes Passwort, das dieses Zeichen enthält, in Anführungszeichen.

E-Mail ist der Schritt, an dem die meisten Installationen scheitern

Seit August 2026 können Sie im Assistenten SMTP überspringen und stattdessen Discourse-ID-Anmeldungen verwenden. Außerdem enthält app.yml einen passenden DISCOURSE_SKIP_EMAIL_SETUP-Schalter, der dort als Möglichkeit zum Überspringen der Validierung der E-Mail-Einrichtung beschrieben wird. Für einen ersten Blick auf die Software ist das Überspringen sinnvoll. Für eine Community ist es jedoch eine schlechte Wahl, weil ohne ausgehende E-Mails niemand ein Konto aktivieren oder ein Passwort zurücksetzen kann.

Das praktische Problem besteht darin, dass die meisten VPS-Anbieter den ausgehenden Port 25 blockieren. Ein einfacher Mailserver auf dem System kann dann keine Nachrichten zustellen. Verwenden Sie ein authentifiziertes Relay über Port 587 oder über Port 465 mit implizitem TLS (Transport Layer Security). Setzen Sie für Port 465 DISCOURSE_SMTP_FORCE_TLS: true. Die Beispielkonfiguration empfiehlt diese Einstellung für diesen Port. Testen Sie die Erreichbarkeit vom Host aus, bevor Sie die Installation neu erstellen.

nc -vz smtp.example.com 587

Ein korrektes Ergebnis besteht aus einer einzelnen Zeile, die mit succeeded! endet. Wenn ein Befehl hängt und anschließend wegen eines Timeouts abbricht, ist der Port auf dem ausgehenden Pfad Ihres VPS blockiert. Keine Discourse-Einstellung kann das beheben. Wechseln Sie zu einem Port, den Ihr Anbieter zulässt, oder bitten Sie den Anbieter, den Port freizuschalten.

Sobald die Website verfügbar ist, senden Sie auf der Seite Email im Bereich Admin eine Testnachricht. Prüfen Sie anschließend auf derselben Seite die Tabs Skipped und Bounced. Dort erfasst Discourse E-Mails, deren Versand es abgelehnt hat, sowie E-Mails, die das Relay abgewiesen hat. Außerdem wird dort der Grund angegeben. Das ist schneller, als die Logs zu lesen.

TLS: Der Container erhält sein eigenes Zertifikat

Wenn Discourse die Ports 80 und 443 verwendet, nutzen Sie die integrierte Zertifikatsausstellung. Entfernen Sie die Kommentarzeichen vor den beiden oben gezeigten SSL-Template-Zeilen und erstellen Sie den Container anschließend neu. Das Template steuert acme.sh, speichert Zertifikate im gemeinsamen Volume unter /shared/ssl, erneuert sie nach einem Zeitplan im Container und konfiguriert Discourse so, dass HTTPS erzwungen wird.

Port 80 muss aus dem Internet erreichbar bleiben, damit dies funktioniert, weil die HTTP-Challenge dort beantwortet wird. Eine Firewall, die nur 443 zulässt, führt zu einem Build, der abgeschlossen wird, und zu einem Zertifikat, das nie ausgestellt wird. Prüfen Sie das Ergebnis direkt nach dem erneuten Build mit ./launcher logs app.

Sollten Sie nginx oder Caddy vorschalten?

Wenn Discourse der einzige Webdienst auf dem VPS ist, sollten Sie das nicht tun. Der Container verwendet bereits einen optimierten nginx. Ein zweiter Proxy fügt einen weiteren Hop, ein zusätzliches zu erneuerndes Zertifikat und eine neue Fehlerquelle für Header hinzu.

Schalten Sie einen Proxy vor, wenn derselbe VPS weitere Websites bereitstellt. Fügen Sie templates/web.socketed.template.yml zur Liste der Templates hinzu, kommentieren Sie beide expose-Zeilen aus und lassen Sie die beiden SSL-Templates auskommentiert. Der Container lauscht dann an einem Unix-Socket unter /var/discourse/shared/standalone/nginx.http.sock und verwendet überhaupt keine Ports. Dadurch stehen Port 80 und 443 für Ihren eigenen Proxy zur Verfügung.

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;
  }
}

Der abschließende Doppelpunkt hinter .sock gehört zur Unix-Socket-Syntax von nginx. sudo nginx -t weist die Konfiguration ohne ihn zurück. Auch X-Forwarded-Proto ist erforderlich. Discourse schreibt absolute Links. Ohne diesen Header erzeugt es http://-Links auf einer HTTPS-Seite. Browser blockieren diese als Mixed Content. Wenn der Container über einen Socket angebunden ist, sind Sie für TLS zuständig. Stellen Sie das Zertifikat auf dem Host mit Certbot unter Ubuntu 24.04 und nginx aus. Wenn Sie sich noch nicht für einen Proxy entschieden haben, erläutert der Vergleich von nginx, Caddy und Traefik die damit verbundenen Abwägungen.

Neuaufbau, Upgrades und die Befehle, die Sie tatsächlich verwenden

cd /var/discourse
./launcher rebuild app

rebuild entfernt den laufenden Container, erstellt anhand von app.yml einen neuen und startet ihn. Die Website ist während des gesamten Builds nicht erreichbar. Behandeln Sie daher jede Konfigurationsänderung als geplante Ausfallzeit von einigen Minuten.

Änderungen ausschließlich an Werten unter env: erfordern keinen vollständigen Neuaufbau. ./launcher destroy app && ./launcher start app erstellt den Container aus dem bereits erstellten Image neu. Das dauert nur wenige Sekunden. Alles unter templates: oder hooks: ändert das Image selbst und erfordert daher den vollständigen Neuaufbau.

Upgrades kommen auf zwei Wegen. Point Releases werden über die Weboberfläche unter /admin/upgrade eingespielt. Diese Funktion wird vom Plugin docker_manager bereitgestellt, das app.yml während des Builds klont. Änderungen am Basis-Image oder an den Templates kommen aus git.

cd /var/discourse
git pull
./launcher rebuild app

Bei Neuaufbauten versagen kleine Server häufig, weil die Asset-Kompilierung den höchsten Speicherbedarf des gesamten Systems verursacht. Wenn ein Build vorzeitig abbricht und dmesg eine Zeile wie Out of memory: Killed process anzeigt, in der ein ruby-Prozess genannt wird, ist während des Builds der Speicher ausgegangen, obwohl die Website zuvor ordnungsgemäß lief. Fügen Sie Swap hinzu und führen Sie den Neuaufbau erneut aus.

./launcher logs app
./launcher enter app
./launcher cleanup

logs gibt die Ausgabe des Containers aus. enter öffnet eine Shell im Container. cleanup entfernt Container, die länger als 24 Stunden gestoppt waren. Führen Sie cleanup gelegentlich aus, weil jeder Neuaufbau einen alten Container zurücklässt und der Speicherplatz auf einem kleinen VPS unbemerkt knapp wird.

Backups und die Datei, die das Backup nicht enthält

Erstellen Sie Backups über die Seite „Backups“ im Admin-Bereich. Das Archiv wird auf dem Host unter /var/discourse/shared/standalone/backups/default/ abgelegt. Derselbe Vorgang lässt sich auch über eine Shell ausführen.

cd /var/discourse
./launcher enter app
discourse backup

discourse restore <filename> macht die Änderung rückgängig. Wiederherstellungen werden verweigert, bis Sie discourse enable_restore ausführen. Diese Schutzmaßnahme verhindert, dass ein versehentlicher Befehl ein aktives Forum überschreibt.

Zwei Lücken müssen Sie selbst schließen. Das Archiv enthält die Datenbank. Hochgeladene Dateien sind nur enthalten, wenn die Backup-Einstellung zum Einschließen von Uploads aktiviert ist. Prüfen Sie diese Einstellung, bevor Sie dem Backup vertrauen. app.yml ist nie enthalten. Bei einer Wiederherstellung auf einem neuen VPS benötigen Sie daher weiterhin Ihren Hostnamen und den SMTP-Block. Kopieren Sie diese Datei ebenfalls vom Server.

Das Archiv liegt außerdem auf demselben Datenträger wie die geschützte Website. Das ist kein Backup. Übertragen Sie es regelmäßig an einen anderen Speicherort.

rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/

Was ein stark frequentiertes Forum an RAM benötigt

Das Bootstrap-Skript setzt UNICORN_WORKERS und db_shared_buffers anhand der erkannten Speicher- und CPU-Ressourcen. Die Beispielkonfiguration begrenzt die gemeinsam verwendeten Puffer auf ein Viertel des gesamten Arbeitsspeichers. Jeder Unicorn-Worker ist ein vollständiger Ruby-Prozess. Sidekiq führt zusätzlich Hintergrundaufgaben aus. Der Speicherbedarf hängt daher von der Anzahl gleichzeitiger Anfragen ab, nicht von der Zahl registrierter Mitglieder. Ein ruhiges Forum mit einigen hundert Mitgliedern ist keine hohe Belastung. Meist ist entscheidender, welche anderen Dienste sich den Server teilen. Wenn das eine Fotobibliothek ist, zeigen die gemessenen RAM-Untergrenzen im Vergleich von PhotoPrism und Immich, ob für einen Discourse-Neuaufbau noch genügend Speicher verfügbar ist.

Dimensionieren Sie den Server nicht anhand einer Zahl aus einem Artikel, auch nicht aus diesem. Messen Sie Ihre eigene Umgebung.

free -m
docker stats --no-stream

Durchgehend verwendeter Swap zusammen mit langsamen Seiten bedeutet, dass zu wenig RAM vorhanden ist. Bleibt der Speicherverbrauch stabil und sind die Seiten trotzdem langsam, liegt die Ursache meist an anderer Stelle. Lesen Sie daher ./launcher logs app, bevor Sie einen größeren Tarif buchen. Richten Sie zusätzlich eine Prüfung von außerhalb des Servers ein. Ein Forum, dem um 3 Uhr morgens der Speicher ausgeht, fällt sonst möglicherweise unbemerkt aus: ein selbst gehosteter Uptime-Kuma-Statusmonitor auf einem separaten Host informiert Sie, bevor Ihre Mitglieder den Ausfall bemerken.

Wenn Discourse die falsche Wahl ist

Discourse ist eine große Anwendung mit einer umfangreichen Installation. Für jede Einstellung in app.yml ist ein Rebuild erforderlich. Dieser Aufwand bietet leistungsfähige Moderationsfunktionen und eine Suche, die auch bei großen Archiven funktioniert. Für dreißig Personen, die einen Ort zum Austauschen suchen, ist Discourse jedoch umfangreicher, als die Unterhaltung es erfordert. Lesen Sie zuerst den Vergleich selbst gehosteter Forensoftware und wählen Sie Discourse, weil Sie seine Funktionen benötigen, nicht weil Sie den Namen bereits kannten.

FAQ

Kann ich Discourse auf einem VPS ohne Domainnamen installieren?

Nein. Die mitgelieferte Konfiguration legt fest, dass Discourse mit einer reinen IP-Adresse nicht funktioniert. DISCOURSE_HOSTNAME ist erforderlich. Discourse erstellt aus diesem Hostnamen absolute Links. Eine IP-Adresse führt dort zu fehlerhaften Links und verhindert die Ausstellung von Zertifikaten. Erstellen Sie vor dem Start einen A-Record. Prüfen Sie mit dig +short forum.example.com, ob er auf die Adresse Ihres Servers aufgelöst wird.

Muss ich SMTP konfigurieren, um die Installation abzuschließen?

Seit August 2026 können Sie diesen Schritt überspringen. Der Setup-Assistent bietet stattdessen Anmeldungen über Discourse ID an. app.yml enthält eine Option, mit der sich die Validierung der E-Mail-Konfiguration überspringen lässt. Für alles, was über einen ersten Test hinausgeht, sollten Sie SMTP konfigurieren. Die Aktivierung von Konten und das Zurücksetzen von Passwörtern erfolgen per E-Mail. Verwenden Sie ein authentifiziertes Relay auf Port 587 oder 465, da die meisten VPS-Anbieter ausgehenden Datenverkehr über Port 25 blockieren.

Warum ist der Discourse-Rebuild auf halbem Weg fehlgeschlagen?

Die häufigste Ursache ist zu wenig Arbeitsspeicher. Die Kompilierung der Assets während des Builds benötigt mehr Speicher als der laufende Betrieb. Deshalb kann ein Server das Forum problemlos bereitstellen und trotzdem beim Rebuild fehlschlagen. Wenn dmesg Out of memory: Killed process anzeigt und dabei einen Ruby-Prozess nennt, fügen Sie Swap hinzu. Die Swap-Datei des Assistenten ist 2 GB groß. Führen Sie anschließend ./launcher rebuild app erneut aus. Wenn der Build wegen eines YAML-Fehlers stoppt, deutet das stattdessen auf einen Einrückungsfehler in app.yml hin.

Sollte Discourse hinter meinem eigenen nginx oder Caddy laufen?

Nur wenn auf dem VPS auch andere Websites bereitgestellt werden. Wenn Discourse allein auf dem Server läuft, sollten Sie den Container die Ports 80 und 443 verwalten und sein eigenes Zertifikat ausstellen lassen. Dadurch gibt es weniger Komponenten. Um den Server gemeinsam zu nutzen, fügen Sie templates/web.socketed.template.yml hinzu, kommentieren die expose-Zeilen aus und leiten Anfragen an den Unix-Socket unter /var/discourse/shared/standalone/nginx.http.sock weiter. Leiten Sie X-Forwarded-Proto weiter. Andernfalls erzeugt Discourse http://-Links auf einer HTTPS-Seite.

Wie erstelle ich ein Backup eines selbst gehosteten Discourse?

Verwenden Sie die Seite „Backups“ im Admin-Bereich oder führen Sie nach ./launcher enter app den Befehl discourse backup aus. Die Archive werden auf dem Host unter /var/discourse/shared/standalone/backups/default/ abgelegt. Prüfen Sie, ob die Einstellung zum Einschließen von Uploads aktiviert ist. Kopieren Sie /var/discourse/containers/app.yml zusammen mit dem Archiv und übertragen Sie beides auf einen anderen Rechner. Ein Backup auf derselben Festplatte wie die Website übersteht den Ausfall nicht, vor dem es schützen soll.