GitHub-fähiger WordPress-Stack mit WordPress (Apache/PHP 8.5), MySQL 8, Redis 8, OPcache und vollständig per .env konfigurierbaren Traefik-Labels.
wordpress: WordPress mit Apache und PHP 8.5mysql: MySQL 8, nur im internen Backend-Netzwerkredis: Redis 8 als Object Cache, nur im internen Backend-Netzwerkproxy: vorhandenes externes Docker-Netzwerk für Traefikbackend: internes Docker-Netzwerk ohne externen Zugriff- Apache
mod_remoteip: stellt hinter Cloudflare und Traefik die echte Besucher-IP wieder her
git clone https://github.com/happylippo/wordpress-stack.git
cd wordpress-stack
cp .env.example .envErzeuge zwei unterschiedliche sichere Passwörter, beispielsweise mit:
openssl rand -base64 32Trage sie in .env ein:
MYSQL_PASSWORD=CHANGE_ME_DATABASE_PASSWORD
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORDPasse anschließend mindestens die Domain an:
TRAEFIK_RULE=Host(`wordpress.example.com`)Falls das externe Traefik-Netzwerk noch nicht existiert:
docker network create proxyBeim ersten Start wird das angepasste WordPress-Image gebaut:
docker compose config
docker compose up -d --buildBei späteren normalen Starts reicht:
docker compose up -d--build ist nur erforderlich, wenn sich das Dockerfile, docker-entrypoint-realip.sh oder andere in das Image eingebaute Dateien ändern. Änderungen an .env erfordern normalerweise keinen erneuten Image-Build.
Status und Logs:
docker compose ps
docker compose logs -f wordpress mysql redisAlle Traefik-Labelwerte des WordPress-Containers werden über .env gesteuert:
TRAEFIK_ENABLE=true
TRAEFIK_DOCKER_NETWORK=proxy
TRAEFIK_ENTRYPOINTS=websecure
TRAEFIK_RULE=Host(`wordpress.example.com`)
TRAEFIK_SERVICE_NAME=wordpress-app
TRAEFIK_SERVICE_PORT=80
TRAEFIK_TLS=true
TRAEFIK_CERTRESOLVER=cloudflare_resolver
TRAEFIK_MIDDLEWARES=security-headers@file
TRAEFIK_PASS_HOST_HEADER=trueMehrere Middlewares können kommasepariert angegeben werden:
TRAEFIK_MIDDLEWARES=security-headers@file,crowdsec@fileDie Compose-Konfiguration setzt außerdem FORCE_SSL_ADMIN und berücksichtigt X-Forwarded-Proto, damit WordPress HTTPS hinter Traefik korrekt erkennt.
Die Request-Kette ist typischerweise:
Besucher -> Cloudflare -> Traefik -> WordPress/Apache
Ohne zusätzliche Konfiguration sieht Apache nur die IP-Adresse des vorgeschalteten Traefik-Containers. Der Stack aktiviert deshalb Apache mod_remoteip und verwendet den von Cloudflare gesetzten Header CF-Connecting-IP.
Die vertrauenswürdigen Proxy-Adressen werden in .env als kommaseparierte Liste angegeben. IPv4 und IPv6 können gemeinsam verwendet werden:
TRUSTED_PROXIES=172.31.191.254,fd00:1:be:a:7001:0:3e:7fffBeim Containerstart erzeugt docker-entrypoint-realip.sh daraus für jede Adresse eine eigene Apache-Direktive:
RemoteIPTrustedProxy 172.31.191.254
RemoteIPTrustedProxy fd00:1:be:a:7001:0:3e:7fffAuch CIDR-Netze können eingetragen werden, beispielsweise:
TRUSTED_PROXIES=172.31.128.0/18,fd00:1:be:a:7001:0:3e:7000/116Aus Sicherheitsgründen sollten nur tatsächlich vertrauenswürdige Traefik-Adressen bzw. möglichst eng gefasste Docker-Netze eingetragen werden. Andernfalls könnte ein nicht vertrauenswürdiger Client versuchen, den CF-Connecting-IP-Header zu manipulieren.
Nach der Verarbeitung durch mod_remoteip enthält Apache %a die echte Besucher-IP. PHP und WordPress erhalten diese ebenfalls über REMOTE_ADDR.
Prüfen kannst du das über:
docker compose logs -f wordpressNach einer erstmaligen Aktivierung oder Änderung am Dockerfile/EntryPoint:
docker compose up -d --buildÄnderst du später lediglich TRUSTED_PROXIES in .env, reicht normalerweise:
docker compose up -dCompose erstellt den WordPress-Container bei geänderter Environment-Konfiguration neu und das EntryPoint-Script generiert die Apache-Proxy-Konfiguration beim Start erneut.
WordPress erhält bereits die Redis-Verbindungsparameter über WORDPRESS_CONFIG_EXTRA:
- Host:
redis - Port:
6379 - Datenbank: konfigurierbar über
REDIS_DATABASE
Installiere im WordPress-Backend anschließend das Plugin Redis Object Cache und aktiviere dort den Object Cache.
Redis ist nicht am Host veröffentlicht und ausschließlich über das interne Backend-Netzwerk erreichbar.
Die versionierte Konfiguration befindet sich in:
config/php/opcache.ini
Sie wird read-only nach /usr/local/etc/php/conf.d/10-opcache.ini eingebunden.
Prüfen:
docker compose exec wordpress php -i | grep -i opcacheNach Änderungen:
docker compose up -d --force-recreate wordpressDie Standardwerte sind auf einen normalen WordPress-Produktivbetrieb ausgelegt. opcache.validate_timestamps=1 bleibt aktiviert, damit Plugin-, Theme- und Core-Updates ohne manuelles Leeren des OPcache erkannt werden.
Die PHP-Limits befinden sich in:
config/php/uploads.ini
Standardwerte:
upload_max_filesize=128Mpost_max_size=128Mmemory_limit=512Mmax_execution_time=300max_input_vars=5000
Bei vorgeschalteten Proxys oder CDN-Diensten können zusätzliche Upload-Limits gelten.
Die wichtigsten Tuning-Werte sind über .env konfigurierbar:
MYSQL_INNODB_BUFFER_POOL_SIZE=256M
MYSQL_MAX_CONNECTIONS=100Weitere statische Einstellungen liegen unter:
config/mysql/custom.cnf
Der InnoDB Buffer Pool sollte passend zum verfügbaren RAM des Servers dimensioniert werden.
Redis verwendet AOF-Persistenz und standardmäßig:
REDIS_MAXMEMORY=256mb
REDIS_MAXMEMORY_POLICY=allkeys-lruDa Redis hier als Cache und nicht als primärer Datenspeicher verwendet wird, ist allkeys-lru für diesen Einsatzzweck sinnvoll.
Neue Basis-Images herunterladen und das eigene WordPress-Image neu bauen:
docker compose pull
docker compose build --pull wordpress
docker compose up -d
docker image pruneVor Updates sollte ein getestetes Backup vorhanden sein.
.envist über.gitignorevom Repository ausgeschlossen.- MySQL und Redis besitzen keine veröffentlichten Host-Ports.
- Das Backend-Netzwerk ist als
internalmarkiert. - Nur WordPress hängt zusätzlich im externen Traefik-Netzwerk.
CF-Connecting-IPwird nur über explizit konfigurierte vertrauenswürdige Proxies akzeptiert.- Datenbankpasswörter gehören ausschließlich in die lokale
.env. - Für Produktion sollten regelmäßige Backups und Wiederherstellungstests eingerichtet werden.