
Mit dem Reverse-Proxy Traefik lassen sich Docker-Container effizient verwalten und komfortabel im Browser aufrufen – ganz ohne manuelles Jonglieren mit Portnummern.
In diesem Beitrag richten wir eine lokale Testumgebung ein, die verschiedene Webprojekte umfasst: mehrere WordPress-Instanzen, phpMyAdmin, Joomla, Drupal, eine statische HTML Seiten und eine Landing-Page für das Projekt. Host-System ist Ubuntu 25.04.

Alle Dateien und Skripte des Projekts haben wir für Sie auf GitHub bereitgestellt.
Im vorherigen Beitrag haben wir bereits gezeigt, wie sich eine einfache WordPress-Testumgebung mit Docker aufsetzen lässt. Nun erweitern wir dieses Setup und machen es durch Traefik deutlich flexibler und übersichtlicher.

Projektstruktur
Alle Dienste werden in einem übergeordneten Projektverzeichnis namens WebDev
organisiert. Für jeden Container gibt es einen eigenen Unterordner mit einer individuellen docker-compose.yaml
. Ein zentrales Skript steuert den Start und Stopp aller Container gleichzeitig.
Das Projekt umfasst:
traefik
– zentrale Reverse-Proxy-Konfigurationwp1
,wp2
– zwei eigenständige WordPress-Instanzendrupal1
– Drupal mit PostgreSQLjoomla1
– Joomla mit MySQLhtml
– statische Website mit NGINXpma
– phpMyAdmin zur Datenbankverwaltunglandingpage
– eine zentrale Startseite mit Links zu allen ProjektenREADME.md
-Dateien – Dokumentation pro Container (optional)
Verzeichnisbaum:
WebDev/
├── drupal1/
│ ├── compose.yaml
│ └── README.md
├── html/
│ ├── compose.yaml
│ └── public/
│ └── index.html
├── joomla1/
│ ├── compose.yaml
│ └── README.md
├── landingpage/
│ ├── compose.yaml
│ ├── public/
│ │ ├── index.html
│ │ └── styles.css
│ └── README.md
├── pma/
│ ├── compose.yaml
│ └── README.md
├── traefik/
│ └── compose.yaml
├── wp1/
│ ├── compose.yaml
│ └── README.md
├── wp2/
│ ├── compose.yaml
│ └── README.md
├── start-all.sh
├── stop-all.sh
└── README.md
Container erstellen
Die einzelnen Unterordner enthalten jeweils ihre eigene Compose-Datei. Jedes Web-Projekt verwendet einen eigenen Datenbank-Container.
1. Traefik als Reverse-Proxy
Der traefik
-Container ist die zentrale Schaltstelle. Er lauscht auf Port 80
(lokal begrenzt auf 127.0.0.1
) und leitet Anfragen basierend auf der gewünschten Domain weiter.
Jeder Service registriert sich bei Traefik über Container-Labels, etwa:
labels:
- "traefik.enable=true"
- "traefik.http.routers.wp1.rule=Host(`wp1.localhost`)"
- "traefik.http.routers.wp1.entrypoints=web"
Anhand diese Labels erkennt Traefik den Service, an den die Anfrage weitergeleitet werden soll. Ohne Traefik würde diese Adressierung durch Port-Nummern vorgenommen.
Wir erstellen den Container mit einer compose.yaml
Datei:
# traefik compose local restricted
services:
traefik:
image: traefik:v3.4
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--api.dashboard=true"
- "--api.insecure=true"
- "--log.level=INFO"
ports:
- "127.0.0.1:80:80" # nur lokal zugänglich
- "127.0.0.1:8080:8080" # Dashboard nur lokal
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- webdev-net
restart: unless-stopped
networks:
webdev-net:
external: true
Ein Dashboard unter http://localhost:8080
zeigt aktive Router, Services und Netzwerke. Für die Testumgebung ist eine Authentifizierung nicht erforderlich, im Produktiveinsatz aber unbedingt.


Die Ansicht im Dashboard lässt sich mit den üblichen Tastenkombinationen vergrößern und verkleinern, ohne dabei unbenutzbar zu werden.
Strg + Plus-Taste
Strg + Bindestrick (Minus)
2. Webprojekte (CMS und statisch)
Jedes CMS wird in einem eigenen Compose-Projekt betrieben:
- WordPress (mit MariaDB)
- Drupal (mit PostgreSQL)
- Joomla (mit MySQL)
- HTML-Seite (mit NGINX)
Alle sind über .localhost
-Domains erreichbar, z. B.
wp1.localhost
drupal1.localhost
Beispiel für eine compose.yaml
Datei:
# compose.yaml Example
services:
wordpress1:
image: wordpress
environment:
WORDPRESS_DB_HOST: db_wp1
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: wordpress
volumes:
- wp1_data:/var/www/html
networks:
- webdev-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.wp1.rule=Host(`wp1.localhost`)"
- "traefik.http.routers.wp1.entrypoints=web"
restart: unless-stopped
db_wp1:
image: mariadb
container_name: wp1-db_wp1
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- db_wp1_data:/var/lib/mysql
networks:
- webdev-net
restart: unless-stopped
volumes:
wp1_data:
db_wp1_data:
networks:
webdev-net:
external: true
Erläuterungen:
Domain wp1.localhos t | wird von Traefik per Label erkann |
Netzwerk webdev-net | alle Container (inkl. Traefik) müssen darin sein |
Keine Ports notwendig | dank Traefik entfallen individuelle ports: -Einträge |
Datenbank-Zugang über phpMyAdmin | Mit Host db_wp1 , Benutzer wordpress , Passwort examplepass |
Sie starten die einzelnen Web-Instanzen jeweils aus dem Verzeichnis heraus, in dem sich die compose.yaml Datei befindet. Weiter unten zeigen wir, wie man alle Container gleichzeitig per Skript starten kann.
In einem Terminal, z.B. für wp1:
cd WebDev/wp1
# und Starten mit
sudo docker compose up -d
Die Seite im Browser erreichen Sie dann mit der Eingabe von
wp1.localhost
Weiter unten erklären wir, wie Sie eine Landing-Page erstellen, von der aus alle Web-Projekte im Browser aufgerufen werden.
Nun startet wie gewohnt die Installation:



3. phpMyAdmin
Zur Verwaltung der MariaDB- und MySQL-Datenbanken verwenden wir phpMyAdmin
. Durch die Umgebungsvariable PMA_ARBITRARY=1
kann man beim Login frei wählen, mit welchem Datenbankhost man sich verbindet – etwa
db_wp1
oder db_joomla1



Die WordPress-Datenbank ist vor der Installation noch leer, Joomla haben wir schon eingerichtet, die Datenbank ist mit Inhalten gefüllt.
4. Landing Page
Eine einfache statische Startseite listet alle Projekte mit Links auf. Sie wird über NGINX bereitgestellt und ist unter webdev.localhost
erreichbar. Das HTML-Gerüst ist minimal gehalten, das Styling erfolgt per styles.css
.

Netzwerk
Alle Container verwenden dasselbe benannte externe Netzwerk webdev-net
, um miteinander zu kommunizieren und von Traefik erkannt zu werden.
Container starten und stoppen per Skript
Für den bequemen Start/Stopp der gesamten Umgebung haben wir zwei Skripte angelegt, die Sie im Terminal aufrufen:
# alle Projekte starten:
sudo bash start-all.sh
# alle Projekte stoppen:
sudo bash stop-all.sh
Weil docker-compose in unserer Installation Administratorrechte benötigt, also der einzelne Befehl lauten würde:
sudo docker compose up -d
starten wir zunächst ein Terminal als Administrator sudo bash
und führen anschließend das Skript mit allen Start- oder Stop-Befehlen aus.

Ausblick
Die Umgebung lässt sich flexibel erweitern – z. B. um:
- weitere CMS-Systeme wie Typo3 oder DokuWiki
- Webmail, Newsletter-Tools oder Shop-Systeme
- einen internen Mailserver für Testzwecke
- automatische Zertifikate mit Let’s Encrypt (bei externem Zugriff)