TL;DR — Kurzzusammenfassung
Caddy als Reverse Proxy mit automatischem HTTPS. Caddyfile-Syntax, Load-Balancing-Richtlinien, Health Checks und Produktions-Caddyfile für mehrere Sites.
Caddy ist ein moderner Open-Source-Webserver, geschrieben in Go, dessen definierendes Merkmal automatisches HTTPS ist: Er provisoniert und erneuert TLS-Zertifikate von Let’s Encrypt oder ZeroSSL in dem Moment, in dem Sie eine Domain darauf zeigen — ganz ohne manuelle Certbot-Einrichtung. Als Reverse Proxy kombiniert Caddy dieses konfigurationsfreie TLS-Management mit einer sauberen deklarativen Syntax, integriertem Load Balancing, standardmäßig aktiviertem HTTP/2 und HTTP/3, und einem einzigen statisch kompilierten Binary ohne externe Abhängigkeiten. Diese Anleitung deckt alles ab, was Sie für den Betrieb von Caddy als Produktions-Reverse-Proxy benötigen: Installation, Caddyfile-Syntax, alle Load-Balancing-Richtlinien, aktive und passive Health Checks, Header-Manipulation, Authentifizierung, On-Demand-TLS, die Admin-API und eine vollständige Caddyfile für Multi-Site-Hosting.
Warum Caddy als Reverse Proxy wählen?
Hier ist ein direkter Vergleich der wichtigsten Reverse-Proxy-Optionen, die 2026 verfügbar sind:
| Funktion | Caddy | Nginx | Traefik | HAProxy | Apache |
|---|---|---|---|---|---|
| Automatisches HTTPS | Integrierter ACME-Client | Manuell (Certbot) | Integriert (via ACME) | Manuell | Manuell (mod_md) |
| Konfigurationsformat | Caddyfile (minimal) | nginx.conf (ausführlich) | YAML/TOML/Docker-Labels | haproxy.cfg | httpd.conf |
| HTTP/2 | Standardmäßig | Explizite Konfiguration | Standardmäßig | Nein (nur TCP) | Explizite Konfiguration |
| HTTP/3 (QUIC) | Standardmäßig | Experimentell | Via Plugin | Nein | Nein |
| Einzelnes Binary | Ja (Go, keine Deps) | Nein (C, mit Modulen) | Ja (Go) | Ja (C) | Nein |
| Konfigurations-API | Vollständige REST-API | Nein | Vollständige REST-API | Nur Statistik-Socket | Nein |
| Load Balancing | 8 integrierte Richtlinien | Begrenzt integriert | Mehrere Anbieter | Ausgezeichnet | Grundlegend |
| Speicherbedarf | ~20-50 MB | ~5-15 MB | ~25-60 MB | ~5-10 MB | ~30-80 MB |
| Lernkurve | Niedrig | Mittel-Hoch | Mittel | Hoch | Mittel-Hoch |
Voraussetzungen
- Ein Linux-Server mit Ubuntu 22.04+, Debian 12+ oder einer RHEL/CentOS-kompatiblen Distribution
- Ein Domainname mit DNS A/AAAA-Einträgen, die auf die öffentliche IP des Servers zeigen
- Ports 80 und 443 in Ihrer Firewall geöffnet
- Root- oder sudo-Zugang
- Kein anderer Prozess, der an den Ports 80 oder 443 gebunden ist
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw status
Caddy installieren
Ubuntu und Debian (APT)
sudo apt update && sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy
caddy version
RHEL, CentOS, Fedora (DNF)
dnf install 'dnf-command(copr)'
dnf copr enable @caddy/caddy
dnf install caddy
Docker
docker run -d \
-p 80:80 -p 443:443 -p 443:443/udp \
-v /pfad/zur/Caddyfile:/etc/caddy/Caddyfile \
-v caddy_data:/data \
-v caddy_config:/config \
caddy:latest
xcaddy — Benutzerdefinierte Builds mit Plugins
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
xcaddy build \
--with github.com/caddy-dns/cloudflare \
--with github.com/mholt/caddy-ratelimit
sudo mv caddy /usr/bin/caddy && sudo systemctl restart caddy
Caddyfile-Syntax
Struktur
# Globaler Optionsblock
{
email admin@beispiel.de
admin off
grace_period 10s
}
# Site-Block — die Domain löst automatisches HTTPS aus
app.beispiel.de {
direktive argument
}
Matcher
beispiel.de {
@api path /api/*
reverse_proxy @api localhost:8000
reverse_proxy /statisch/* localhost:9000
file_server *
}
Platzhalter (Placeholders)
beispiel.de {
reverse_proxy localhost:3000 {
header_up X-Echte-IP {remote_host}
header_up X-Weitergeleiteter-Port {server_port}
header_up X-Anfrage-ID {uuid}
}
}
Reverse-Proxy-Konfiguration
Einfaches einzelnes Backend
app.beispiel.de {
reverse_proxy localhost:3000
}
Diese einzelne Zeile bietet: automatisches HTTPS, HTTP/2, HTTP/3, HTTP→HTTPS-Weiterleitung, X-Forwarded-For-Header-Weitergabe und transparente WebSocket-Unterstützung.
Pfadbasiertes Routing
beispiel.de {
reverse_proxy /api/* localhost:8000
reverse_proxy /ws/* localhost:4000
reverse_proxy /admin/* localhost:9000
root * /var/www/frontend
file_server
}
Header-Manipulation
app.beispiel.de {
reverse_proxy localhost:3000 {
header_up Host {upstream_hostport}
header_up X-Echte-IP {remote_host}
header_up X-Weitergeleitetes-Proto {scheme}
header_up -Authorization
header_down -X-Interne-Server-ID
header_down Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
}
}
WebSocket und langlaufende Verbindungen
ws.beispiel.de {
reverse_proxy localhost:4000 {
flush_interval -1
}
}
Load Balancing
Mehrere Backends
app.beispiel.de {
reverse_proxy localhost:3001 localhost:3002 localhost:3003
}
Alle Load-Balancing-Richtlinien
app.beispiel.de {
reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
lb_policy least_conn # Backend mit wenigsten aktiven Verbindungen
# lb_policy round_robin # Sequentielle Rotation (Standard)
# lb_policy first # Immer das erste verfügbare Backend
# lb_policy random # Zufällige Auswahl
# lb_policy ip_hash # Client-IP → konsistentes Backend
# lb_policy cookie caddy_lb # Cookie-basierte Sitzungsbeibehaltung
# lb_policy header X-Shard # Routing nach Header-Wert
# lb_policy uri_hash # Anfrage-URI → konsistentes Backend
}
}
Aktive Health Checks
app.beispiel.de {
reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
lb_policy least_conn
health_uri /health
health_interval 15s
health_timeout 5s
health_status 200
}
}
Passive Health Checks
app.beispiel.de {
reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
lb_policy round_robin
fail_duration 30s
max_fails 3
unhealthy_latency 500ms
unhealthy_status 5xx
}
}
Automatisches HTTPS im Detail
ACME-Challenge-Typen
{
email admin@beispiel.de
}
# HTTP-01 (Standard)
beispiel.de {
reverse_proxy localhost:3000
}
# TLS-ALPN-01: Verwendet Port 443
nur-tls.beispiel.de {
tls {
challenges tls-alpn-01
}
reverse_proxy localhost:3001
}
# DNS-01: Keine eingehenden Ports — benötigt xcaddy + DNS-Plugin
wildcard.beispiel.de {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
reverse_proxy localhost:3002
}
On-Demand-TLS für dynamische Domains
{
on_demand_tls {
ask http://localhost:9001/domain-pruefen
interval 2m
burst 5
}
}
:443 {
tls {
on_demand
}
reverse_proxy localhost:3000
}
Interne CA für die Entwicklung
{
local_certs
}
localhost, 127.0.0.1, ::1 {
reverse_proxy localhost:3000
}
Authentifizierung
HTTP-Basisauthentifizierung
admin.beispiel.de {
basicauth /admin/* {
alice $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GT.VVKf3KCrXxpHPkAXmn9sQHO
}
reverse_proxy localhost:9000
}
caddy hash-password --plaintext 'ihrpasswort'
Delegierte Authentifizierung (Authelia, oauth2-proxy)
app.beispiel.de {
forward_auth authelia:9091 {
uri /api/verify?rd=https://auth.beispiel.de
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
reverse_proxy localhost:3000
}
Dateiserver und SPA
Statischer Dateiserver
statisch.beispiel.de {
root * /var/www/html
encode gzip zstd
file_server {
hide .git .env .htaccess
}
}
Single-Page-Application (SPA)
spa.beispiel.de {
root * /var/www/app/dist
encode gzip zstd
try_files {path} /index.html
file_server
}
Komprimierung und Zugriffsprotokollierung
beispiel.de {
encode {
zstd
gzip 6
minimum_length 1024
}
log {
output file /var/log/caddy/zugriff.log {
roll_size 100MiB
roll_keep 10
roll_keep_for 720h
}
format json
level INFO
}
reverse_proxy localhost:3000
}
Die Caddy-Admin-API
# Aktuelle Konfiguration anzeigen
curl http://localhost:2019/config/
# Konfiguration aus Caddyfile neu laden
curl -X POST http://localhost:2019/load \
-H "Content-Type: text/caddyfile" \
--data-binary @/etc/caddy/Caddyfile
Produktions-Caddyfile für mehrere Sites
{
email admin@beispiel.de
grace_period 30s
admin unix//run/caddy/admin.sock
}
(sicherheits_header) {
header {
Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
-X-Powered-By
}
}
app.beispiel.de {
import sicherheits_header
encode zstd gzip
log {
output file /var/log/caddy/app-zugriff.log { roll_size 50MiB; roll_keep 7 }
format json
}
reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
lb_policy least_conn
health_uri /health
health_interval 10s
health_timeout 3s
fail_duration 30s
max_fails 3
header_up X-Echte-IP {remote_host}
header_up X-Weitergeleitetes-Proto {scheme}
header_down -X-Interner-Trace
}
}
www.beispiel.de {
import sicherheits_header
root * /var/www/frontend/dist
encode zstd gzip
@statisch path *.css *.js *.png *.jpg *.webp *.gif *.svg *.woff2 *.ico
header @statisch Cache-Control "public, max-age=31536000, immutable"
try_files {path} /index.html
file_server
}
Fallstricke und Sonderfälle
Port 80 muss für HTTP-01-Challenges erreichbar sein. Wenn Ihr Cloud-Anbieter oder Ihre Firewall Port 80 blockiert, verwenden Sie den tls-alpn-01-Challenge oder DNS-01 via xcaddy mit einem DNS-Plugin.
Let’s Encrypt-Ratenlimits. Der Produktions-ACME-Server erlaubt 5 doppelte Zertifikate pro Domain pro Woche. Setzen Sie während Tests acme_ca https://acme-staging-v02.api.letsencrypt.org/directory.
Der caddy-Benutzer benötigt Lesezugriff auf Ihre Web-Roots. Führen Sie immer sudo chown -R caddy:caddy /var/www/ihresite aus, nachdem Sie Dateien erstellt oder kopiert haben.
Das Flush-Intervall ist wichtig für Streaming. Server-Sent Events (SSE) und Streaming-APIs erfordern flush_interval -1 im reverse_proxy-Block.
Fehlerbehebung
# Caddyfile-Syntax validieren
caddy validate --config /etc/caddy/Caddyfile
# Caddyfile automatisch formatieren
caddy fmt --overwrite /etc/caddy/Caddyfile
# Live-Protokolle verfolgen
sudo journalctl -u caddy -f --no-pager
# Prüfen, auf welchen Ports Caddy lauscht
sudo ss -tlnp | grep caddy
# TLS-Zertifikat prüfen
echo | openssl s_client -connect beispiel.de:443 -servername beispiel.de 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
Zusammenfassung
- Caddy ist ein einzelnes Go-Binary ohne externe Abhängigkeiten, das automatisches HTTPS via ACME, HTTP/2 und HTTP/3 standardmäßig und eine minimale Caddyfile-Syntax bietet
- Die
reverse_proxy-Direktive verwaltet Proxying, Load Balancing, Header-Manipulation, WebSocket-Unterstützung und Health Checks in einem einzigen Block - Acht Load-Balancing-Richtlinien decken alle Szenarien ab, von zustandslosem Round-Robin bis zur Cookie-basierten Sitzungsaffinität
- Aktive und passive Health Checks können für eine robuste Fehlererkennung kombiniert werden
- On-Demand-TLS ermöglicht die Zertifikatsausstellung pro Tenant für SaaS-Plattformen ohne Vorkonfiguration
- Verwenden Sie Snippets, um Konfigurationsblöcke zwischen mehreren Site-Definitionen zu teilen