Ghost 6 mit Docker Compose und externem Nginx installieren

Überarbeitet am 8. September 2026.

Auf meinen Servern läuft Nginx gerne direkt auf dem Host, während Anwendungen in Docker-Containern stecken. Genau für dieses Szenario ist diese Anleitung gedacht: Ghost 6 + MySQL 8 in Docker Compose, davor ein bereits vorhandener Nginx.

Ghost selbst bietet seit Version 6 zusätzlich einen neuen offiziellen Docker-Compose-Stack als Preview an. Der bringt unter anderem Caddy und auf Wunsch die selbst gehosteten Social-Web-/Analytics-Dienste mit. Wer diesen kompletten Stack möchte, sollte direkt die offizielle Ghost-Dokumentation nutzen. Hier bleiben wir bewusst bei einem schlanken Setup mit dem offiziellen Ghost-Docker-Image und meinem externen Nginx.

Voraussetzungen

  • Docker Engine und Docker Compose,
  • Nginx auf dem Host,
  • eine Domain mit DNS-Eintrag auf den Server,
  • Port 80/443 für Nginx,
  • ein SMTP-Dienst für produktive Ghost-E-Mails.

Falls Docker noch fehlt: Docker und Docker Compose installieren. Den Aufbau einer Compose-Datei erkläre ich außerdem in Docker Compose erklärt.

Projektordner anlegen

sudo mkdir -p /opt/ghost
sudo chown $USER:$USER /opt/ghost
cd /opt/ghost

Passwörter nicht in compose.yaml schreiben

Wir legen eine .env an:

nano .env
GHOST_URL=https://blog.example.de
MYSQL_DATABASE=ghost
MYSQL_USER=ghost
MYSQL_PASSWORD=ein-langes-zufaelliges-passwort
MYSQL_ROOT_PASSWORD=ein-anderes-langes-zufaelliges-passwort

Danach:

chmod 600 .env

Für besonders sensible Setups unterstützt das offizielle Ghost-Image inzwischen auch Docker-Secrets über Variablen mit dem Suffix _FILE. Für einen überschaubaren Einzelserver ist eine geschützte .env aber ein verständlicher Einstieg.

compose.yaml erstellen

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost -p$${MYSQL_ROOT_PASSWORD} --silent"]
      interval: 10s
      timeout: 5s
      retries: 10

  ghost:
    image: ghost:6-alpine
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:2368:2368"
    environment:
      database__client: mysql
      database__connection__host: db
      database__connection__user: ${MYSQL_USER}
      database__connection__password: ${MYSQL_PASSWORD}
      database__connection__database: ${MYSQL_DATABASE}
      url: ${GHOST_URL}
      NODE_ENV: production
    volumes:
      - ghost_content:/var/lib/ghost/content

volumes:
  db_data:
  ghost_content:

Die zwei wichtigsten Sicherheitsdetails dabei:

  • MySQL hat gar keinen veröffentlichten Host-Port.
  • Ghost-Port 2368 ist nur an 127.0.0.1 gebunden und damit nicht direkt aus dem Internet erreichbar.

Container starten

docker compose up -d
docker compose ps
docker compose logs --tail=100 ghost

Nginx als Reverse Proxy

Für die Domain kann ein schlanker Serverblock so aussehen:

server {
    listen 80;
    listen [::]:80;
    server_name blog.example.de;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name blog.example.de;

    ssl_certificate /etc/letsencrypt/live/blog.example.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/blog.example.de/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:2368;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Ghosts offizielles Docker-Image weist für Produktionsbetrieb ausdrücklich auf HTTPS sowie passende X-Forwarded-For-, X-Forwarded-Host– und X-Forwarded-Proto-Header hin.

Nginx testen

sudo nginx -t
sudo systemctl reload nginx

Danach erreichst du Ghost Admin unter:

https://blog.example.de/ghost/

Ghost aktualisieren

Vor größeren Versionssprüngen: Backup und Release Notes lesen. Für normale Image-Updates:

cd /opt/ghost
docker compose pull
docker compose up -d

Ich würde Ghost nicht blind in irgendeine nächtliche Auto-Update-Schleife werfen. Warum, erkläre ich in Docker-Container 2026 sicher aktualisieren.

Favicon und Branding

Nach der Installation brauchst du für ein normales Favicon keine alten Server-Tricks mehr. Ghost besitzt dafür das Publication Icon im Adminbereich. Dazu gibt es ebenfalls eine aktualisierte Anleitung: Favicon und Apple Touch Icon in Ghost einrichten.

Alternative: klassische Ghost-CLI

Ghost 6 lässt sich weiterhin ohne Docker auf dem offiziell unterstützten Ubuntu-/Node-/MySQL-/Nginx-Stack installieren: Ghost 6 unter Ubuntu 24.04 mit Ghost-CLI installieren.

Fazit

Wenn Nginx ohnehin auf dem Host läuft, brauche ich keinen zusätzlichen öffentlich erreichbaren Webserver-Container. Ghost und MySQL bleiben sauber im Docker-Umfeld, Ghost lauscht ausschließlich lokal und Nginx übernimmt TLS und den öffentlichen Zugriff.

Quellen: Docker Official Image: Ghost, Ghost: Docker Compose preview und Ghost: Ubuntu installation.

Wie ist deine Meinung?
Schreib gern einen Kommentar unter dem Artikel oder diskutiere mit anderen im Matrix-Kanal: #dasnetzundich:matrix.org

5 Kommentare zu „Ghost 6 mit Docker Compose und externem Nginx installieren“

Schreibe einen Kommentar