Caddy – Konzepte und Konfiguration
Caddy – Konzepte und Konfiguration
Was macht ein Webserver?
Ein Webserver wartet auf eingehende Netzwerkanfragen (HTTP/HTTPS) und beantwortet sie. Das kann bedeuten:
- Eine Datei ausliefern (HTML, Bild, CSS)
- Eine Anfrage an einen anderen Dienst weiterzuleiten (Reverse Proxy)
- Eine Anfrage umzuleiten (Redirect)
- Eine Anfrage abzulehnen (403, 404)
Klassische Webserver wie Apache und nginx können all das – benötigen aber für HTTPS externe Werkzeuge (z.B. Certbot) und manuelle Zertifikatsverwaltung.
Caddy übernimmt die Zertifikatsverwaltung automatisch: Er bezieht TLS-Zertifikate von Let's Encrypt, erneuert sie selbstständig, und erzwingt HTTPS ohne manuellen Eingriff.
Das Caddyfile
Die Konfiguration von Caddy erfolgt in einer einzigen Textdatei: dem Caddyfile. Die Syntax ist bewusst einfach gehalten.
Grundstruktur:
<syntaxhighlight lang="caddy"> example.com {
# Direktiven für diese Domain
} </syntaxhighlight>
Alles innerhalb der geschweiften Klammern gilt nur für diese Domain. Mehrere Domains können in derselben Datei konfiguriert werden.
Direktiven
reverse_proxy
Kurzfassung: Leitet eingehende Anfragen an einen anderen Dienst weiter.
<syntaxhighlight lang="caddy"> reverse_proxy localhost:8080 reverse_proxy myapp:3000 </syntaxhighlight>
Erklärung:
Ein Reverse Proxy sitzt zwischen dem Browser des Nutzers und dem eigentlichen Dienst. Der Browser spricht immer mit Caddy – nie direkt mit dem Dienst dahinter. Caddy nimmt die Anfrage entgegen, leitet sie weiter, bekommt die Antwort, und schickt sie zurück an den Browser.
Vorteile:
- Nur Caddy ist nach außen sichtbar – interne Dienste bleiben verborgen
- TLS wird einmalig bei Caddy terminiert
- Mehrere Dienste können hinter einer einzigen IP laufen
Bei Docker-Containern kann der Containername als Hostname verwendet werden:
<syntaxhighlight lang="caddy"> reverse_proxy nextcloud:443 </syntaxhighlight>
Caddy löst nextcloud über das interne Docker-Netz auf.
transport http
Kurzfassung: Steuert wie Caddy intern mit dem Zieldienst kommuniziert.
<syntaxhighlight lang="caddy"> reverse_proxy nextcloud:443 {
transport http {
tls_insecure_skip_verify
}
} </syntaxhighlight>
Erklärung:
Standardmäßig kommuniziert Caddy mit Zieldiensten über HTTP. Spricht der Zieldienst selbst HTTPS (z.B. ein Container der intern TLS verwendet), muss Caddy das wissen – und bekommt den transport http-Block.
tls_insecure_skip_verify deaktiviert die Zertifikatsprüfung für die interne Verbindung. Das klingt unsicher – ist es intern aber nicht, weil:
- Die Verbindung innerhalb des Docker-Netzes stattfindet
- Kein externer Angreifer Zugriff auf diesen internen Kanal hat
- Das Zertifikat des Zieldienstes selbstsigniert sein darf
Nach außen (Browser → Caddy) bleibt HTTPS mit gültigem Zertifikat bestehen.
header
Kurzfassung: Setzt, entfernt oder verändert HTTP-Response-Header – also Header die Caddy an den Browser zurückschickt.
<syntaxhighlight lang="caddy"> header {
-Server Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "no-referrer"
} </syntaxhighlight>
Erklärung:
HTTP-Header sind Metadaten die jede Antwort begleiten. Sie sagen dem Browser wie er die Antwort behandeln soll.
-Server– Das Minuszeichen entfernt den Header. Ohne diese Zeile würde CaddyServer: Caddymitsenden – ein Hinweis für Angreifer welche Software läuft.Strict-Transport-Security– Sagt dem Browser: „Verbinde dich für die nächsten 31536000 Sekunden (1 Jahr) ausschließlich über HTTPS mit dieser Domain."X-Content-Type-Options "nosniff"– Verhindert dass der Browser den Dateityp einer Antwort „errät". Schutz gegen bestimmte Angriffe über präparierte Dateien.X-Frame-Options "SAMEORIGIN"– Verhindert dass die Seite in einem<iframe>einer fremden Domain eingebettet wird. Schutz gegen Clickjacking.Referrer-Policy "no-referrer"– Der Browser sendet beim Klick auf einen Link keine Information woher der Nutzer kam.
header_up
Kurzfassung: Setzt Header die Caddy an den Zieldienst (upstream) weiterleitet – nicht an den Browser.
<syntaxhighlight lang="caddy"> reverse_proxy myapp:8080 {
header_up X-Real-IP {remote_ip}
} </syntaxhighlight>
Erklärung:
Ohne zusätzliche Header sieht ein Dienst hinter Caddy als Absender immer Caddys interne IP – nie die echte Client-IP. Mit header_up X-Real-IP {remote_ip} reicht Caddy die echte IP des Clients weiter.
{remote_ip} ist eine Caddy-Variable die zur Laufzeit durch die tatsächliche IP ersetzt wird.
Caddy setzt X-Forwarded-For, X-Forwarded-Proto und X-Forwarded-Host automatisch – diese müssen nicht manuell gesetzt werden.
@matcher (Named Matchers)
Kurzfassung: Definiert eine benannte Bedingung die auf Anfragen zutreffen kann oder nicht.
<syntaxhighlight lang="caddy"> @xmlrpc path /xmlrpc.php respond @xmlrpc 403
@admin {
method POST path /admin/*
} handle @admin {
reverse_proxy backend:8080
} </syntaxhighlight>
Erklärung:
Matcher sind das Herzstück von Caddy-Konfigurationen. Sie ermöglichen es, Regeln nur auf bestimmte Anfragen anzuwenden.
Das @-Zeichen leitet einen Matcher ein. Der Name danach ist frei wählbar. Matcher können prüfen:
path– welcher Pfad wird angefragt?method– GET, POST, PUT, DELETE...?query– enthält die URL bestimmte Parameter?remote_ip– kommt die Anfrage von einer bestimmten IP?header– enthält die Anfrage bestimmte Header?
Mehrere Bedingungen in einem Block werden mit UND verknüpft – alle müssen zutreffen.
handle
Kurzfassung: Führt Direktiven nur dann aus wenn ein Matcher zutrifft. Nicht-passende Anfragen fallen durch zum nächsten Block.
<syntaxhighlight lang="caddy"> @static path /static/* handle @static {
file_server
}
handle {
reverse_proxy backend:8080
} </syntaxhighlight>
Erklärung:
handle ohne Matcher ist der Standardfall – er greift für alles was kein anderer Block behandelt hat. In Kombination mit Matchern entsteht eine Art Weiche: statische Dateien werden direkt ausgeliefert, alles andere geht an den Backend-Dienst.
route
Kurzfassung: Wie handle, aber die Reihenfolge der Direktiven wird strikt eingehalten.
Erklärung:
Caddy verarbeitet Direktiven normalerweise in einer intern festgelegten Reihenfolge – unabhängig davon wie sie im Caddyfile stehen. route erzwingt die Reihenfolge wie sie im Caddyfile steht. Nützlich wenn die Reihenfolge der Verarbeitung wichtig ist.
redir
Kurzfassung: Leitet den Browser auf eine andere URL um.
<syntaxhighlight lang="caddy"> redir https://new.example.com{uri} 301 redir https://new.example.com{uri} 308 </syntaxhighlight>
Erklärung:
Der Unterschied zwischen 301 und 308:
| Code | Name | Bedeutung |
|---|---|---|
| 301 | Moved Permanently | Browser darf die HTTP-Methode ändern (POST → GET) |
| 308 | Permanent Redirect | Browser behält die HTTP-Methode bei (POST bleibt POST) |
Für einfache Browser-Weiterleitungen ist 301 der Klassiker. Für API-Weiterleitungen oder Formulare ist 308 wichtig.
{uri} ist eine Caddy-Variable für den vollständigen Pfad inkl. Query-String – so bleibt der ursprüngliche Pfad nach der Weiterleitung erhalten.
respond
Kurzfassung: Antwortet direkt mit einem HTTP-Statuscode – ohne den Zieldienst zu kontaktieren.
<syntaxhighlight lang="caddy"> @xmlrpc path /xmlrpc.php respond @xmlrpc 403
respond 404 </syntaxhighlight>
Erklärung:
Nützlich um bestimmte Pfade hart zu blockieren ohne dass die Anfrage den eigentlichen Dienst erreicht. Caddy antwortet sofort – schnell und ressourcenschonend.
Gängige Statuscodes:
| Code | Bedeutung |
|---|---|
| 200 | OK |
| 301/308 | Weiterleitung (permanent) |
| 403 | Forbidden – Zugriff verweigert |
| 404 | Not Found – nicht vorhanden |
| 500 | Internal Server Error |
file_server
Kurzfassung: Liefert statische Dateien aus einem Verzeichnis aus.
<syntaxhighlight lang="caddy"> root * /var/www/html file_server </syntaxhighlight>
Erklärung:
root legt das Basisverzeichnis fest. file_server aktiviert die Auslieferung. Caddy sucht dann für jeden Request die entsprechende Datei im Verzeichnis und liefert sie aus – wie ein klassischer Webserver.
tls
Kurzfassung: Steuert TLS-Einstellungen für eine Domain.
<syntaxhighlight lang="caddy"> tls {
alpn http/1.1
} </syntaxhighlight>
Erklärung:
Caddy verwaltet TLS-Zertifikate automatisch. Der tls-Block ist nur nötig wenn vom Standard abgewichen werden soll.
alpn (Application-Layer Protocol Negotiation) legt fest welche HTTP-Version ausgehandelt wird. Standardmäßig bietet Caddy HTTP/2 an. Mit alpn http/1.1 wird HTTP/2 deaktiviert – nützlich wenn ein Zieldienst damit nicht zurechtkommt.
Globale Optionen
Am Anfang des Caddyfiles können globale Einstellungen gesetzt werden:
<syntaxhighlight lang="caddy"> {
admin 127.0.0.1:2019
} </syntaxhighlight>
admin aktiviert die Caddy-Admin-API auf dem angegebenen Port. Mit 127.0.0.1:2019 ist sie nur lokal erreichbar – nicht von außen. Über diese API kann Caddy zur Laufzeit neu geladen werden:
<syntaxhighlight lang="bash"> caddy reload --config /etc/caddy/Caddyfile </syntaxhighlight>
