Caddy: automatisches HTTPS als schlanke Reverse-Proxy-Alternative
Minimaler Caddy-Stack mit Docker Compose: zwei Services hinter einer Domain, TLS vollautomatisch – inklusive lokalem Testen und typischer Stolperfallen.
Wer einen Reverse Proxy nur dafür braucht, ein paar Container hinter eine Domain mit gültigem HTTPS zu hängen, dem ist nginx schnell zu umständlich und Traefik mit seinen Labels schon fast wieder zu viel. Caddy zielt genau auf diese Lücke: Die Konfiguration ist eine winzige Textdatei, und HTTPS ist nicht eine Option, sondern der Standard – Zertifikate holt sich Caddy von Let's Encrypt von selbst. Dieser Beitrag zeigt einen lauffähigen Minimal-Stack mit Caddy 2 und Docker Compose, der zwei Services bedient, in unter 15 Minuten.
Was Caddy macht – und wann es passt
Caddy ist ein Webserver und Reverse Proxy, dessen herausragendes Merkmal Automatic HTTPS ist: Sobald Sie eine Domain als Adresse angeben, besorgt Caddy beim ersten Start ein Zertifikat, erneuert es rechtzeitig und leitet HTTP automatisch auf HTTPS um – ganz ohne zusätzliche Konfiguration. Das passt überall dort, wo Sie wenige Services schnell und sicher veröffentlichen wollen und keine Lust auf Zertifikats-Handarbeit oder umfangreiche Proxy-Konfiguration haben.
Konfiguriert wird Caddy über das Caddyfile – ein bewusst minimalistisches Format. Pro veröffentlichtem Dienst schreiben Sie einen Block aus Site-Adresse und einer Direktive. Für einen Reverse Proxy ist das genau eine Zeile: reverse_proxy. Mehr braucht der Normalfall nicht.
Der Datenfluss sieht so aus:
+--------------------+
Internet --:443>| Caddy |
(HTTPS) | Automatic HTTPS + |
| HTTP -> HTTPS |
+---------+----------+
|
+----------------+----------------+
| |
app.example.com api.example.com
| |
[ app ] [ api ]
:80 :80
Der minimale Stack
Wir brauchen zwei Dateien: ein docker-compose.yml und ein Caddyfile. Legen Sie das Caddyfile in einen Unterordner caddy/, der als Ganzes nach /etc/caddy gemountet wird (warum nicht die Datei direkt, steht weiter unten bei den Stolperfallen).
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./caddy:/etc/caddy
- caddy_data:/data
- caddy_config:/config
networks:
- web
app:
image: traefik/whoami
networks: [web]
api:
image: traefik/whoami
networks: [web]
networks:
web:
volumes:
caddy_data:
caddy_config:
Das zugehörige caddy/Caddyfile:
{
email admin@example.com
}
app.example.com {
reverse_proxy app:80
}
api.example.com {
reverse_proxy api:80
}
Das ist der komplette Stack. Der oberste Block mit den geschweiften Klammern ohne Namen sind die globalen Optionen; er muss als Erstes im Caddyfile stehen. Das email darin hinterlegt die Adresse für Ihr ACME-Konto bei Let's Encrypt – nützlich für Ablaufwarnungen. Darunter steht pro Service ein Block: die öffentliche Adresse, und reverse_proxy <ziel>:<port> leitet an den Container weiter. app und api sind die Service-Namen aus Compose; im gemeinsamen Netz web löst Docker sie als Hostnamen auf. Der Port 80 ist der Port, auf dem whoami im Container lauscht.
Starten
docker compose up -d
Sobald die DNS-A-Records von app.example.com und api.example.com auf den Host zeigen und die Ports 80 und 443 von außen erreichbar sind, beantragt Caddy beim ersten Aufruf die Zertifikate. Ein Aufruf von https://app.example.com liefert die whoami-Ausgabe mit gültigem HTTPS, ohne dass Sie eine einzige Zertifikatszeile geschrieben haben. Die ausgestellten Zertifikate liegen im Volume caddy_data unter /data – dieses Verzeichnis ist kein Cache und muss erhalten bleiben, sonst beantragt Caddy nach jedem Neustart neu und läuft in die Rate-Limits.
Lokal testen ohne öffentliche Domain
Für öffentliche Zertifikate muss die Domain real auf den Host zeigen. Zum Testen auf dem eigenen Rechner gibt es zwei einfache Wege. Verwenden Sie eine .localhost-Adresse – dafür stellt Caddy automatisch ein lokal vertrauenswürdiges Zertifikat aus:
app.localhost {
reverse_proxy app:80
}
Oder Sie zwingen Caddy für eine beliebige interne Domain auf seine eingebaute CA mit der Direktive tls internal:
app.intern.example.com {
tls internal
reverse_proxy app:80
}
So testen Sie den kompletten HTTPS-Pfad, ohne Let's Encrypt zu kontaktieren.
Drei typische Stolperfallen
1. Das Caddyfile als Verzeichnis mounten, nicht als Datei. Mounten Sie den Ordner (./caddy:/etc/caddy), nicht die Datei direkt nach /etc/caddy/Caddyfile. Beim Bearbeiten ändert sich sonst der Inode der Datei, und der unterbrechungsfreie Reload bekommt die Änderung nicht mit. Das ist die offizielle Empfehlung aus den Caddy-Docs.
2. /data muss persistent sein. Geht das Volume caddy_data verloren, verliert Caddy alle Zertifikate und Konto-Schlüssel und beantragt alles neu. Bei häufigen Neustarts laufen Sie so in die Rate-Limits von Let's Encrypt. Behandeln Sie /data wie Daten, nicht wie einen Cache.
3. HTTP/3 braucht 443/udp. Caddy bietet HTTP/3 standardmäßig an, dafür muss der UDP-Port 443 freigegeben sein – deshalb steht "443:443/udp" zusätzlich zu "443:443" in der Compose-Datei. Fehlt es, funktioniert zwar HTTPS über TCP, aber HTTP/3 stillschweigend nicht.
Wie es weitergeht
Damit steht ein schlanker Reverse Proxy mit automatischem HTTPS. Bevor Sie Änderungen ausrollen, prüfen Sie sie mit caddy validate und formatieren Sie das Caddyfile mit caddy fmt; eine laufende Instanz übernimmt neue Konfiguration unterbrechungsfrei mit caddy reload. Tiefer geht es in der Caddyfile-Dokumentation, bei der reverse_proxy-Direktive und unter Automatic HTTPS. Das offizielle Docker-Image samt Compose-Beispiel ist auf Docker Hub und unter Running Caddy dokumentiert.
Hinweis: Die Beiträge dieses Blogs werden unter Einsatz von KI erstellt und vor der Veröffentlichung redaktionell geprüft. Die redaktionelle Verantwortung trägt Emre Yurtbay (siehe Impressum).