SSD Nodes Learn 🎉 VPS ab $5.50/Monat
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-13

Discourse auf einem VPS mit Docker installieren

Erfahren Sie, wie Sie Discourse mittels offiziellem Docker-Launcher auf Ihrem VPS einrichten. Wir behandeln RAM-Anforderungen, SMTP-Konfiguration, app.yml und TLS-Setups.

Discourse auf einem VPS installieren: ein Container, eine Konfigurationsdatei

Um Discourse auf einem VPS zu installieren, führen Sie das projekteigene Installationsprogramm aus, beantworten einen kurzen Einrichtungsassistenten und warten auf den Build-Vorgang. Discourse wird als einzelner Docker-Container ausgeliefert, der die Rails-Anwendung, PostgreSQL, Redis und nginx enthält. Alles, was Sie später ändern, befindet sich in einer einzigen Datei, /var/discourse/containers/app.yml, und jede Änderung wird durch einen erneuten Build auf die Website angewendet.

Die offizielle Installation ist discourse_docker: ein launcher-Shell-Skript sowie eine Reihe von YAML-Vorlagen. Discourse unterstützt keine selbst erstellte Compose-Datei, und der Container ist nicht dafür vorgesehen, manuell aufgeteilt zu werden. Wenn Sie es gewohnt sind, Dienste auf einem VPS mit Docker Compose auszuführen, stellen Sie sich auf eine andere Struktur ein. Es gibt hier kein docker compose up -d, und ./launcher rebuild app ist der Bereitstellungsprozess.

Voraussetzungen für Discourse

Vier Anforderungen führen häufig zu Problemen, noch bevor die Anmeldeseite erreicht wird.

  • Arbeitsspeicher. Ein Container betreibt PostgreSQL, Redis, Sidekiq und einen Ruby-Webserver. Der Build-Prozess kompiliert Assets und benötigt mehr Arbeitsspeicher als der laufende Dienst.
  • Ein echter Domainname. Die mitgelieferte Beispielkonfiguration stellt klar: "Discourse funktioniert nicht mit einer reinen IP-Adresse."
  • Ein ausgehender E-Mail-Weg. Kontoaktivierungen, Passwort-Resets, Admin-Einladungen und Digest-Mails werden über SMTP (Simple Mail Transfer Protocol) versendet.
  • Freie Ports 80 und 443 auf dem Host, sofern Discourse nicht bewusst hinter einem bereits vorhandenen Proxy betrieben wird.
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 Installationsanleitung setzt das Minimum bei 1 GB RAM inklusive Swap und 10 GB Festplattenspeicher an und empfiehlt 2 GB RAM mit 20 GB Festplattenspeicher. Betrachten Sie den ersten Wert als die Untergrenze, damit der Installer erfolgreich durchläuft, nicht als die Kapazität für den Betrieb einer Community. Dieser Unterschied ist wichtig, da der Speicherbedarf beim Build-Vorgang seinen Höhepunkt erreicht, nicht durch den eigentlichen Datenverkehr.

Verweisen Sie die Domain vor der Installation auf den Server

Erstellen Sie einen A-Record für den Hostnamen, den Sie verwenden möchten, und bestätigen Sie diesen anschließend direkt vom Server aus.

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

Beide Befehle müssen dieselbe Adresse ausgeben. Sie müssen übereinstimmen, da der Einrichtungsassistent einen Verbindungstest mit Ihrem Hostnamen durchführt; ein Record, der noch auf ein anderes Ziel verweist, lässt diesen Test fehlschlagen. Ein vor zwei Minuten erstellter Record kann zudem noch im Cache liegen. Warten Sie daher den Ablauf der alten TTL (Time to Live) ab, anstatt den Assistenten zu forcieren.

Entscheiden Sie jetzt, ob der Record über ein CDN geproxied werden soll. Ein geproxied-Record verbirgt Ihre Serveradresse, wodurch die Zertifikatsanforderung des Containers fehlschlägt, da die ACME-Challenge (Automatic Certificate Management Environment) vom Proxy und nicht von Discourse beantwortet wird. Belassen Sie den Record für die erste Installation im ungeproxied-Zustand.

Ausführen des offiziellen Installers

Ein einziger Befehl installiert git, installiert Docker mittels des offiziellen Docker-Installationsskripts, klont discourse_docker nach /var/discourse und startet den Einrichtungsassistenten.

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

Falls Docker bereits auf dem System vorhanden ist und Sie die einzelnen Schritte bevorzugen, führen Sie die Arbeit manuell aus.

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. Wird er als normaler Benutzer gestartet, bricht discourse-setup sofort mit This script must be run as root. Please sudo or log in as root first. ab. Ohne installiertes Docker auf dem System bricht der Prozess mit Docker is not installed. Please install Docker first. ab, da das manuelle Klonen keine automatische Installation vornimmt.

Was der Einrichtungsassistent abfragt und was er schreibt

Seit August 2026 ist discourse-setup ein schlanker Wrapper. Er führt discourse/setup-wizard:release als Container aus, wobei das Host-Netzwerk und der Docker-Socket eingebunden sind, damit der Assistent die zu konfigurierende Maschine untersuchen kann. Er fragt nach dem Hostnamen und den E-Mail-Adressen für den Administrator, anschließend nach Ihrem SMTP-Block. Er schreibt containers/app.yml und führt danach einen Rebuild durch.

Zwei Verhaltensweisen sind vor dem Start wichtig. Wenn die Maschine über zu wenig Arbeitsspeicher verfügt und kein Swap vorhanden ist, hält der Assistent an und bietet dessen Erstellung an: Der Wrapper erstellt dann eine 2 GB große /swapfile, 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-Vorgang dauert auf einem kleinen VPS einige Minuten; der erste Durchlauf ist am langsamsten, da alle Assets von Grund auf neu kompiliert werden.

./discourse-setup --help listet die Flags auf, die bei Problemen relevant sind. --skip-rebuild schreibt die Konfiguration, ohne den Build-Vorgang zu starten, und --skip-connection-test überspringt die DNS- und Port-Prü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.

Lesen Sie app.yml vor dem ersten Rebuild

Der Assistent erstellt eine Datei, für deren Pflege Sie nun verantwortlich sind. Öffnen Sie diese mit sudo nano /var/discourse/containers/app.yml. Die darin enthaltenen Abschnitte bestimmen nahezu alle Funktionen.

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 Website erreichbar ist. Discourse generiert daraus seine Links; ein falscher Wert führt dazu, dass die Seite einmal lädt und Sie anschließend auf eine andere Adresse weiterleitet. DISCOURSE_DEVELOPER_EMAILS ist eine durch Kommas getrennte Liste. Die dort aufgeführten Adressen erhalten bei der ersten Registrierung automatisch Administratorrechte. Tragen Sie hier Ihre eigene Adresse ein und registrieren Sie sich damit, da dies der Weg ist, um das erste Administratorkonto zu erstellen.

Die Datei speichert Ihr SMTP-Passwort im Klartext. Schränken Sie daher den Zugriff auf das Verzeichnis mit sudo chmod 700 /var/discourse/containers ein. Da es sich um YAML handelt, ist die Einrückung Teil der Konfiguration: Ein falsch ausgerichteter Schlüssel führt zu einem Parse-Fehler beim Build-Vorgang und lässt die Website nicht starten. Eine Falle ist in der Beispieldatei selbst dokumentiert. Ein # innerhalb eines nicht in Anführungszeichen gesetzten Passworts leitet einen Kommentar ein. Setzen Sie daher jedes Passwort, das ein solches Zeichen enthält, in Anführungszeichen.

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

Seit August 2026 erlaubt der Einrichtungsassistent das Überspringen von SMTP, um stattdessen Discourse ID Logins zu verwenden. app.yml enthält einen entsprechenden DISCOURSE_SKIP_EMAIL_SETUP-Schalter, der dort als Option zum Überspringen der E-Mail-Validierung beschrieben wird. Für einen ersten Blick auf die Software ist das Überspringen vertretbar. Für eine Community ist es jedoch eine schlechte Wahl, da ohne ausgehenden E-Mail-Versand 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, weshalb ein einfacher Mailserver auf dem System keine Nachrichten zustellen kann. Verwenden Sie ein authentifiziertes Relay auf Port 587 oder auf 465 mit implizitem TLS (Transport Layer Security). Für 465 setzen Sie DISCOURSE_SMTP_FORCE_TLS: true, was die Beispielkonfiguration für diesen Port empfiehlt. Testen Sie die Erreichbarkeit vom Host aus, bevor Sie einen Rebuild durchführen.

nc -vz smtp.example.com 587

Ein erfolgreiches Ergebnis ist eine einzelne Zeile, die mit succeeded! endet. Ein Befehl, der hängen bleibt und dann in ein Timeout läuft, bedeutet, dass der Port auf dem ausgehenden Pfad Ihres VPS blockiert ist; dies lässt sich durch keine Discourse-Einstellung beheben. Wechseln Sie zu einem Port, den Ihr Anbieter erlaubt, oder bitten Sie den Anbieter, diesen freizuschalten.

Sobald die Seite läuft, senden Sie eine Testnachricht über die E-Mail-Seite im Admin-Bereich und prüfen Sie anschließend die Reiter „Skipped“ (Übersprungen) und „Bounced“ (Unzustellbar) auf derselben Seite. In diesen Reitern protokolliert Discourse E-Mails, deren Versand verweigert wurde oder die vom Relay abgelehnt wurden. Dort wird auch der Grund genannt, was schneller ist als das Lesen der Logs.

TLS: Zertifikatserstellung durch den Container

Wenn Discourse die Ports 80 und 443 verwaltet, nutzen Sie die integrierte Zertifikatsausstellung. Entfernen Sie die Kommentarzeichen vor den beiden oben gezeigten SSL-Template-Zeilen und führen Sie anschließend einen Rebuild durch. Das Template steuert acme.sh, speichert Zertifikate im freigegebenen Volume unter /shared/ssl, erneuert diese innerhalb des Containers nach Zeitplan und konfiguriert Discourse so, dass HTTPS erzwungen wird.

Port 80 muss für diesen Vorgang aus dem Internet erreichbar sein, da dort die HTTP-Challenge beantwortet wird. Eine Firewall, die nur Port 443 zulässt, führt zu einem erfolgreichen Build-Vorgang, bei dem das Zertifikat jedoch nie ausgestellt wird. Überprüfen Sie das Ergebnis direkt nach dem Rebuild mit ./launcher logs app.

Sollten Sie nginx oder Caddy vorschalten?

Wenn Discourse der einzige Webdienst auf dem VPS ist, sollten Sie dies nicht tun. Der Container betreibt bereits einen optimierten nginx. Ein zweiter Proxy fügt einen zusätzlichen Hop, ein weiteres zu erneuerndes Zertifikat und eine neue Fehlerquelle bei Headern hinzu.

Schalten Sie einen Proxy vor, wenn der VPS auch andere 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 auf einem Unix-Socket unter /var/discourse/shared/standalone/nginx.http.sock und belegt keine Ports. Dadurch werden 80 und 443 für Ihren eigenen Proxy frei.

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 nachgestellte Doppelpunkt nach .sock ist Teil der Unix-Socket-Syntax von nginx; sudo nginx -t lehnt die Konfiguration ohne diesen ab. X-Forwarded-Proto ist ebenfalls nicht optional. Discourse schreibt absolute Links; ohne diesen Header werden auf einer HTTPS-Seite http://-Links ausgegeben, die von Browsern als Mixed Content blockiert werden. Da der Container nun über einen Socket angebunden ist, liegt die TLS-Verwaltung bei Ihnen. Stellen Sie das Zertifikat daher auf dem Host aus, wie unter Certbot unter Ubuntu 24.04 und nginx beschrieben. Falls Sie sich noch nicht für einen Proxy entschieden haben, behandelt der Vergleich zwischen nginx, Caddy und Traefik die damit verbundenen Abwägungen.

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

cd /var/discourse
./launcher rebuild app

rebuild zerstört den laufenden Container, erstellt einen neuen aus app.yml und startet diesen. Die Website ist während des gesamten Build-Vorgangs offline; betrachten Sie daher jede Konfigurationsänderung als geplante Ausfallzeit von wenigen Minuten.

Änderungen, die nur Werte unter env: betreffen, erfordern dies nicht. ./launcher destroy app && ./launcher start app erstellt den Container aus dem bereits gebauten Image neu, was nur Sekunden dauert. Alles unter templates: oder hooks: ändert das Image selbst und erfordert daher einen vollständigen Rebuild.

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

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

Rebuilds sind der Punkt, an dem kleine Server scheitern, da die Asset-Kompilierung die höchste Speicherauslastung des gesamten Systems darstellt. Ein Build, der mittendrin abbricht und bei dem dmesg eine Zeile wie Out of memory: Killed process mit der Nennung eines ruby-Prozesses anzeigt, hatte während des Builds keinen Arbeitsspeicher mehr zur Verfügung, obwohl die Website selbst zuvor einwandfrei lief. Fügen Sie Swap hinzu und führen Sie den Rebuild erneut aus.

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

logs gibt die Ausgabe des Containers aus, enter öffnet eine Shell darin und cleanup entfernt Container, die seit mehr als 24 Stunden gestoppt sind. Führen Sie cleanup gelegentlich aus, da jeder Rebuild einen alten Container hinterlässt und der Speicherplatz auf einem kleinen VPS unbemerkt zur Neige gehen kann.

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 über die Shell ausführen.

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

discourse restore <filename> macht diesen Vorgang 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 sowie hochgeladene Dateien nur dann, wenn die entsprechende Backup-Einstellung für Uploads aktiviert ist. Überprüfen Sie diese Einstellung, bevor Sie sich auf das Backup verlassen. Es enthält niemals app.yml. Daher erfordert eine Wiederherstellung auf einem neuen VPS weiterhin Ihren Hostnamen und den SMTP-Block. Kopieren Sie diese Datei daher zusätzlich vom Server.

Das Archiv liegt zudem auf demselben Datenträger wie die zu schützende Website; dies stellt kein Backup dar. Übertragen Sie das Archiv planmäßig auf ein anderes System.

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

Was ein stark frequentiertes Forum an RAM verbraucht

Der Bootstrap-Prozess setzt UNICORN_WORKERS und db_shared_buffers basierend auf dem erkannten Arbeitsspeicher und der CPU. Die Beispielkonfiguration begrenzt die shared buffers auf ein Viertel des Gesamtspeichers. Jeder unicorn-Worker ist ein vollständiger Ruby-Prozess, und Sidekiq führt Hintergrund-Jobs parallel dazu aus. Der Speicherverbrauch korreliert daher mit der Anzahl der gleichzeitigen Anfragen und nicht mit der Anzahl der registrierten Mitglieder. Ein ruhiges Forum mit einigen hundert Mitgliedern stellt keine hohe Last dar.

Dimensionieren Sie den Server nicht anhand einer Zahl aus einem Artikel, auch nicht aus diesem. Messen Sie Ihren eigenen Bedarf.

free -m
docker stats --no-stream

Wenn Swap ständig genutzt wird und die Seiten langsam laden, fehlt es an RAM. Ein konstanter Speicherverbrauch bei gleichzeitig langsamen Seiten deutet meist auf eine andere Ursache hin. Lesen Sie daher ./launcher logs app, bevor Sie einen größeren Tarif buchen. Richten Sie zusätzlich eine Überwachung von außerhalb des Systems ein. Ein Forum, dem nachts um 3 Uhr der Speicher ausgeht, fällt unbemerkt aus: ein selbst gehosteter Uptime Kuma Status-Monitor auf einem separaten Host informiert Sie, bevor Ihre Mitglieder es bemerken.

Wann Discourse die falsche Wahl ist

Discourse ist eine umfangreiche Anwendung mit einer aufwendigen Installation und einem Rebuild-Zyklus für jede Einstellung, die in app.yml gespeichert ist. Dieser Aufwand erkauft Ihnen echte Moderationswerkzeuge und eine Suchfunktion, die auch bei großen Archiven noch funktioniert. Für dreißig Personen, die einen Ort zum Austausch suchen, ist es mehr Technik, als für die Unterhaltung erforderlich ist. Lesen Sie zuerst den Vergleich selbst gehosteter Forensoftware und entscheiden Sie sich für Discourse, weil Sie dessen Funktionen benötigen, nicht weil es der Name ist, den Sie bereits kannten.

FAQ

Kann ich Discourse auf einem VPS ohne Domainnamen installieren?

Nein. Die ausgelieferte Konfiguration sieht vor, dass Discourse nicht mit einer reinen IP-Adresse funktioniert; ein DISCOURSE_HOSTNAME ist erforderlich. Discourse erstellt absolute Links basierend auf diesem Hostnamen. Eine IP-Adresse führt daher zu defekten Links und verhindert die Ausstellung von Zertifikaten. Erstellen Sie einen A-Record, bevor Sie beginnen, und prüfen Sie mit dig +short forum.example.com, ob dieser korrekt auf die Adresse Ihres Servers auflöst.

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

Seit August 2026 können Sie diesen Schritt überspringen. Der Einrichtungsassistent bietet stattdessen Discourse-ID-Logins an, und app.yml enthält einen Schalter, der die Validierung der E-Mail-Einrichtung umgeht. Für alles, was über einen ersten Test hinausgeht, sollten Sie SMTP konfigurieren, da sowohl die Kontoaktivierung als auch das Zurücksetzen von Passwörtern per E-Mail erfolgen. Verwenden Sie ein authentifiziertes Relay auf Port 587 oder 465, da die meisten VPS-Anbieter den ausgehenden Port 25 blockieren.

Warum ist mein Discourse-Rebuild mittendrin fehlgeschlagen?

Arbeitsspeichermangel ist die häufigste Ursache. Die Asset-Kompilierung während des Builds benötigt mehr Speicher als der laufende Betrieb. Ein Server, der das Forum problemlos hostet, kann beim Rebuild dennoch scheitern. Wenn dmesg einen Out of memory: Killed process-Prozess im Zusammenhang mit Ruby anzeigt, fügen Sie Swap hinzu (die Swap-Datei des Assistenten ist 2 GB groß) und führen Sie ./launcher rebuild app erneut aus. Ein Build, der aufgrund eines YAML-Fehlers abbricht, deutet hingegen auf einen Einrückungsfehler in app.yml hin.

Sollte Discourse hinter meinem eigenen Nginx oder Caddy laufen?

Nur wenn der VPS auch andere Webseiten bereitstellt. Wenn der Server ausschließlich für Discourse genutzt wird, lassen Sie den Container die Ports 80 und 443 verwalten und seine Zertifikate selbst ausstellen; dies reduziert die Komplexität. Um die Maschine gemeinsam zu nutzen, fügen Sie templates/web.socketed.template.yml hinzu, kommentieren Sie die expose-Zeilen aus und leiten Sie Anfragen an den Unix-Socket unter /var/discourse/shared/standalone/nginx.http.sock weiter. Leiten Sie X-Forwarded-Proto durch, da Discourse sonst http://-Links auf einer HTTPS-Seite ausgibt.

Wie erstelle ich ein Backup eines selbst gehosteten Discourse?

Verwenden Sie die Backup-Seite in der Administrationsoberfläche oder führen Sie discourse backup nach ./launcher enter app aus. Archive werden auf dem Host unter /var/discourse/shared/standalone/backups/default/ abgelegt. Stellen Sie sicher, dass die Einstellung zum Einbeziehen von Uploads aktiviert ist, kopieren Sie /var/discourse/containers/app.yml zusammen mit dem Archiv und verschieben Sie beides auf eine andere Maschine. Ein Backup auf derselben Festplatte wie die Webseite übersteht den Ausfall, vor dem es schützen soll, nicht.