Überarbeitet am 9. September 2026.

Diese Anleitung brauchte dringend eine Überarbeitung. Die alte Version startete das normale WordPress-Apache-Image, konfigurierte anschließend aber einen Nginx-Container so, als würde WordPress auf FastCGI-Port 9000 laufen. Das waren zwei verschiedene Betriebsarten vermischt.

Heute zeige ich den Aufbau, den ich selbst bevorzuge: WordPress und MariaDB laufen in Docker, Nginx läuft bereits auf dem Host als Reverse Proxy.

Voraussetzungen

Docker und das Compose-Plugin sollten bereits installiert sein. Falls nicht, findest du hier meine aktuelle Anleitung: Docker und Docker Compose unter Debian/Ubuntu installieren.

Für das Beispiel verwende ich:

  • WordPress 7.1 mit PHP 8.4 und Apache,
  • MariaDB 11.8,
  • einen externen Nginx auf dem Host,
  • die lokale Weiterleitung 127.0.0.1:8080.

Projektverzeichnis anlegen

sudo mkdir -p /opt/wordpress
cd /opt/wordpress

Zugangsdaten in .env ablegen

Passwörter möchte ich nicht direkt in der compose.yaml verteilen. Deshalb lege ich eine .env an:

nano .env

Beispiel:

WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=HIER_EIN_LANGES_ZUFAELLIGES_PASSWORT
MARIADB_ROOT_PASSWORD=NOCH_EIN_LANGES_ZUFAELLIGES_PASSWORT

Danach die Datei vor anderen lokalen Benutzern schützen:

chmod 600 .env

compose.yaml erstellen

nano compose.yaml

Meine schlanke Basis sieht so aus:

services:
  db:
    image: mariadb:11.8
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: ${WORDPRESS_DB_NAME}
      MARIADB_USER: ${WORDPRESS_DB_USER}
      MARIADB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 10

  wordpress:
    image: wordpress:7.1.0-php8.4-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
      WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      WORDPRESS_CONFIG_EXTRA: |
        if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
            $_SERVER['HTTPS'] = 'on';
        }
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - wp_data:/var/www/html

volumes:
  db_data:
  wp_data:

Warum nur 127.0.0.1?

Der WordPress-Container muss in diesem Aufbau nicht selbst öffentlich auf Port 8080 erreichbar sein. Nginx sitzt davor und ist der einzige öffentliche Einstiegspunkt.

Deshalb:

127.0.0.1:8080:80

und nicht:

8080:80

Das reduziert unnötig offene Docker-Ports.

Container starten

docker compose up -d
docker compose ps

Die Logs des WordPress-Containers kannst du bei Bedarf so verfolgen:

docker compose logs -f --tail=100 wordpress

Nginx als Reverse Proxy

Wenn Nginx auf dem Host bereits HTTPS und das Zertifikat verwaltet, reicht für WordPress im Kern ein Reverse Proxy auf den lokalen Port.

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;

    client_max_body_size 128M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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-Proto $scheme;
    }
}

Vor dem Neuladen immer testen:

sudo nginx -t
sudo systemctl reload nginx

WordPress einrichten

Danach rufst du die konfigurierte HTTPS-Domain im Browser auf. Wenn Datenbank und Container gesund sind, erscheint der normale WordPress-Einrichtungsdialog.

Die Datenbank-Zugangsdaten müssen dort nicht nochmals eingegeben werden, weil das offizielle Docker-Image sie bereits aus den Umgebungsvariablen erhält.

Backups: zwei Dinge gehören zusammen

Ein WordPress-Backup besteht nicht nur aus dem Volume wp_data. Ebenso wichtig ist die MariaDB-Datenbank. Ich sichere deshalb immer Dateien und Datenbank.

Die Docker-Volumes allein sind noch kein Backup, solange sie nur auf demselben Server liegen.

Updates

Für neue Container-Images:

docker compose pull
docker compose up -d

Vor größeren WordPress-, PHP- oder Datenbank-Sprüngen würde ich immer ein aktuelles Backup erstellen und die Release-Hinweise prüfen.

Mehr zu Compose selbst findest du in meiner Erklärung Docker Compose: Services, Volumes, Ports und Netzwerke verstehen.

Apache oder FPM?

Das offizielle WordPress-Image gibt es sowohl mit Apache als auch als FPM-Variante. FPM ist interessant, wenn Nginx direkt mit PHP-FPM im privaten Docker-Netz sprechen soll. Das Setup ist aber etwas komplexer, weil Nginx dann auch Zugriff auf die WordPress-Dateien benötigt.

Für einen bereits vorhandenen externen Nginx finde ich den hier gezeigten Apache-Container auf localhost angenehm unkompliziert.

Fazit

Damit ist WordPress sauber getrennt: MariaDB bleibt intern, WordPress ist nur lokal auf Port 8080 erreichbar und der vorhandene Nginx übernimmt Domain, HTTPS und öffentlichen Zugriff. Vor allem ist der Aufbau jetzt technisch konsistent – im Gegensatz zur alten Mischung aus Apache-Image und FastCGI-Konfiguration.

Quelle: Docker Official Image: WordPress.