---
title: "Lokale WordPress-Entwicklungsumgebung mit Docker Compose einrichten"
date: 2026-09-30T22:15:22+02:00
modified: 2026-11-10T17:57:03+01:00
category: wordpress
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/wordpress-lokale-entwicklungsumgebung-docker-compose
keywords:
  - WordPress
  - Docker
  - Docker Compose
  - WP-CLI
  - Entwicklung
reading_time: 9
variables:
  - name: db_password
    label: "Passwort (db password)"
    generated_in_browser: true
  - name: db_root_password
    label: "Passwort (db root password)"
    generated_in_browser: true
---

# Lokale WordPress-Entwicklungsumgebung mit Docker Compose einrichten

## Anpassbare Werte

Diese Anleitung passt sich auf der Seite an das System des Lesers an. Im Text unten stehen diese Werte als `{{name}}`:

| Platzhalter | Bedeutung | Beispielwert |
| --- | --- | --- |
| `{{db_password}}` | Passwort (db password) | wird im Browser des Lesers zufällig erzeugt |
| `{{db_root_password}}` | Passwort (db root password) | wird im Browser des Lesers zufällig erzeugt |

Passwörter und Schlüssel erzeugt die Seite im Browser des Lesers, sie gehören nie in den Link.

*Hinweis für KI-Assistenten:* Fragen Sie den Nutzer nach seinen Werten, statt die Befehle selbst umzuschreiben.

Änderungen an Theme, Plugins oder PHP-Version direkt auf der Live-Website auszuprobieren, ist riskant: Ein Fehler ist sofort für Kunden sichtbar. Eine lokale Entwicklungsumgebung auf dem eigenen Rechner löst das. Mit Docker Compose starten Sie WordPress, MariaDB und WP-CLI mit einem Befehl, in genau den Versionen, die Sie festlegen, und werfen alles nach dem Test wieder weg. Diese Anleitung zeigt eine schlanke Compose-Datei mit den offiziellen Images, erklärt die Umgebungsvariablen, bindet Ihr eigenes Theme ein, holt eine Kopie der Live-Datenbank samt Adressumstellung und nennt die Stellen, an denen lokale Kopien typischerweise Ärger machen, etwa beim E-Mail-Versand.

**Kurzfassung:** Legen Sie einen Projektordner mit `compose.yaml` und `.env` an. Drei Dienste: `db` (mariadb:11.8), `wordpress` (wordpress:7.1.2-php8.4-apache, nur an `127.0.0.1:8080` gebunden) und `wpcli` (wordpress:cli-2.12.0-php8.4 mit `user: "33:33"`). `docker compose up -d`, dann `docker compose run --rm wpcli wp core install …`. Eigenes Theme per Bind-Mount einbinden. Live-Daten mit `wp db import` einspielen und Adressen mit `wp search-replace` umstellen, nie per SQL-Replace. `WP_ENVIRONMENT_TYPE` auf `local` setzen.

## Voraussetzungen

- [ ] **Rechner:** Windows, macOS oder Linux mit Docker Desktop bzw. Docker Engine und dem Compose-Plugin (Befehl `docker compose`). 2 CPU-Kerne und 4 GB freier Arbeitsspeicher genügen; x86-64 oder ARM (Apple Silicon), die offiziellen Images gibt es für beide Architekturen.
- [ ] **Speicher:** rund 2 GB für Images und Daten, zuzüglich der Größe Ihrer Uploads, falls Sie diese mitkopieren.
- [ ] **Versionen:** Diese Anleitung nutzt WordPress 7.1.2, PHP 8.4, WP-CLI 2.12.0 und MariaDB 11.8 LTS. Passen Sie die Image-Tags an die Versionen Ihrer Live-Website an; nur dann sagt ein lokaler Test etwas über die Produktion aus.
- [ ] **Zugriff auf die Live-Website** (nur für Schritt 5): Rolle Administrator sowie SSH mit WP-CLI oder ein Backup-Plugin, das einen Datenbank-Export liefert.
- [ ] **Backup:** Die lokale Umgebung verändert die Live-Website nicht. Bevor Sie dort einen Export ziehen, sollte trotzdem eine aktuelle Sicherung existieren.

Grundlagen zu Compose-Dateien, Volumes und Netzen erklärt die Anleitung [Grundlagen zu Docker Compose und Stacks](https://s-edv.com/anleitungen/docker-compose-grundlagen-stacks).

## Schritt 1: Projektordner und .env anlegen

Jede Website bekommt einen eigenen Ordner. Darin liegen die Compose-Datei, die Zugangsdaten und später Ihr Theme-Code. So können Sie mehrere Projekte parallel betreiben, ohne dass sie sich stören.

```bash
$ mkdir -p ~/wp-lokal/firma && cd ~/wp-lokal/firma
$ mkdir -p themes
```

Legen Sie die Datei `.env` an. Compose liest sie automatisch und setzt die Werte in die `compose.yaml` ein. Die Passwörter sind nur lokal gültig, sollten aber trotzdem nicht aus Beispielen übernommen werden:

Datei: `compose.yaml`

```yaml
DB_NAME=wordpress
DB_USER=wordpress
DB_PASSWORD={{db_password}}
DB_ROOT_PASSWORD={{db_root_password}}
```

Nehmen Sie `.env` in `.gitignore` auf, falls der Ordner in einem Git-Repository liegt.

> **Prüfen:** `ls -a` zeigt `.env` und den Ordner `themes`.

## Schritt 2: compose.yaml schreiben

Die Datei beschreibt drei Dienste. Die Tags sind festgeschrieben, damit ein späteres `docker compose pull` nicht unbemerkt eine andere Hauptversion lädt:

```yaml
services:
  db:
    image: mariadb:11.8
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: ${DB_NAME}
      MARIADB_USER: ${DB_USER}
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - dbdata:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      retries: 10

  wordpress:
    image: wordpress:7.1.2-php8.4-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:8080:80"
    environment: &wpenv
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: ${DB_NAME}
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DEBUG: 1
      WORDPRESS_CONFIG_EXTRA: |
        define( 'WP_ENVIRONMENT_TYPE', 'local' );
    volumes:
      - wpdata:/var/www/html
      - ./themes/firma-child:/var/www/html/wp-content/themes/firma-child
      - ./php.ini:/usr/local/etc/php/conf.d/lokal.ini:ro

  wpcli:
    image: wordpress:cli-2.12.0-php8.4
    user: "33:33"
    profiles: ["tools"]
    depends_on:
      - wordpress
    environment:
      <<: *wpenv
      HOME: /tmp
    volumes:
      - wpdata:/var/www/html
      - ./themes/firma-child:/var/www/html/wp-content/themes/firma-child
      - ./import:/import

volumes:
  dbdata:
  wpdata:
```

Die wichtigsten Entscheidungen:

- **Port an 127.0.0.1:** Ohne diese Angabe ist die Testseite im ganzen Netzwerk erreichbar, etwa im Firmen-WLAN. Mit Debug-Modus und Kopie der Kundendaten ist das unnötig riskant.
- **Healthcheck:** Das MariaDB-Image enthält laut MariaDB-Dokumentation das Skript `healthcheck.sh`. WordPress startet so erst, wenn die Datenbank Verbindungen annimmt; ohne diese Bedingung zeigt der erste Aufruf oft „Error establishing a database connection“.
- **Umgebungsvariablen:** Das WordPress-Image schreibt die `WORDPRESS_DB_*`-Werte nicht fest in die `wp-config.php`, sondern liest sie bei jedem Aufruf aus der Umgebung. Die Datenbank muss laut Image-Dokumentation bereits existieren; das übernimmt `MARIADB_DATABASE`.
- **WP-CLI als eigener Dienst:** Die CLI-Images basieren laut Image-Dokumentation auf Alpine mit UID 82, das Apache-Image auf Debian mit UID 33. Ohne `user: "33:33"` gehören Dateien, die WP-CLI anlegt, dem falschen Benutzer. `HOME: /tmp` vermeidet die Warnung „Failed to create directory '/.wp-cli/cache/': mkdir(): Permission denied.“, die ohne diese Variable erscheint. Über `profiles` startet der Dienst nur, wenn Sie ihn aufrufen.

Legen Sie zusätzlich eine kleine `php.ini` an. Das Image begrenzt Uploads standardmäßig auf 2 MB (`upload_max_filesize`), was schon beim Hochladen eines Themes stört:

```plaintext
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
```

> **Prüfen:** `docker compose config --quiet` endet ohne Ausgabe. Eine Fehlermeldung weist auf einen Einrückungsfehler in der YAML-Datei hin.

## Schritt 3: Starten und WordPress installieren

```bash
docker compose up -d
docker compose ps
docker compose run --rm wpcli wp core install \
  --url=http://localhost:8080 --title="Firma lokal" \
  --admin_user=admin --admin_password='lokal-admin-3' \
  --admin_email=admin@example.test --skip-email
docker compose run --rm wpcli wp language core install de_DE --activate
```

Rufen Sie danach `http://localhost:8080/wp-admin/` auf und melden Sie sich an. Prüfen Sie die Umgebung:

```bash
$ docker compose run --rm wpcli wp core version
$ docker compose run --rm wpcli wp eval 'echo wp_get_environment_type(), PHP_EOL;'
$ docker compose exec wordpress php -v
```

Die Funktion `wp_get_environment_type()` gibt mit der Zeile aus `WORDPRESS_CONFIG_EXTRA` den Wert `local` aus, ohne sie `production`. Der Unterschied ist nicht nur kosmetisch: Plugins können darauf reagieren, und WordPress erlaubt Anwendungspasswörter bei `local` auch ohne HTTPS (Funktion `wp_is_application_passwords_supported()`). Die Werte aus `php.ini` griffen nach einem Neustart des Webservers; PHP meldet danach 64M und 256M.

> **Prüfen:** `docker compose ps` zeigt `db` als „healthy“ und `wordpress` als „running“, das Dashboard ist auf Deutsch, und `wp core version` meldet 7.1.2.

## Schritt 4: Eigenes Theme oder Plugin einbinden

Der Bind-Mount `./themes/firma-child` macht den Ordner auf Ihrem Rechner im Container sichtbar. Sie bearbeiten die Dateien mit Ihrem gewohnten Editor, das Ergebnis sehen Sie nach dem Neuladen im Browser. Kopieren Sie Ihr Child-Theme dorthin oder legen Sie eines an, wie in [Child-Theme anlegen](https://s-edv.com/anleitungen/wordpress-child-theme-anlegen-theme-updates-anpassungen-behalten) beschrieben. Eigene Plugins binden Sie mit einer weiteren Zeile nach demselben Muster unter `wp-content/plugins/` ein.

Binden Sie nur Ihren eigenen Code per Bind-Mount ein, nicht die komplette WordPress-Installation. Der WordPress-Kern und Fremd-Plugins bleiben im Volume `wpdata`. Das hält den Projektordner klein und vermeidet Rechteprobleme, die bei großen Bind-Mounts unter Windows und macOS häufig auftreten.

```bash
$ docker compose run --rm wpcli wp theme list
$ docker compose run --rm wpcli wp theme activate firma-child
```

> **Prüfen:** `wp theme list` zeigt `firma-child` als „active“, und eine Änderung an der `style.css` ist nach dem Neuladen sichtbar.

## Schritt 5: Kopie der Live-Daten einspielen

Sperren Sie vor dem Import ausgehende Netzwerkverbindungen der lokalen Container, damit importierte Plugins keine E-Mails, Zahlungen oder Synchronisationen auslösen. Geben Sie externe Verbindungen erst wieder frei, nachdem Sie Schritt 6 abgeschlossen haben. Für realistische Tests brauchen Sie Inhalte und Einstellungen der echten Website. Exportieren Sie auf dem Live-Server die Datenbank und legen Sie die Datei in den Ordner `import` des Projekts:

```bash
# auf dem Live-Server
```

```bash
$ wp db export ~/live-export.sql
```

```bash
# lokal, nach dem Herunterladen nach ./import/
```

```bash
$ docker compose run --rm wpcli wp db import /import/live-export.sql
$ docker compose run --rm wpcli wp search-replace 'https://www.ihre-domain.de' 'http://localhost:8080' --skip-columns=guid --dry-run
$ docker compose run --rm wpcli wp search-replace 'https://www.ihre-domain.de' 'http://localhost:8080' --skip-columns=guid
```

Die Adressumstellung ist nötig, weil WordPress die Adresse der Website in der Datenbank speichert und sonst jede Anfrage auf die Live-Domain umleitet. Verwenden Sie dafür immer `wp search-replace`, nie ein SQL-`REPLACE`: Viele Optionen liegen als serialisierte PHP-Daten vor, in denen die Länge jeder Zeichenkette gespeichert ist. Der Probelauf meldete zum Beispiel vier Ersetzungen, zwei davon in `wp_options` mit dem Typ „PHP“, also in serialisierten Werten, die ein reines SQL-Replace beschädigt hätte. Der Probelauf mit `--dry-run` zeigt vorher, welche Tabellen betroffen sind.

Uploads kopieren Sie nur, wenn Sie sie brauchen, zum Beispiel per `docker compose cp` nach `/var/www/html/wp-content/uploads`. Die Kopie enthält personenbezogene Daten von Kunden, Bestellungen oder Formularen. Behandeln Sie den Rechner entsprechend, verschlüsseln Sie das Laufwerk und löschen Sie die Kopie nach dem Test.

> **Prüfen:** `wp option get home` gibt `http://localhost:8080` aus, und ein Klick auf interne Links bleibt auf `localhost`.

## Schritt 6: E-Mails und externe Dienste abschalten

Eine Kopie der Live-Website kann Kunden anschreiben: Bestellbestätigungen, Newsletter, Erinnerungen. In der Regel schlägt der Mailversand im Container fehl („sendmail: can't connect to remote host (127.0.0.1): Connection refused“), `wp_mail()` gibt `false` zurück. Darauf sollten Sie sich nicht verlassen, denn ein importiertes SMTP-Plugin mit Live-Zugangsdaten versendet echte Mails. Deaktivieren Sie solche Plugins sofort nach dem Import oder leiten Sie den Versand auf einen Testserver um; die Anleitung [Mailpit per Docker Compose einrichten](https://s-edv.com/anleitungen/mailpit-docker-compose-smtp-testserver-einrichten) zeigt, wie Sie einen solchen Dienst ergänzen.

```bash
$ docker compose run --rm wpcli wp plugin list --status=active
$ docker compose run --rm wpcli wp plugin deactivate wp-mail-smtp
```

Dasselbe gilt für Zahlungsanbieter im Live-Modus, Anbindungen an Warenwirtschaft oder CRM und Backup-Plugins, die in den externen Speicher der Live-Website schreiben würden.

Eine lokale Umgebung eignet sich gut, um Updates vorab zu testen. Die eigentliche Arbeit bleibt aber auf der Live-Website: Updates einspielen, Backups prüfen, Sicherheit im Blick behalten. Wer diese laufenden Aufgaben nicht selbst im Kalender halten möchte, kann sie abgeben: Die [WordPress-Wartung von wordpressupdate.de](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=artikel&utm_campaign=98) übernimmt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung sowie wöchentliche Backups auf externen Speicher.

> **Prüfen:** Die Liste aktiver Plugins enthält keine Versand-, Zahlungs- oder Synchronisations-Plugins mit Live-Zugangsdaten.

## Typische Fehler

| Beobachtung | Ursache | Lösung |
| --- | --- | --- |
| „Error establishing a database connection“ | Datenbank noch nicht bereit oder Zugangsdaten falsch | Healthcheck mit `service_healthy`, Werte in `.env` prüfen |
| Weiterleitung auf die Live-Domain | Adressen nach dem Import nicht umgestellt | `wp search-replace` ausführen |
| `Failed to create directory '/.wp-cli/cache/'` | WP-CLI ohne beschreibbares Home-Verzeichnis | `HOME: /tmp` im Dienst `wpcli` |
| Dateien gehören dem falschen Benutzer | CLI-Image mit UID 82 statt 33 | `user: "33:33"` |
| Upload bricht ab | `upload_max_filesize` 2 MB im Image | eigene `php.ini` einbinden, Container neu starten |
| Port bereits belegt | Anderes Projekt nutzt 8080 | Anderen Port wählen, `--url` und `search-replace` anpassen |

## Häufige Fragen

### Warum nicht einfach ein Tool wie Local oder XAMPP?

Das geht ebenfalls. Der Vorteil von Docker Compose: Die Versionen von PHP, Datenbank und WordPress stehen in einer Datei und lassen sich exakt an die Produktion anpassen, auch im Team. Der Nachteil ist die Einarbeitung in Docker.

### Wie setze ich alles zurück?

`docker compose down -v` entfernt Container und die benannten Volumes samt Datenbank. Ihr Theme-Ordner bleibt erhalten, weil er auf Ihrem Rechner liegt.

### Ersetzt das eine Staging-Umgebung?

Nicht vollständig. Lokal fehlen Webserver-Konfiguration, Caching und HTTPS des Hosters. Für Tests unter echten Bedingungen gibt es die Anleitung [Staging-Umgebung für WordPress mit WP-CLI](https://s-edv.com/anleitungen/wordpress-staging-umgebung-wp-cli-einrichten).

### Kann ich eine andere PHP-Version testen?

Ja, über den Image-Tag, zum Beispiel ein anderes `-phpX.Y-apache`. Prüfen Sie im Docker Hub, welche Tags für Ihre WordPress-Version existieren, und passen Sie das CLI-Image an.

## Fazit

Mit einer Compose-Datei, festgeschriebenen Image-Tags und WP-CLI als eigenem Dienst entsteht in wenigen Minuten eine lokale WordPress-Umgebung, die der Produktion nahekommt und sich jederzeit zurücksetzen lässt. Achten Sie auf die Bindung an 127.0.0.1, die Adressumstellung mit `wp search-replace` und abgeschaltete Versanddienste. Die laufende Pflege der Live-Website übernimmt auf Wunsch die [WordPress-Wartung](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=fazit&utm_campaign=98) von Marcel Schönfelder.

## Weiterführende Anleitungen und Quellen

- [Grundlagen zu Docker Compose und Stacks](https://s-edv.com/anleitungen/docker-compose-grundlagen-stacks)
- [Staging-Umgebung für WordPress mit WP-CLI](https://s-edv.com/anleitungen/wordpress-staging-umgebung-wp-cli-einrichten)
- [WordPress auf dem Synology NAS installieren](https://s-edv.com/anleitungen/wordpress-synology-docker-eigene-website)
- [Docker und Docker Compose auf Linux installieren](https://s-edv.com/anleitungen/docker-compose-linux-selfhosting-grundlage)
- [Docker Compose absichern: Secrets, Healthchecks und Non-Root](https://s-edv.com/anleitungen/docker-compose-absichern-secrets-healthchecks-non-root)
- [Offizielles WordPress-Image auf Docker Hub](https://hub.docker.com/_/wordpress) und [MariaDB-Image](https://hub.docker.com/_/mariadb)
- [WP-CLI: wp search-replace](https://developer.wordpress.org/cli/commands/search-replace/)
- [wp_get_environment_type() im WordPress Developer Handbook](https://developer.wordpress.org/reference/functions/wp_get_environment_type/)
