Docker Stack Traefik: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Die Seite wurde neu angelegt: „Dieser Artikel beschreibt einen kompletten Docker-Compose-Stack mit '''Traefik''' als Reverse-Proxy, einer gemeinsamen '''MariaDB''' und den beiden Webanwendun…“ |
Keine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
Dieser Artikel beschreibt einen | Dieser Artikel beschreibt einen Docker-Compose-Stack mit '''Traefik''' als Reverse-Proxy und den beiden Webanwendungen '''Nextcloud''' und '''MediaWiki''', die jeweils eine '''eigene, getrennte''' MariaDB erhalten. Traefik erkennt die Container automatisch über Labels und terminiert TLS mit einem statischen Wildcard-Zertifikat. | ||
==Konzept== | ==Konzept== | ||
| Zeile 9: | Zeile 9: | ||
* Im Lab gibt es kein ACME/Let's-Encrypt nach außen. Das Wildcard-Zertifikat liegt unter <code>/etc/ssl/own.crt</code> und <code>/etc/ssl/own.key</code> und wird per File-Provider als Default registriert. | * Im Lab gibt es kein ACME/Let's-Encrypt nach außen. Das Wildcard-Zertifikat liegt unter <code>/etc/ssl/own.crt</code> und <code>/etc/ssl/own.key</code> und wird per File-Provider als Default registriert. | ||
; | ; Pro App eine eigene Datenbank | ||
* | * Jede Anwendung bekommt einen eigenen MariaDB-Container in einem eigenen Backend-Netz. Es gibt '''keine''' gemeinsame Datenbank. Eine kompromittierte Anwendung kann damit nicht über eine geteilte DB an die Daten der anderen Anwendung gelangen. | ||
==Netz-Trennung== | |||
; proxy | |||
* Verbindet Traefik mit den Webanwendungen. | |||
; nextcloud-back | |||
* Verbindet '''nur''' Nextcloud mit seiner Datenbank. | |||
; mediawiki-back | |||
* Verbindet '''nur''' MediaWiki mit seiner Datenbank. | |||
Die beiden DB-Container hängen jeweils nur an ihrem eigenen Backend-Netz und sind weder von außen noch von der jeweils anderen Anwendung erreichbar. | |||
==Verzeichnisstruktur== | ==Verzeichnisstruktur== | ||
| Zeile 17: | Zeile 30: | ||
docker-stack/ | docker-stack/ | ||
├── docker-compose.yml | ├── docker-compose.yml | ||
└── traefik/ | |||
└── dynamic/ | |||
└── tls.yml | |||
</pre> | </pre> | ||
| Zeile 54: | Zeile 65: | ||
- proxy | - proxy | ||
# | # Nextcloud + eigene DB | ||
db: | nextcloud-db: | ||
image: mariadb:11 | image: mariadb:11 | ||
container_name: db | container_name: nextcloud-db | ||
restart: unless-stopped | restart: unless-stopped | ||
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW | command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW | ||
environment: | environment: | ||
MARIADB_ROOT_PASSWORD: rootpass | MARIADB_ROOT_PASSWORD: nc-rootpass | ||
MARIADB_DATABASE: nextcloud | |||
MARIADB_USER: nextcloud | |||
MARIADB_PASSWORD: nextcloudpass | |||
MARIADB_AUTO_UPGRADE: "1" | MARIADB_AUTO_UPGRADE: "1" | ||
volumes: | volumes: | ||
- | - nextcloud_db:/var/lib/mysql | ||
networks: | networks: | ||
- | - nextcloud-back | ||
nextcloud: | nextcloud: | ||
image: nextcloud:30-apache | image: nextcloud:30-apache | ||
| Zeile 75: | Zeile 87: | ||
restart: unless-stopped | restart: unless-stopped | ||
depends_on: | depends_on: | ||
- db | - nextcloud-db | ||
environment: | environment: | ||
MYSQL_HOST: db | MYSQL_HOST: nextcloud-db | ||
MYSQL_DATABASE: nextcloud | MYSQL_DATABASE: nextcloud | ||
MYSQL_USER: nextcloud | MYSQL_USER: nextcloud | ||
| Zeile 89: | Zeile 101: | ||
networks: | networks: | ||
- proxy | - proxy | ||
- | - nextcloud-back | ||
labels: | labels: | ||
- "traefik.enable=true" | - "traefik.enable=true" | ||
| Zeile 100: | Zeile 112: | ||
- "traefik.http.routers.nextcloud.middlewares=nc-dav" | - "traefik.http.routers.nextcloud.middlewares=nc-dav" | ||
# MediaWiki | # MediaWiki + eigene DB | ||
mediawiki-db: | |||
image: mariadb:11 | |||
container_name: mediawiki-db | |||
restart: unless-stopped | |||
environment: | |||
MARIADB_ROOT_PASSWORD: mw-rootpass | |||
MARIADB_DATABASE: mediawiki | |||
MARIADB_USER: mediawiki | |||
MARIADB_PASSWORD: mediawikipass | |||
MARIADB_AUTO_UPGRADE: "1" | |||
volumes: | |||
- mediawiki_db:/var/lib/mysql | |||
networks: | |||
- mediawiki-back | |||
mediawiki: | mediawiki: | ||
image: mediawiki:1.43 | image: mediawiki:1.43 | ||
| Zeile 106: | Zeile 133: | ||
restart: unless-stopped | restart: unless-stopped | ||
depends_on: | depends_on: | ||
- db | - mediawiki-db | ||
volumes: | volumes: | ||
- mediawiki_data:/var/www/html/images | - mediawiki_data:/var/www/html/images | ||
| Zeile 113: | Zeile 140: | ||
networks: | networks: | ||
- proxy | - proxy | ||
- | - mediawiki-back | ||
labels: | labels: | ||
- "traefik.enable=true" | - "traefik.enable=true" | ||
| Zeile 123: | Zeile 150: | ||
networks: | networks: | ||
proxy: | proxy: | ||
nextcloud-back: | |||
mediawiki-back: | |||
volumes: | volumes: | ||
nextcloud_db: | |||
nextcloud_data: | nextcloud_data: | ||
mediawiki_db: | |||
mediawiki_data: | mediawiki_data: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 147: | Zeile 176: | ||
* Traefik liest die Container-Labels über den Docker-Socket. Der wird '''read-only''' gemountet. | * Traefik liest die Container-Labels über den Docker-Socket. Der wird '''read-only''' gemountet. | ||
=== | ===Datenbanken=== | ||
; | ; Anlage über Umgebungsvariablen | ||
* | * Jeder MariaDB-Container legt Datenbank und Benutzer beim ersten Start selbst an, gesteuert über <code>MARIADB_DATABASE</code>, <code>MARIADB_USER</code> und <code>MARIADB_PASSWORD</code>. Ein separates Init-Skript ist nicht nötig. | ||
; | ; Getrennte Volumes | ||
* <code> | * <code>nextcloud_db</code> und <code>mediawiki_db</code> sind voneinander unabhängige Volumes. Jede DB hat ihren eigenen Datenbestand. | ||
==Traefik Dynamic Config (tls.yml)== | ==Traefik Dynamic Config (tls.yml)== | ||
| Zeile 178: | Zeile 202: | ||
; Default-Zertifikat | ; Default-Zertifikat | ||
* Durch das <code>default</code>-Store reicht an jedem Router ein einfaches <code>tls=true</code>. Traefik greift automatisch auf dieses Zertifikat zurück, ein eigener Cert-Verweis pro Router entfällt. | * Durch das <code>default</code>-Store reicht an jedem Router ein einfaches <code>tls=true</code>. Traefik greift automatisch auf dieses Zertifikat zurück, ein eigener Cert-Verweis pro Router entfällt. | ||
==Inbetriebnahme== | ==Inbetriebnahme== | ||
| Zeile 228: | Zeile 231: | ||
; Erstaufruf im Browser | ; Erstaufruf im Browser | ||
* MediaWiki startet ohne <code>LocalSettings.php</code> mit dem Web-Installer. Als Datenbank-Host <code>db</code>, Datenbank <code>mediawiki</code>, Benutzer <code>mediawiki</code> angeben. | * MediaWiki startet ohne <code>LocalSettings.php</code> mit dem Web-Installer. Als Datenbank-Host <code>mediawiki-db</code>, Datenbank <code>mediawiki</code>, Benutzer <code>mediawiki</code> angeben. | ||
; LocalSettings.php einhängen | ; LocalSettings.php einhängen | ||
* Nach dem Setup wird die generierte <code>LocalSettings.php</code> heruntergeladen, neben das Compose-File gelegt und der auskommentierte Volume-Mount im <code>mediawiki</code>-Service aktiviert. Danach Container neu starten. | * Nach dem Setup wird die generierte <code>LocalSettings.php</code> heruntergeladen, neben das Compose-File gelegt und der auskommentierte Volume-Mount im <code>mediawiki</code>-Service aktiviert. Danach Container neu starten. | ||
* <code>docker compose up -d mediawiki</code> | * <code>docker compose up -d mediawiki</code> | ||
Version vom 27. Juni 2026, 16:13 Uhr
Dieser Artikel beschreibt einen Docker-Compose-Stack mit Traefik als Reverse-Proxy und den beiden Webanwendungen Nextcloud und MediaWiki, die jeweils eine eigene, getrennte MariaDB erhalten. Traefik erkennt die Container automatisch über Labels und terminiert TLS mit einem statischen Wildcard-Zertifikat.
Konzept
- Traefik als Reverse-Proxy
- Im Gegensatz zu HAProxy werden die Backends nicht von Hand konfiguriert. Traefik liest die Docker-Labels der Container und erzeugt Router und Services dynamisch.
- Statisches Zertifikat
- Im Lab gibt es kein ACME/Let's-Encrypt nach außen. Das Wildcard-Zertifikat liegt unter
/etc/ssl/own.crtund/etc/ssl/own.keyund wird per File-Provider als Default registriert.
- Pro App eine eigene Datenbank
- Jede Anwendung bekommt einen eigenen MariaDB-Container in einem eigenen Backend-Netz. Es gibt keine gemeinsame Datenbank. Eine kompromittierte Anwendung kann damit nicht über eine geteilte DB an die Daten der anderen Anwendung gelangen.
Netz-Trennung
- proxy
- Verbindet Traefik mit den Webanwendungen.
- nextcloud-back
- Verbindet nur Nextcloud mit seiner Datenbank.
- mediawiki-back
- Verbindet nur MediaWiki mit seiner Datenbank.
Die beiden DB-Container hängen jeweils nur an ihrem eigenen Backend-Netz und sind weder von außen noch von der jeweils anderen Anwendung erreichbar.
Verzeichnisstruktur
docker-stack/
├── docker-compose.yml
└── traefik/
└── dynamic/
└── tls.yml
docker-compose.yml
services:
# Traefik - Reverse Proxy (statisches Wildcard-Cert)
traefik:
image: traefik:v3.3
container_name: traefik
restart: unless-stopped
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--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"
- "./traefik/dynamic:/etc/traefik/dynamic:ro"
- "/etc/ssl/own.crt:/etc/ssl/own.crt:ro"
- "/etc/ssl/own.key:/etc/ssl/own.key:ro"
networks:
- proxy
# Nextcloud + eigene DB
nextcloud-db:
image: mariadb:11
container_name: nextcloud-db
restart: unless-stopped
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
environment:
MARIADB_ROOT_PASSWORD: nc-rootpass
MARIADB_DATABASE: nextcloud
MARIADB_USER: nextcloud
MARIADB_PASSWORD: nextcloudpass
MARIADB_AUTO_UPGRADE: "1"
volumes:
- nextcloud_db:/var/lib/mysql
networks:
- nextcloud-back
nextcloud:
image: nextcloud:30-apache
container_name: nextcloud
restart: unless-stopped
depends_on:
- nextcloud-db
environment:
MYSQL_HOST: nextcloud-db
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_PASSWORD: nextcloudpass
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: adminpass
NEXTCLOUD_TRUSTED_DOMAINS: cloud.it2XX.xinmen.de.int
OVERWRITEPROTOCOL: https
volumes:
- nextcloud_data:/var/www/html
networks:
- proxy
- nextcloud-back
labels:
- "traefik.enable=true"
- "traefik.http.routers.nextcloud.rule=Host(`cloud.it2XX.xinmen.de.int`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls=true"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
- "traefik.http.middlewares.nc-dav.redirectregex.regex=https://([^/]*)/.well-known/(card|cal)dav"
- "traefik.http.middlewares.nc-dav.redirectregex.replacement=https://$${1}/remote.php/dav/"
- "traefik.http.routers.nextcloud.middlewares=nc-dav"
# MediaWiki + eigene DB
mediawiki-db:
image: mariadb:11
container_name: mediawiki-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: mw-rootpass
MARIADB_DATABASE: mediawiki
MARIADB_USER: mediawiki
MARIADB_PASSWORD: mediawikipass
MARIADB_AUTO_UPGRADE: "1"
volumes:
- mediawiki_db:/var/lib/mysql
networks:
- mediawiki-back
mediawiki:
image: mediawiki:1.43
container_name: mediawiki
restart: unless-stopped
depends_on:
- mediawiki-db
volumes:
- mediawiki_data:/var/www/html/images
# LocalSettings.php nach dem Setup einhaengen:
# - ./LocalSettings.php:/var/www/html/LocalSettings.php:ro
networks:
- proxy
- mediawiki-back
labels:
- "traefik.enable=true"
- "traefik.http.routers.mediawiki.rule=Host(`wiki.it2XX.xinmen.de.int`)"
- "traefik.http.routers.mediawiki.entrypoints=websecure"
- "traefik.http.routers.mediawiki.tls=true"
- "traefik.http.services.mediawiki.loadbalancer.server.port=80"
networks:
proxy:
nextcloud-back:
mediawiki-back:
volumes:
nextcloud_db:
nextcloud_data:
mediawiki_db:
mediawiki_data:
Erklärung der Bausteine
Traefik
- Docker-Provider mit Opt-in
exposedbydefault=falsesorgt dafür, dass nur Container mittraefik.enable=trueveröffentlicht werden. Alles andere bleibt unsichtbar.
- File-Provider für TLS
- Das statische Zertifikat wird nicht über Labels, sondern über eine Datei eingebunden (siehe
tls.yml).watch=truelädt Änderungen ohne Neustart.
- HTTP→HTTPS-Redirect global
- Die beiden
redirections-Zeilen leiten den gesamten Port-80-Verkehr auf HTTPS um. Das muss kein Container selbst regeln.
- Docker-Socket read-only
- Traefik liest die Container-Labels über den Docker-Socket. Der wird read-only gemountet.
Datenbanken
- Anlage über Umgebungsvariablen
- Jeder MariaDB-Container legt Datenbank und Benutzer beim ersten Start selbst an, gesteuert über
MARIADB_DATABASE,MARIADB_USERundMARIADB_PASSWORD. Ein separates Init-Skript ist nicht nötig.
- Getrennte Volumes
nextcloud_dbundmediawiki_dbsind voneinander unabhängige Volumes. Jede DB hat ihren eigenen Datenbestand.
Traefik Dynamic Config (tls.yml)
Pfad im Container: /etc/traefik/dynamic/tls.yml
tls:
certificates:
- certFile: /etc/ssl/own.crt
keyFile: /etc/ssl/own.key
stores:
default:
defaultCertificate:
certFile: /etc/ssl/own.crt
keyFile: /etc/ssl/own.key
- Default-Zertifikat
- Durch das
default-Store reicht an jedem Router ein einfachestls=true. Traefik greift automatisch auf dieses Zertifikat zurück, ein eigener Cert-Verweis pro Router entfällt.
Inbetriebnahme
- Zertifikat ablegen
- Das Wildcard-Zertifikat zur Domain mit dem vorhandenen Skript ziehen, sodass
/etc/ssl/own.crtund/etc/ssl/own.keyvorhanden sind. ./get-cert.sh
- Stack starten
docker compose up -d
- Status prüfen
docker compose ps
- Logs verfolgen
docker compose logs -f traefik
DNS
Die beiden Hostnamen müssen auf den Docker-Host zeigen:
- Nextcloud
cloud.it2XX.xinmen.de.int
- MediaWiki
wiki.it2XX.xinmen.de.int
MediaWiki-Setup abschließen
- Erstaufruf im Browser
- MediaWiki startet ohne
LocalSettings.phpmit dem Web-Installer. Als Datenbank-Hostmediawiki-db, Datenbankmediawiki, Benutzermediawikiangeben.
- LocalSettings.php einhängen
- Nach dem Setup wird die generierte
LocalSettings.phpheruntergeladen, neben das Compose-File gelegt und der auskommentierte Volume-Mount immediawiki-Service aktiviert. Danach Container neu starten. docker compose up -d mediawiki