2026-06-22 20:21:04 +02:00
2026-06-22 20:21:04 +02:00
2026-06-22 20:21:04 +02:00
2026-06-22 20:21:04 +02:00

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

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

sudo -u www-data wp --path=/var/www/html db export /tmp/muckibackup.sql

1.3 wp-content sichern

tar czf /tmp/wp-content.tar.gz -C /var/www/html wp-content

1.4 Dateien auf den Docker-Host übertragen

scp user@prod-server:/tmp/muckibackup.sql ~/muckibackup/
scp user@prod-server:/tmp/wp-content.tar.gz ~/muckibackup/

2. Verzeichnisstruktur anlegen

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:

grep -m1 "CREATE TABLE" ~/muckibackup/muckibackup.sql

3. Konfigurationsdateien erstellen

3.1 .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

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

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: Uploaddocker-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

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):

SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('siteurl', 'home');

URL ersetzen — im WordPress-Container (Portainer → wordpress-Container → Console):

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

# 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

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

# 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

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

# 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.

S
Description
No description provided
Readme 32 KiB
Languages
PHP 100%