# WordPress Testumgebung mit Docker **Datum:** 22. Juni 2026 **Zielumgebung:** Ubuntu Server, Docker, Portainer **Produktionssystem:** WordPress 7.0, PHP 8.1, Apache, Ubuntu 22.04, MariaDB 10.6 **Testsystem:** Docker Compose, MariaDB 10.6, WordPress 7.0 FPM-Alpine, Nginx, phpMyAdmin, WP-CLI --- ## 1. Vorbereitung: Produktionssystem sichern ### 1.1 WP-CLI auf Produktionsserver installieren ```bash curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp wp --info ``` ### 1.2 Datenbank exportieren ```bash sudo -u www-data wp --path=/var/www/html db export /tmp/muckibackup.sql ``` ### 1.3 wp-content sichern ```bash tar czf /tmp/wp-content.tar.gz -C /var/www/html wp-content ``` ### 1.4 Dateien auf den Docker-Host übertragen ```bash scp user@prod-server:/tmp/muckibackup.sql ~/muckibackup/ scp user@prod-server:/tmp/wp-content.tar.gz ~/muckibackup/ ``` --- ## 2. Verzeichnisstruktur anlegen ```bash mkdir -p ~/muckibackup/wp-content cd ~/muckibackup # wp-content entpacken tar xzf wp-content.tar.gz -C ./wp-content --strip-components=1 # Berechtigungen setzen (UID 82 = www-data in Alpine) sudo chown -R 82:82 ./wp-content ``` Tabellenprefix aus dem Dump prüfen: ```bash grep -m1 "CREATE TABLE" ~/muckibackup/muckibackup.sql ``` --- ## 3. Konfigurationsdateien erstellen ### 3.1 `.env` ```env MYSQL_ROOT_PASSWORD=sicheresRootPW MYSQL_DATABASE=wordpress MYSQL_USER=wp_user MYSQL_PASSWORD=sicheresUserPW WP_TABLE_PREFIX=wp_ WP_PORT=8088 PMA_PORT=8181 ``` ### 3.2 `docker-compose.yml` ```yaml services: db: image: mariadb:10.6 restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} volumes: - wp_db_data:/var/lib/mysql networks: - wp_internal healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s timeout: 5s retries: 5 wordpress: image: wordpress:7.0-php8.5-fpm-alpine restart: unless-stopped depends_on: db: condition: service_healthy environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: ${MYSQL_DATABASE} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_TABLE_PREFIX: ${WP_TABLE_PREFIX} volumes: - wp_core:/var/www/html - /home/hans/muckibackup/wp-content:/var/www/html/wp-content networks: - wp_internal nginx: image: nginx:1.27-alpine restart: unless-stopped depends_on: - wordpress ports: - "${WP_PORT}:80" volumes: - wp_core:/var/www/html:ro - /home/hans/muckibackup/wp-content:/var/www/html/wp-content:ro - /home/hans/muckibackup/nginx.conf:/etc/nginx/conf.d/default.conf:ro networks: - wp_internal phpmyadmin: image: phpmyadmin:5.2-apache restart: unless-stopped depends_on: - db ports: - "${PMA_PORT}:80" environment: PMA_HOST: db PMA_USER: ${MYSQL_USER} PMA_PASSWORD: ${MYSQL_PASSWORD} UPLOAD_LIMIT: 512M networks: - wp_internal wpcli: image: wordpress:cli-php8.3 restart: "no" depends_on: db: condition: service_healthy environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: ${MYSQL_DATABASE} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} volumes: - wp_core:/var/www/html - /home/hans/muckibackup/wp-content:/var/www/html/wp-content networks: - wp_internal entrypoint: ["wp", "--allow-root"] volumes: wp_db_data: driver: local wp_core: driver: local networks: wp_internal: driver: bridge ``` ### 3.3 `nginx.conf` ```nginx server { listen 80; root /var/www/html; index index.php; client_max_body_size 64M; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { fastcgi_pass wordpress:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_read_timeout 300; } location ~ /\.ht { deny all; } } ``` --- ## 4. Stack in Portainer deployen 1. Portainer öffnen → **Stacks → Add Stack** 2. Name: `wordpress-test` 3. Build method: **Upload** → `docker-compose.yml` hochladen 4. Unter **Environment variables**: Inhalt der `.env` eintragen 5. **Deploy the stack** Warten bis alle Container den Status **running** zeigen. --- ## 5. Datenbank importieren ### Option A: Via phpMyAdmin (empfohlen bis 512 MB) 1. Browser: `http://SERVERIP:8181` 2. Links: Datenbank **wordpress** anklicken 3. Reiter **Importieren** → Datei `muckibackup.sql` auswählen 4. **OK** ### Option B: Via CLI ```bash docker exec -i wordpress-test_db_1 \ mysql -u wp_user -psicheresUserPW wordpress \ < ~/muckibackup/muckibackup.sql ``` --- ## 6. Produktions-URL anpassen Aktuelle URL aus der DB ermitteln (phpMyAdmin → wordpress → SQL-Reiter): ```sql SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl', 'home'); ``` URL ersetzen — im WordPress-Container (Portainer → wordpress-Container → Console): ```bash curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar php wp-cli.phar search-replace \ 'http://www.gh-muschitz.at' \ 'http://SERVERIP:8088' \ --skip-columns=guid --allow-root --path=/var/www/html ``` --- ## 7. Funktionstest ```bash # HTTP-Status prüfen curl -sI http://SERVERIP:8088 | head -3 # Uploads erreichbar? curl -sI http://SERVERIP:8088/wp-content/uploads/2022/03/beispiel.jpg | head -3 # Logs beobachten docker logs wordpress-test_wordpress_1 --tail=20 docker logs wordpress-test_nginx_1 --tail=20 ``` - Testsystem: `http://SERVERIP:8088` - phpMyAdmin: `http://SERVERIP:8181` --- ## 8. Theme-Dateien anpassen und deployen ### 8.1 Theme-Verzeichnis ermitteln ```bash ssh user@prod-server "ls /var/www/html/wp-content/themes/" ``` ### 8.2 Datei lokal bearbeiten Theme-Dateien liegen im Testsystem unter: ``` /home/hans/muckibackup/wp-content/themes/THEME-NAME/ ``` ### 8.3 Geänderte Datei auf Produktion übertragen ```bash # Backup der Originaldatei ssh user@prod-server \ "cp /var/www/html/wp-content/themes/THEME-NAME/header.php \ /var/www/html/wp-content/themes/THEME-NAME/header.php.bak" # Neue Datei übertragen scp header.php user@prod-server:/var/www/html/wp-content/themes/THEME-NAME/header.php # Berechtigungen prüfen ssh user@prod-server \ "chown www-data:www-data /var/www/html/wp-content/themes/THEME-NAME/header.php" ``` ### 8.4 Bilder/Assets auf Produktion übertragen ```bash scp burgenlandlogo.png user@prod-server:/var/www/html/wp-content/uploads/2026/06/ ssh user@prod-server \ "chown www-data:www-data /var/www/html/wp-content/uploads/2026/06/burgenlandlogo.png" ``` --- ## 9. Stack verwalten ```bash # Stack stoppen docker compose -f ~/muckibackup/docker-compose.yml down # Stack neu starten docker compose -f ~/muckibackup/docker-compose.yml up -d # Alles löschen inkl. DB-Volumes (für Neustart von Null) docker compose -f ~/muckibackup/docker-compose.yml down -v ``` --- ## Hinweise > **Pi-hole Konflikt:** Pi-hole belegt Port 80 auf allen Interfaces. Nginx immer auf einem anderen Port betreiben (z.B. 8088). > **UID/GID:** Das `fpm-alpine` Image verwendet UID 82 für www-data. Bind-Mounts mit `sudo chown -R 82:82` setzen. > **Nginx muss wp-content mounten:** Nginx benötigt denselben `wp-content` Bind-Mount wie WordPress — sonst werden statische Dateien (Bilder, CSS, JS) nicht gefunden und PHP gibt 404 zurück. > **URL nach jedem DB-Import anpassen:** Nach erneutem Import muss `search-replace` wiederholt werden. > **WP-CLI auf Produktion:** Immer als `sudo -u www-data wp --path=/var/www/html` ausführen, nicht als root — sonst wechseln Dateibesitzer auf root.