Zurück
26/08/2025
Im letzten Beitrag habe ich gezeigt, wie sich WordPress mit Docker Compose schnell aufsetzen lässt. Das Setup war allerdings nur lokal unter http://localhost:3000 erreichbar. In diesem Beitrag gehen wir den nächsten Schritt und machen unseren Service über eine eigene Domain mit automatischem SSL-Zertifikat erreichbar. Möglich macht das alles Traefik.
Traefik ist ein moderner Reverse Proxy, der speziell für Container-Umgebungen entwickelt wurde. Das Besondere daran: Traefik erkennt automatisch neue Docker-Container und kann diese über Labels konfigurieren. Das bedeutet, dass wir keine klassischen Konfigurationsdateien pflegen müssen. Zusätzlich übernimmt Traefik die automatische Beschaffung und Erneuerung von SSL-Zertifikaten über Let's Encrypt.
Bevor wir loslegen, sollte Folgendes vorhanden sein:
Für diesen Guide verwende ich meine Domain pndl.net. Diese musst du natürlich durch deine eigene Domain ersetzen.
Als Erstes erstellen wir eine eigene docker-compose.yml für Traefik. Ich empfehle, Traefik in einem separaten Compose-Projekt zu verwalten, da er als zentraler Reverse Proxy für alle Services dient.
services:
traefik:
image: traefik:v3.4
container_name: traefik
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=me@pndl.net"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- traefik
networks:
traefik:
name: traefikIn diesem Setup passiert bereits einiges. Bevor wir starten, gehe ich auf die wichtigsten Punkte ein.
Die gesamte Konfiguration von Traefik erfolgt hier über die command-Einträge. Das hat den Vorteil, dass alles in einer einzigen Datei sichtbar bleibt.
--entrypoints.web.address=:80: Definiert den HTTP-Eingang auf Port 80.--entrypoints.websecure.address=:443: Definiert den HTTPS-Eingang auf Port 443.--entrypoints.web.http.redirections.entryPoint.to=websecure: Leitet alle HTTP-Anfragen automatisch auf HTTPS um.--providers.docker=true: Aktiviert die automatische Erkennung von Docker-Containern.--providers.docker.exposedbydefault=false: Verhindert, dass alle Container automatisch erreichbar sind. Nur Container mit dem Label traefik.enable=true werden veröffentlicht.--certificatesresolvers.letsencrypt.acme.httpchallenge=true: Aktiviert die HTTP-Challenge zur Zertifikatsverifizierung.--certificatesresolvers.letsencrypt.acme.email=me@pndl.net: Die E-Mail-Adresse, die bei Let's Encrypt hinterlegt wird. Hier solltest du eine echte E-Mail-Adresse eintragen.--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json: Der Speicherort für die Zertifikate innerhalb des Containers./var/run/docker.sock:/var/run/docker.sock:ro: Gibt Traefik Lesezugriff auf den Docker-Socket, damit neue Container automatisch erkannt werden../letsencrypt:/letsencrypt: Persistiert die SSL-Zertifikate, damit sie nach einem Neustart nicht erneut angefordert werden müssen.networks: traefik: Erstellt ein gemeinsames Netzwerk, über das sich Traefik mit den anderen Services verbindet.Nun passen wir die WordPress-docker-compose.yml aus dem letzten Beitrag an. Die wichtigsten Änderungen: Wir entfernen die ports-Konfiguration vom WordPress-Service, da Traefik nun die Weiterleitung übernimmt, und fügen stattdessen Labels hinzu.
services:
wordpress:
image: wordpress
container_name: wordpress
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: wordpress-db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: wordpress
volumes:
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
- ./app:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.routers.wordpress.rule=Host(`pndl.net`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
networks:
- traefik
- default
wordpress-db:
image: mysql
container_name: wordpress-db
restart: unless-stopped
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- ./mysql_data:/var/lib/mysql
volumes:
mysql_data:
networks:
traefik:
external: trueDie Traefik-Labels am WordPress-Service steuern, wie der Container von außen erreichbar ist.
traefik.enable=true: Aktiviert Traefik für diesen Container.traefik.http.routers.wordpress.rule=Host(`pndl.net`): Definiert, unter welcher Domain der Service erreichbar ist. Hier musst du deine eigene Domain eintragen.traefik.http.routers.wordpress.entrypoints=websecure: Der Service wird nur über HTTPS (Port 443) bereitgestellt.traefik.http.routers.wordpress.tls.certresolver=letsencrypt: Verwendet den zuvor konfigurierten Let's Encrypt Resolver, um automatisch ein SSL-Zertifikat zu beschaffen.traefik.http.services.wordpress.loadbalancer.server.port=80: Teilt Traefik mit, auf welchem internen Port der Service lauscht.Der WordPress-Service muss sich im traefik-Netzwerk befinden, damit Traefik den Traffic weiterleiten kann. Gleichzeitig bleibt das default-Netzwerk bestehen, damit WordPress und die Datenbank miteinander kommunizieren können. Die Datenbank selbst braucht keinen Zugang zum Traefik-Netzwerk, da sie nicht von außen erreichbar sein soll.
Das Traefik-Netzwerk wird als external: true markiert, da es bereits im Traefik-Compose-Projekt erstellt wurde.
Zuerst starten wir Traefik, da das Netzwerk existieren muss, bevor andere Services es verwenden können.
# Im Traefik-Verzeichnis
docker compose up -dAnschließend starten wir WordPress.
# Im WordPress-Verzeichnis
docker compose up -dNach wenigen Sekunden sollte WordPress unter https://pndl.net erreichbar sein, und das mit einem gültigen SSL-Zertifikat.
Zu Beginn kann es vorkommen, dass dein Browser sich über ein ungültiges Zertifikat beschwert. Das liegt meist am Caching, denn der Browser hat sich noch das alte, selbstsignierte Zertifikat von Traefik gemerkt, bevor Let's Encrypt das echte ausgestellt hat. Ein kurzer Moment Geduld, ein Neuladen mit geleertem Cache oder ein Aufruf im Inkognito-Fenster schaffen hier in der Regel Abhilfe.
Das Schöne an diesem Setup ist, dass sich jeder weitere Service auf die gleiche Weise anbinden lässt. Einfach die Traefik-Labels setzen, das traefik-Netzwerk einbinden und eine andere Domain oder Subdomain verwenden, ohne Traefik selbst anpassen zu müssen. Als Beispiel binden wir phpMyAdmin an, um unsere Datenbank bequem über https://pma.pndl.net im Browser verwalten zu können. Dazu fügen wir der WordPress-docker-compose.yml einfach einen weiteren Service hinzu.
phpmyadmin:
image: phpmyadmin
container_name: phpmyadmin
restart: unless-stopped
environment:
PMA_HOST: wordpress-db
labels:
- "traefik.enable=true"
- "traefik.http.routers.phpmyadmin.rule=Host(`pma.pndl.net`)"
- "traefik.http.routers.phpmyadmin.entrypoints=websecure"
- "traefik.http.routers.phpmyadmin.tls.certresolver=letsencrypt"
- "traefik.http.services.phpmyadmin.loadbalancer.server.port=80"
networks:
- traefik
- defaultÜber PMA_HOST: wordpress-db verbindet sich phpMyAdmin mit demselben Datenbank-Service, den auch WordPress nutzt. Wichtig ist, dass auch hier ein passender DNS-Eintrag für die Subdomain pma.pndl.net auf den Server zeigt. Das war es schon, nach einem docker compose up -d ist phpMyAdmin unter der eigenen Subdomain mit gültigem SSL-Zertifikat erreichbar.
Mit Traefik als Reverse Proxy wird das Bereitstellen von Docker-Services unter eigenen Domains mit SSL-Zertifikaten sehr angnehm. Die Konfiguration erfolgt direkt über Labels an den einzelnen Services, was das Hinzufügen neuer Anwendungen extrem einfach macht.