Traefik als Docker-Reverse-Proxy mit automatischem HTTPS
So richten Sie Traefik per Docker Compose als Reverse-Proxy mit automatischem Let's-Encrypt-HTTPS ein: compose.yaml, Auto-Discovery über Container-Labels, ACME per HTTP-01 und DNS-01, abgesichertes Dashboard sowie Update und Backup.
Geprüft am 29.09.2026 · für traefik 3.7
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Traefik liest sein Routing direkt aus Docker-Labels und holt per Let's Encrypt automatisch TLS-Zertifikate. Diese Anleitung zeigt Einrichtung per Docker Compose, abgesichertes Dashboard, eigene Dienste per Labels sowie Update und Backup.
Voraussetzungen
- Linux-Server: Debian 12/13 oder Ubuntu 24.04 mit öffentlicher IP, x86-64 oder ARM64. 1 bis 2 CPU-Kerne und 1 GB RAM reichen für Traefik allein; für die Dienste dahinter sind 2 Kerne und 4 GB RAM ein guter Ausgangspunkt.
- Docker & Docker Compose: aktuelle Docker Engine mit Compose-Plugin (
docker compose). - RAM & Storage: rund
50–100 MBRAM im Leerlauf, Plattenplatz nur für dieacme.json(wenige Kilobyte). - Keine GPU nötig: Traefik läuft rein auf der CPU.
- Domain & DNS: eigene Domain (z. B.
IHRE-DOMAIN.de) mit A-/AAAA-Records auf die Server-IP; für HTTP-01 Ports80und443von außen erreichbar. - Hinter CGNAT/ohne offene Ports: DNS-01-Challenge statt HTTP-01 (Schritt 6); sie ist auch die einzige Option für Wildcard-Zertifikate.
Schritt 1: Wie Traefik arbeitet – statische vs. dynamische Konfiguration
Traefik trennt zwei Arten von Konfiguration:
- Statische Konfiguration – steht beim Start fest: Entrypoints (Ports 80/443), Provider, ACME-Resolver. Hier im
command-Block der compose.yaml (alternativtraefik.ymloder Env-Vars). - Dynamische Konfiguration – das Routing (welcher Host auf welchen Container zeigt). Traefik liest es per Docker-Provider live aus den Labels; neue Dienste brauchen keinen Traefik-Neustart.
Beim manuellen nginx-Reverse-Proxy mit TLS pflegen Sie dagegen Vhost-Dateien von Hand und erneuern Zertifikate über certbot.
Verifizieren: Sie können für Ihr Vorhaben zuordnen, was statisch in die compose.yaml gehört (Ports, Provider, ACME) und was per Label am jeweiligen Dienst steht (Host-Regel, Zertifikat).
Schritt 2: Projektverzeichnis anlegen und acme.json vorbereiten
Im Stack-Verzeichnis liegen die compose.yaml und der Ordner letsencrypt. Die acme.json muss vor dem ersten Start existieren und die Rechte 600 haben, sonst verweigert Traefik das Laden.
sudo mkdir -p /srv/traefik
cd /srv/traefik
# acme.json korrekt anlegen (sonst Fehler wegen zu offener Rechte)
mkdir -p ./letsencrypt && touch ./letsencrypt/acme.json && chmod 600 ./letsencrypt/acme.json
Die acme.json enthält die privaten Schlüssel Ihrer Zertifikate: niemals in ein Git-Repository committen und off-site sichern (Schritt 9).
Verifizieren: ls -l ./letsencrypt/acme.json zeigt eine leere Datei mit den Rechten -rw-------.
Schritt 3: Die vollständige compose.yaml anlegen
Die compose.yaml für den Produktivbetrieb: Entrypoints web (:80) und websecure (:443), globaler HTTP→HTTPS-Redirect, ACME-Resolver per HTTP-01-Challenge, abgesichertes Dashboard und traefik/whoami als Beispieldienst. Passen Sie email, Host-Regeln und BasicAuth-Hash an.
services:
traefik:
image: traefik:v3.7 # Minor pinnen statt :latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
command:
# --- Dashboard / API ---
- "--api.dashboard=true"
- "--api.insecure=false" # KEIN ungeschuetztes :8080 in Produktion
# --- Docker-Provider (Auto-Discovery) ---
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" # nur Container mit traefik.enable=true
- "--providers.docker.network=proxy"
# --- Entrypoints ---
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# --- globaler HTTP->HTTPS Redirect ---
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
# --- ACME / Let's Encrypt (HTTP-01) ---
- "--certificatesresolvers.le.acme.email=admin@IHRE-DOMAIN.de"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
# Zum Testen entkommentieren (Staging, verbraucht kein Rate-Limit):
# - "--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # IMMER read-only
- ./letsencrypt:/letsencrypt
networks:
- proxy
labels:
# --- Dashboard ueber Router absichern (TLS + BasicAuth) ---
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.IHRE-DOMAIN.de`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=le"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
# $$ = escaptes $ (Pflicht in docker-compose!), Hash via htpasswd -nB
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xxxx$$yyyy"
whoami:
image: traefik/whoami
container_name: whoami
restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.IHRE-DOMAIN.de`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=le"
# optional, wenn der Container-Port abweicht:
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
proxy:
name: proxy
Traefik und alle Zieldienste müssen im selben Docker-Netzwerk liegen (hier proxy), sonst folgt gateway timeout. --providers.docker.network=proxy legt fest, über welches Netzwerk Traefik die Container anspricht.
Den BasicAuth-Hash für das Dashboard erzeugen
Ersetzen Sie den Platzhalter admin:$$apr1$$xxxx$$yyyy durch einen echten Hash aus htpasswd (BCrypt empfohlen). In der compose.yaml muss jedes Dollarzeichen verdoppelt sein ($$), sonst wertet Compose es als Variable. Der Befehl verdoppelt gleich mit:
# BasicAuth-Hash (BCrypt) mit korrekt verdoppelten $ fuer docker-compose:
echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g
Die Ausgabe (z. B. admin:$$2y$$05$$...) tragen Sie hinter basicauth.users= ein. Über eine externe .env-Datei oder Ansible gesetzt, dürfen die Dollarzeichen nicht verdoppelt werden.
Verifizieren: docker compose config läuft ohne Fehler durch und zeigt beim Label basicauth.users den Hash mit einfachen Dollarzeichen (Compose hat $$ zu $ aufgelöst).
Schritt 4: Stack starten und Zertifikate prüfen
Starten Sie den Stack und kontrollieren Sie die Logs. Die DNS-Records für traefik.IHRE-DOMAIN.de und whoami.IHRE-DOMAIN.de müssen bereits auf den Server zeigen, sonst scheitert die HTTP-01-Challenge.
# Stack starten
docker compose up -d
# Status pruefen
docker compose ps
# Logs verfolgen (mit Strg+C beenden)
docker compose logs -f traefik
Beim ersten Aufruf fordert Traefik das Zertifikat an und speichert es in der acme.json. Testen Sie https://whoami.IHRE-DOMAIN.de; das Dashboard liegt unter https://traefik.IHRE-DOMAIN.de.
Tipp: Testen Sie zuerst mit dem Staging-caServer (in der compose.yaml entkommentieren), denn Let's Encrypt hat strenge Rate-Limits. Danach Staging-Zeile auskommentieren,
acme.jsonneu anlegen (chmod 600) und neu starten, sonst bleiben die ungültigen Staging-Zertifikate gespeichert.
Verifizieren: docker compose ps zeigt traefik und whoami als running. curl -I https://whoami.IHRE-DOMAIN.de antwortet mit HTTP/2 200 ohne Zertifikatsfehler, curl -I http://whoami.IHRE-DOMAIN.de mit einer Weiterleitung (301/308) auf HTTPS, und das Dashboard fragt nach den BasicAuth-Zugangsdaten.
Schritt 5: Einen eigenen Dienst per Labels veröffentlichen
Einen neuen Dienst veröffentlichen Sie nur über Labels, ohne Eingriff in die Traefik-Konfiguration. Hängen Sie ihn ans proxy-Netzwerk und ersetzen Sie app durch einen eindeutigen Router-/Service-Namen und app.IHRE-DOMAIN.de durch Ihre Subdomain:
meine-app:
image: nginx:stable
container_name: meine-app
restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.IHRE-DOMAIN.de`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=le"
# Pflicht, wenn der Container mehrere oder abweichende Ports exponiert:
- "traefik.http.services.app.loadbalancer.server.port=80"
Nach docker compose up -d erkennt Traefik den Container, fordert das Zertifikat an und routet https://app.IHRE-DOMAIN.de dorthin. Die zentralen Labels:
| Label | Funktion |
|---|---|
traefik.enable=true | Macht den Container für Traefik sichtbar (Pflicht bei exposedbydefault=false). |
...routers.NAME.rule=Host(`...`) | Welche Domain auf diesen Dienst zeigt. Backticks beachten (v3-Syntax). |
...routers.NAME.entrypoints=websecure | Lauscht auf Port 443 (HTTPS). |
...routers.NAME.tls.certresolver=le | Verknüpft mit dem ACME-Resolver – löst die automatische Zertifikatsausstellung aus. |
Middleware: HTTPS-Redirect und BasicAuth
Der HTTP→HTTPS-Redirect am Entrypoint (Schritt 3) gilt für alle Dienste. Für zusätzliche BasicAuth an einem einzelnen Dienst definieren und referenzieren Sie eine Middleware per Labels:
- "traefik.http.routers.app.middlewares=app-auth"
- "traefik.http.middlewares.app-auth.basicauth.users=admin:$$apr1$$xxxx$$yyyy"
Verifizieren: Das Dashboard listet unter HTTP Routers den neuen Router app@docker ohne Fehlermarkierung, und curl -I https://app.IHRE-DOMAIN.de liefert 200 (mit Middleware ohne Zugangsdaten 401).
Schritt 6: DNS-01-Challenge für Wildcard-Zertifikate (optional)
HTTP-01 verlangt öffentliche Erreichbarkeit auf Port 80. Hinter CGNAT, in abgeschotteten Netzen oder für ein Wildcard-Zertifikat (*.IHRE-DOMAIN.de) nutzen Sie die DNS-01-Challenge: Traefik legt kurzzeitig einen TXT-Record per DNS-Provider-API an. Beispiel mit Cloudflare:
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.email=admin@IHRE-DOMAIN.de"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.dnschallenge.provider=cloudflare"
environment:
- CF_DNS_API_TOKEN=IHR-SCOPED-CLOUDFLARE-TOKEN
Den Scoped API Token erstellen Sie im Cloudflare-Dashboard mit Schreibrechten auf die DNS-Zone (alternativ CF_API_EMAIL + CF_API_KEY). Mit dem Suffix _FILE lesen alle Varianten Docker-Secrets, etwa CF_DNS_API_TOKEN_FILE=/run/secrets/cf_token; so steht das Token nicht im Klartext in der compose.yaml.
Für ein Wildcard-Zertifikat setzen Sie die Domains direkt am Router:
- "traefik.http.routers.app.tls.domains[0].main=IHRE-DOMAIN.de"
- "traefik.http.routers.app.tls.domains[0].sans=*.IHRE-DOMAIN.de"
Verifizieren: In docker compose logs traefik taucht keine ACME-Fehlermeldung zur DNS-Challenge auf, und openssl s_client -connect app.IHRE-DOMAIN.de:443 -servername app.IHRE-DOMAIN.de </dev/null | openssl x509 -noout -ext subjectAltName zeigt *.IHRE-DOMAIN.de.
Schritt 7: Sicherheit – Dashboard, Socket und Defaults
Ein Reverse-Proxy ist exponiert. Diese vier Punkte sind Pflicht:
- Dashboard nie ungeschützt:
--api.insecure=trueöffnet es ohne Authentifizierung auf Port 8080 (nur für lokale Tests). In Produktion wie in Schritt 3 über einen Router aufservice=api@internalmit TLS und BasicAuth. - Docker-Socket read-only: immer
:ro. Schon Lesezugriff gibt tiefen Einblick; Schreibzugriff ist faktisch Host-Root. Für höhere Anforderungen einen Socket-Proxy vorschalten. - exposedbydefault=false: sonst routet Traefik alle Container; so braucht jeder Dienst bewusst
traefik.enable=true. - no-new-privileges & restart:
security_opt: no-new-privileges:trueundrestart: unless-stopped(Defaults der offiziellen Beispiele).
Verifizieren: docker inspect traefik --format '{{range .Mounts}}{{.Source}} rw={{.RW}} {{end}}' zeigt für /var/run/docker.sock den Wert rw=false, und curl -I http://SERVER-IP:8080 bekommt keine Antwort.
Schritt 8: Abgrenzung – Traefik vs. manueller nginx-Reverse-Proxy
Beide Ansätze haben ihre Berechtigung:
| Aspekt | Traefik (Auto-Discovery) | nginx + certbot (manuell) |
|---|---|---|
| Neuer Dienst | nur Labels setzen, kein Neustart | Vhost-Datei schreiben + reload |
| Zertifikate | vollautomatisch per ACME-Resolver | certbot manuell/per Cron |
| Konfiguration | aus Container-Labels (dynamisch) | statische Konfigdateien |
| Ideal für | viele wechselnde Docker-Dienste | wenige, statische Backends / Nicht-Docker |
Traefik lohnt sich bei vielen, oft wechselnden Containern. Bei ein, zwei statischen Backends oder Diensten außerhalb von Docker ist der manuelle nginx-Reverse-Proxy mit Let's Encrypt per certbot oft übersichtlicher. Grundlagen: Docker-Compose-Grundlagen.
Verifizieren: Sie haben entschieden, welcher Ansatz zu Ihren Diensten passt. Laufen Traefik und nginx parallel, belegt nur einer von beiden die Ports 80 und 443 (ss -tlnp | grep -E ':80 |:443 ').
Schritt 9: Update- und Backup-Workflow
Update: neues Image ziehen, Container neu erstellen; Config und Volumes bleiben erhalten.
# Update einspielen
docker compose pull # neues Image (Tag z. B. traefik:v3.7) ziehen
docker compose up -d # Container neu erstellen, acme.json bleibt erhalten
docker image prune -f # alte, ungenutzte Images aufraeumen
Pinnen Sie den Tag auf eine Minor-Version (traefik:v3.7) statt :latest. v2 auf v3 brachte Breaking Changes (z. B. Rule-Syntax), auch ein unkontrollierter Minor-Wechsel kann Konfigs brechen; alte v2-Tutorials sind nicht 1:1 übertragbar.
Sichern Sie vor allem die acme.json (Zertifikate und private Schlüssel) zusammen mit der compose.yaml off-site.
# Backup: nur acme.json + Compose-/Config-Dateien sichern
mkdir -p ./backup
cp -p ./letsencrypt/acme.json ./backup/acme.json.$(date +%F)
Verifizieren: Nach dem Update zeigt docker compose exec traefik traefik version die erwartete Version, die Dienste antworten weiter per HTTPS, und im Ordner ./backup liegt die Kopie der acme.json mit Rechten 600.
Troubleshooting
- Zertifikat wird nicht ausgestellt: HTTP-01/TLS-ALPN-01 brauchen öffentliche Ports 80 bzw. 443 und einen A/AAAA-Record auf den Host. Sonst DNS-01 (Schritt 6).
- Traefik lädt acme.json nicht: Rechte müssen
600sein:touch ./letsencrypt/acme.json && chmod 600 ./letsencrypt/acme.json. - Login am Dashboard schlägt fehl:
$im Hash nicht als$$verdoppelt (nur in der compose.yaml, nicht in.env/Ansible). - gateway timeout / Dienst nicht erreichbar: Container nicht im
proxy-Netzwerk. Bei mehreren exponierten Portsloadbalancer.server.portexplizit setzen. - Dienst wird gar nicht geroutet: bei
exposedbydefault=falsefehlttraefik.enable=trueam Container. - Rate-Limit von Let's Encrypt erreicht: zuerst mit dem Staging-caServer testen, danach umstellen und die
acme.jsonneu anlegen.
Häufige Fragen
Brauche ich für Traefik eine GPU?
Nein. Traefik läuft rein auf der CPU mit rund 50–100 MB RAM im Leerlauf.
Was ist der Unterschied zwischen statischer und dynamischer Konfiguration?
Statisch (Entrypoints, Provider, ACME) steht beim Start fest und kommt aus command oder traefik.yml. Dynamisch ist das Routing aus den Container-Labels; geänderte Labels übernimmt Traefik ohne eigenen Neustart.
Warum muss der Docker-Socket read-only gemountet werden?
Schreibzugriff auf den Socket entspricht Root-Rechten auf dem Host. Mit :ro liest Traefik nur, was es zum Erkennen der Container braucht (siehe Schritt 7).
HTTP-01 oder DNS-01 – welche Challenge nehme ich?
HTTP-01, wenn Port 80 öffentlich erreichbar ist. DNS-01 hinter CGNAT, in abgeschotteten Netzen oder für Wildcards; sie braucht einen unterstützten DNS-Provider mit API-Token.
Wie sichere ich das Traefik-Dashboard ab?
Nie --api.insecure=true in Produktion, sondern Router auf service=api@internal mit TLS und BasicAuth wie in Schritt 3.
Lohnt sich Traefik oder reicht nginx?
Siehe Schritt 8: Traefik für viele wechselnde Docker-Dienste, nginx mit certbot für wenige statische Backends.
Fazit
Traefik mit Docker Compose liefert automatisches HTTPS, Dienste veröffentlichen Sie allein per Labels. Sicherheitskritisch: Dashboard nur über Router mit BasicAuth, Socket read-only, exposedbydefault=false. Dazu acme.json mit chmod 600, gepinnter Tag und Off-site-Sicherung.
Weiterführende Anleitungen und Quellen
- Docker Compose Grundlagen: Stacks sauber aufbauen
- nginx Reverse-Proxy mit TLS einrichten – der manuelle Gegenentwurf.
- Let's Encrypt mit certbot: TLS-Zertifikate
- Home Assistant per Docker einrichten – ein typischer Dienst hinter Traefik.
- Weitere Anleitungen in der Kategorie Docker.
Quellen: Traefik – Setup on Docker (offizielle Doku), Traefik – ACME / Let's Encrypt Certificate Resolver (v3), Traefik – Exposing Services with Docker und Traefik Releases (GitHub).


