Autonomer Docker-Compose-Heimserver mit Traefik, SSL und Watchtower
Teil 4 von 4 der Reihe Homelab auf dem Raspberry Pi

Inhalt
Architektur-Überblick: Autonomen Heimserver auf Raspberry Pi konzipieren
Der Betrieb eines selbstgehosteten Home-Labs auf einem Raspberry Pi erfordert eine ausfallsichere, wartungsarme Administrationsarchitektur. Die Bereitstellung interner Docker-Container im lokalen Netz oder im öffentlichen Internet ohne zentrale SSL/TLS-Terminierung erhöht die administrative Komplexität und birgt erhebliche Sicherheitsrisiken. Manuelle Zertifikatsverlängerungen, statische Reverse-Proxy-Konfigurationen und händische Container-Updates führen unweigerlich zu Ausfallzeiten und abgelaufenen kryptografischen Zertifikaten.
Eine autonome Heimserver-Architektur kombiniert drei Kerntechnologien in einem deklarativen Docker-Compose-Stack: Traefik v3 fungiert als dynamischer Edge-Router, der den Docker-Socket überwacht und eingehende HTTP-/HTTPS-Anfragen basierend auf Container-Labels weiterleitet. Die Integration von Let’s Encrypt ACME automatisiert die Erstellung und Erneuerung von SSL-Zertifikaten über HTTP-01- oder DNS-01-Challenges; und Watchtower übernimmt das kontinuierliche Lifecycle-Management, indem konfigurierte Container-Registries zyklisch geprüft und veraltete Container-Images ohne manuelles Eingreifen sauber aktualisiert werden.

Schritt-für-Schritt-Implementierungsanleitung
Schritt 1: Systemvorbereitung und Dateisystem-Hierarchie
Um eine persistente Datenspeicherung und eine saubere Struktur auf dem Raspberry-Pi-Host zu gewährleisten, muss ein standardisierter Verzeichnisbaum unter /opt/containers/ aufgebaut werden:
mkdir -p /opt/containers/traefik/data
mkdir -p /opt/containers/watchtower
touch /opt/containers/traefik/data/acme.json
chmod 600 /opt/containers/traefik/data/acme.json
Kritischer Sicherheitshinweis: Die Datei acme.json, in der die privaten kryptografischen Let’s-Encrypt-Schlüssel gespeichert werden, muss auf die Dateirechte 600 beschränkt sein. Traefik verweigert den Start bei zu weit gefassten Lese-/Schreibberechtigungen.
Schritt 2: Aufbau des dynamischen Traefik-v3-Edge-Routers
Die Routing-Infrastruktur wird in einer docker-compose.yml unter /opt/containers/traefik/ definiert. Diese Konfiguration legt Entrypoints für Port 80 (HTTP) mit obligatorischen Weiterleitungen auf Port 443 (HTTPS) fest, aktiviert automatisierte Let’s-Encrypt-HTTP-01-Challenges und bindet den Docker-Unix-Socket schreibgeschützt ein:
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- "80:80"
- "443:443"
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=proxy"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=admin@lukaswojcik.com"
- "--certificatesresolvers.myresolver.acme.storage=/data/acme.json"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "/opt/containers/traefik/data:/data"
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`proxy.lukaswojcik.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=myresolver"
- "traefik.http.routers.dashboard.middlewares=dashboard-ip"
- "traefik.http.middlewares.dashboard-ip.ipallowlist.sourcerange=192.168.0.0/16, 10.0.0.0/8"
networks:
proxy:
external: true
Schritt 3: Erstellung des externen Docker-Proxy-Netzwerks
Vor der Ausführung des Compose-Stacks muss ein isoliertes Bridge-Netzwerk im Host-System initialisiert werden, damit Traefik sicher mit nachgelagerten Anwendungscontainern kommunizieren kann:
docker network create proxy
Schritt 4: Integration von Watchtower für automatisiertes Lifecycle-Management
Um manuellen Wartungsaufwand bei Container-Updates zu eliminieren, wird Watchtower als autonomer Hintergrunddienst integriert. Da das ursprüngliche Repository containrrr/watchtower am 17. Dezember 2025 archiviert wurde und keine Fehlerkorrekturen oder Sicherheitsupdates mehr erhält, kommt hier der aktiv gepflegte Fork nickfedor/watchtower zum Einsatz, der ohne Konfigurationsänderung an dessen Stelle tritt. Das Tool prüft konfigurierte Registries alle 24 Stunden (86400 Sekunden), lädt neue Images passend zu den aktuellen Tags herunter, beendet veraltete Container-Instanzen kontrolliert und bereinigt ungenutzte Images automatisch:
services:
watchtower:
image: nickfedor/watchtower:latest
container_name: watchtower
restart: unless-stopped
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_POLL_INTERVAL=86400
- WATCHTOWER_INCLUDE_RESTARTING=true
- WATCHTOWER_ROLLING_RESTART=true
Schritt 5: Bereitstellung eines gesicherten Microservices via Labels
Um eine selbstgehostete Anwendung ohne Anpassung zentraler Proxy-Konfigurationsdateien an den Traefik-Edge-Router anzubinden, werden dynamische Traefik-Routing-Labels direkt in der Compose-Definition des Zielsystems deklariert:
services:
whoami:
image: traefik/whoami:latest
container_name: whoami
restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.lukaswojcik.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=myresolver"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
proxy:
external: true
Schritt 6: Qualitätssicherung und System-Audit
Nach dem Starten der Dienste mit docker compose up -d muss die Infrastruktur systematisch validiert werden:
- Verifikation der Zertifikatsausstellung: Prüfung der Container-Logs über
docker logs -f traefikzur Bestätigung erfolgreicher Let’s-Encrypt-ACME-Challenges und Verifikation, dass die Dateiacme.jsonmit gültigen RSA-/ECDSA-Zertifikaten gefüllt ist. - Audit der automatischen Weiterleitung: Ausführung einer reinen HTTP-cURL-Abfrage auf die Domain (
curl -I http://whoami.lukaswojcik.com) zur Bestätigung eines sofortigen308 Permanent Redirect– oder301 Moved Permanently-Headers auf HTTPS. - Simulation eines Update-Triggers: Durchführung eines einmaligen, nicht eingreifenden Watchtower-Laufs via
docker exec -it watchtower /watchtower --run-once --monitor-onlyzur Prüfung, ob die Zugriffsberechtigungen auf den Docker-Socket korrekt arbeiten.--no-pulleignet sich dafür nicht: Es unterbindet lediglich das Herunterladen neuer Images, während ein lokal bereits vorhandenes neueres Image weiterhin zum Stoppen und Neuerstellen des Containers führt.
Zusammenfassung und resultierender Mehrwert
Was sich damit erreichen lässt: Der vollständige Verzicht auf manuelles Reverse-Proxy-Routing, fehleranfällige SSL-Skript-Cronjobs und manuelle Container-Updates zugunsten einer autonomen, deklarativen Docker-Compose-Infrastruktur mit Traefik v3 und Watchtower.
Resultierender Mehrwert:
- Automatisierte SSL-/TLS-Wartung: Kryptografische Zertifikate werden von Let’s Encrypt automatisch angefordert, konfiguriert und erneuert, was Browser-Warnungen und Systemausfälle verhindert.
- Dynamische Service-Erkennung: Neue Heimserver-Anwendungen werden durch Hinzufügen von Docker-Labels sofort weitergeleitet und verschlüsselt, was manuelle Nginx-/Apache-Konfigurationsänderungen und Server-Reloads überflüssig macht.
- Kontinuierliche Sicherheits-Updates: Sicherheitspatches und Applikations-Aktualisierungen werden innerhalb von 24 Stunden nach Upstream-Release automatisch eingespielt, was den Raspberry Pi effektiv gegen bekannte Schwachstellen härtet. Diese Zusage trägt nur, solange das Update-Werkzeug selbst gepflegt wird; deshalb tritt der aktiv entwickelte Fork
nickfedor/watchtoweran die Stelle des archivierten Originals.
Fragen und Antworten
Macht das :ro am Docker-Socket den Zugriff von Traefik harmlos?
Nein. Das :ro verhindert nur, dass der Container die Socket-Datei selbst verändert. Über den Socket spricht Traefik aber mit der Docker-API, und die unterscheidet nicht zwischen lesenden und schreibenden Aufrufen, nur weil die Datei schreibgeschützt eingebunden ist. Wer den Socket erreicht, kann darüber Container starten, auch solche mit eingebundenem Wurzelverzeichnis des Hosts, und hat damit faktisch Root-Rechte auf dem Raspberry Pi.
Das Risiko liegt deshalb in der Angriffsfläche von Traefik: Es ist der einzige Dienst, der Verbindungen direkt aus dem Internet annimmt. Eine Lücke in Traefik würde nicht am Container enden. Watchtower braucht den Socket ohnehin schreibend, um Container zu ersetzen, nimmt aber keine Verbindungen von außen an.
Abhilfe schafft ein Socket-Proxy: ein kleiner Container, der den Socket hält und nur die lesenden Endpunkte der API weiterreicht, die Traefik für die Erkennung der Container braucht. Traefik bekommt dann statt des Sockets die Netzadresse dieses Proxys, und der Docker-Provider lässt sich über seinen Parameter endpoint darauf richten.
Welche Updates spielt Watchtower ein, und wie lassen sich Sprünge auf eine neue Hauptversion vermeiden?
Watchtower folgt dem Tag, mit dem ein Image eingetragen ist, nicht einer Versionsnummer. Ein Container auf latest bekommt deshalb auch den Sprung auf eine neue Hauptversion, sobald diese unter latest erscheint, samt geänderter Konfiguration oder Datenformate. Ein Rückweg ist nicht vorgesehen: Nach dem Aufräumen mit WATCHTOWER_CLEANUP=true liegt das alte Image nicht einmal mehr auf der Platte.
Der Aufbau im Artikel zeigt schon die Gegenmaßnahme: Traefik steht auf traefik:v3.1 und bekommt so nur neue Images unter diesem Tag, also Korrekturen innerhalb von 3.1, aber keinen Sprung auf eine andere Version. Dasselbe lohnt sich für jeden Dienst mit eigener Datenhaltung, etwa eine Datenbank. Bei den Diensten auf latest, im Artikel whoami und Watchtower selbst, ist das Risiko geringer, weil sie keine Daten halten.
Ist das Traefik-Dashboard unter proxy.lukaswojcik.com geschützt?
Ja, auf das Heimnetz beschränkt: Der Router für das Dashboard hat neben TLS die Middleware dashboard-ip, eine IP-Freigabeliste (ipAllowList), die nur Adressen aus 192.168.0.0/16 und 10.0.0.0/8 durchlässt. Ohne sie sähe jeder, der den Hostnamen kennt, alle Router, Dienste und Hostnamen des Heimservers. Soll das Dashboard auch von unterwegs erreichbar sein, kommt eine Middleware für Basic Auth hinzu.
Funktioniert die HTTP-01-Challenge an jedem Heimanschluss?
Nur, wenn Let’s Encrypt den Raspberry Pi aus dem Internet auf Port 80 erreicht: Der Hostname muss öffentlich auf den Anschluss zeigen, und der Router muss Port 80 an den Pi weiterleiten. An Anschlüssen ohne eigene öffentliche IPv4-Adresse, etwa hinter Carrier-Grade-NAT oder DS-Lite, scheitert das über IPv4; es klappt dann nur, wenn der Hostname einen AAAA-Eintrag hat und der Pi über IPv6 erreichbar ist. Dieselbe Grenze gilt für Dienste, die nur im Heimnetz erreichbar sein sollen.
Für diese Fälle ist die im Artikel genannte DNS-01-Challenge gedacht. Sie belegt die Kontrolle über die Domain mit einem TXT-Eintrag im DNS, braucht keinen offenen Port und erlaubt auch Wildcard-Zertifikate. Dafür braucht Traefik Zugangsdaten für die API des DNS-Anbieters, und diese Zugangsdaten sind dann ebenso schutzbedürftig wie die acme.json.
Homelab auf dem Raspberry Pi
- Raspberry Pi 4 und 5: Vom SSD-Laufwerk booten über den Bootloader
- Unterbrechungsfreie Stromversorgung (USV) für Raspberry Pi 4 und 5: Die Top 5 Lösungen für anspruchsvolle Setups
- Lokales CI/CD für den Raspberry Pi: Automatisierung von Docker-Compose-Deployments
- Autonomer Docker-Compose-Heimserver mit Traefik, SSL und Watchtower