# Caddy — Webserver mit automatischem HTTPS

> Praxis-Guide zu Caddy — automatische TLS-Zertifikate, Caddyfile-Syntax, Reverse Proxy, statischer Dateiserver und CLI, mit Beispielen für den Alltag.

Source: https://www.jpkc.com/db/cheatsheets/web-servers/caddy/

<!-- PROSE:intro -->
Caddy ist ein moderner, in Go geschriebener Webserver, der dir das lästigste Detail im Web-Betrieb abnimmt: Er stellt TLS-Zertifikate über Let's Encrypt oder ZeroSSL vollautomatisch aus und erneuert sie, ohne dass du certbot oder Cronjobs anfassen musst. HTTP/2 und HTTP/3 sind standardmäßig aktiv, und die übersichtliche Caddyfile-Syntax bringt dich mit wenigen Zeilen von der leeren Datei zur produktiven Konfiguration. Ob statischer Dateiserver, Reverse Proxy oder PHP-Backend – Caddy deckt die typischen Aufgaben mit klaren Direktiven ab. Dieser Guide führt dich durch die wichtigsten CLI-Befehle und Caddyfile-Bausteine für den Alltag.
<!-- PROSE:intro:end -->

## Service-Verwaltung (systemctl)

`systemctl start caddy` — Startet den Caddy-Webserver.

```bash
systemctl start caddy
```

`systemctl stop caddy` — Stoppt den Caddy-Webserver.

```bash
systemctl stop caddy
```

`systemctl restart caddy` — Startet Caddy neu (unterbricht kurz die Verbindungen). Für Config-Änderungen ohne Ausfallzeit reload verwenden.

```bash
systemctl restart caddy
```

`systemctl reload caddy` — Lädt die Caddy-Konfiguration ohne Ausfallzeit neu. Caddy liest /etc/caddy/Caddyfile erneut ein.

```bash
systemctl reload caddy
```

`systemctl status caddy` — Zeigt Status, PID und letzte Log-Ausgabe des Caddy-Dienstes.

```bash
systemctl status caddy
```

`systemctl enable caddy` — Aktiviert den automatischen Start von Caddy beim Systemstart.

```bash
systemctl enable caddy
```

`systemctl disable caddy` — Deaktiviert den automatischen Start von Caddy beim Booten.

```bash
systemctl disable caddy
```

## caddy-CLI-Befehle

`caddy run` — Startet Caddy im Vordergrund mit der Caddyfile im aktuellen Verzeichnis. Logs gehen nach stdout.

```bash
caddy run
```

`caddy run --config <file>` — Startet Caddy im Vordergrund mit einer bestimmten Konfigurationsdatei.

```bash
caddy run --config /etc/caddy/Caddyfile
```

`caddy start` — Startet Caddy als Hintergrund-Daemon.

```bash
caddy start
```

`caddy start --config <file>` — Startet Caddy als Hintergrund-Daemon mit einer bestimmten Konfigurationsdatei.

```bash
caddy start --config /etc/caddy/Caddyfile
```

`caddy stop` — Stoppt den laufenden Caddy-Hintergrund-Daemon.

```bash
caddy stop
```

`caddy reload` — Lädt die Caddy-Konfiguration ohne Ausfallzeit neu. Übernimmt die Änderungen aus der Caddyfile.

```bash
caddy reload
```

`caddy reload --config <file>` — Lädt Caddy mit einer bestimmten Konfigurationsdatei neu.

```bash
caddy reload --config /etc/caddy/Caddyfile
```

`caddy validate --config <file>` — Prüft eine Caddyfile auf Syntax- und Konfigurationsfehler, ohne den Server zu starten.

```bash
caddy validate --config /etc/caddy/Caddyfile
```

`caddy fmt <file>` — Formatiert eine Caddyfile nach dem kanonischen Stil.

```bash
caddy fmt /etc/caddy/Caddyfile
```

`caddy fmt --overwrite <file>` — Formatiert eine Caddyfile und überschreibt sie direkt.

```bash
caddy fmt --overwrite /etc/caddy/Caddyfile
```

`caddy version` — Zeigt die installierte Caddy-Version.

```bash
caddy version
```

`caddy list-modules` — Listet alle verfügbaren Caddy-Module auf (Direktiven, Handler, Matcher usw.).

```bash
caddy list-modules
```

`caddy upgrade` — Aktualisiert Caddy auf die neueste Version (ersetzt die Binary).

```bash
caddy upgrade
```

`caddy adapt --config <file>` — Wandelt eine Caddyfile in Caddys natives JSON-Konfigurationsformat um.

```bash
caddy adapt --config Caddyfile
```

`caddy environ` — Gibt die Umgebungsvariablen aus, die Caddy zur Laufzeit verwendet.

```bash
caddy environ
```

## Caddyfile: Grundstruktur

Minimaler Site-Block. Caddy stellt automatisch ein TLS-Zertifikat für die Domain aus.

```bash
example.com {
    respond "Hello, World!"
}
```

Bedient mehrere Domains aus demselben Block (kommagetrennt).

```bash
example.com, www.example.com {
    # shared config
}
```

Globaler Optionsblock (muss der erste Block sein). Legt die ACME-E-Mail, On-Demand-TLS und weitere globale Einstellungen fest.

```bash
{
    email admin@example.com
    on_demand_tls {
        ask http://localhost:9000/check
    }
}
```

Definiert ein wiederverwendbares Konfigurations-Snippet und importiert es in Site-Blöcken.

```bash
(common) {
    encode gzip zstd
    header X-Frame-Options DENY
}
example.com {
    import common
}
```

Lauscht auf einem bestimmten Port ohne HTTPS (kein TLS bei reinen Port-Adressen).

```bash
:8080 {
    respond "dev server"
}
```

Nutzt Caddys eingebaute interne CA für ein lokal vertrauenswürdiges TLS-Zertifikat (ohne Internet).

```bash
localhost {
    tls internal
    respond "local dev"
}
```

## Statischer Dateiserver

Bedient statische Dateien aus einem Verzeichnis. Das * matcht alle Requests.

```bash
example.com {
    root * /var/www/html
    file_server
}
```

Bedient statische Dateien mit aktiviertem Verzeichnis-Listing.

```bash
example.com {
    root * /var/www/html
    file_server browse
}
```

SPA-Modus: probiert den exakten Pfad und fällt für clientseitiges Routing auf index.html zurück.

```bash
example.com {
    root * /var/www/html
    try_files {path} /index.html
    file_server
}
```

Verbirgt bestimmte Dateien oder Verzeichnisse, sodass sie nicht ausgeliefert werden.

```bash
file_server {
    hide .git
    hide *.secret
}
```

`caddy file-server --root ./public --listen :8080` — Bedient ein lokales Verzeichnis sofort von der Kommandozeile aus – ganz ohne Caddyfile.

```bash
caddy file-server --root ./dist --listen :3000
```

## Reverse Proxy

Leitet alle Requests einer Domain an ein lokales Backend auf Port 3000 weiter.

```bash
example.com {
    reverse_proxy localhost:3000
}
```

Leitet nur Requests mit passendem Pfad-Präfix an ein bestimmtes Backend weiter.

```bash
example.com {
    reverse_proxy /api/* localhost:4000
}
```

Verteilt die Last standardmäßig per Round-Robin auf mehrere Backends.

```bash
example.com {
    reverse_proxy backend1:8080 backend2:8080
}
```

Verteilt die Last nach der Least-Connections-Strategie.

```bash
reverse_proxy localhost:3000 {
    lb_policy least_conn
}
```

Reicht die ursprünglichen Host- und Client-IP-Header an das Upstream-Backend weiter.

```bash
reverse_proxy localhost:3000 {
    header_up Host {upstream_hostport}
    header_up X-Real-IP {remote_host}
    header_up X-Forwarded-For {remote_host}
}
```

Konfiguriert aktive Health-Checks für das Upstream-Backend.

```bash
reverse_proxy localhost:3000 {
    health_uri /healthz
    health_interval 10s
    health_timeout 2s
}
```

Leitet an ein HTTPS-Upstream weiter und überspringt dabei die TLS-Prüfung (für interne selbstsignierte Zertifikate).

```bash
reverse_proxy https://upstream.example.com {
    transport http {
        tls_insecure_skip_verify
    }
}
```

## Weiterleitungen & Rewrites

Leitet www dauerhaft auf die Apex-Domain um und behält die Request-URI bei.

```bash
www.example.com {
    redir https://example.com{uri} permanent
}
```

Leitet allen HTTP-Verkehr auf HTTPS um. Caddy erledigt das normalerweise automatisch.

```bash
http://example.com {
    redir https://example.com{uri}
}
```

`redir /old-path /new-path permanent` — Leitet einen bestimmten Pfad dauerhaft an einen neuen Ort um (301).

```bash
redir /blog /news permanent
```

`redir /old-path /new-path temporary` — Leitet einen Pfad temporär um (302).

```bash
redir /sale /deals temporary
```

`rewrite /app/* /index.html` — Schreibt passende Requests intern auf einen anderen Pfad um (ohne Browser-Weiterleitung).

```bash
rewrite /app/* /index.html
```

`rewrite * /index.php{query}` — Schreibt alle Requests auf index.php um und behält den Query-String bei (nützlich für PHP-Apps).

```bash
rewrite * /index.php{query}
```

## TLS / HTTPS

Caddy stellt bei einer öffentlichen Domain automatisch ein Let's-Encrypt-Zertifikat aus. Keine zusätzliche Konfiguration nötig.

```bash
example.com {
    # TLS is automatic — no config needed
}
```

`tls admin@example.com` — Setzt explizit die ACME-Registrierungs-E-Mail für diesen Site-Block (überschreibt die globale Einstellung).

```bash
tls admin@example.com
```

`tls /path/to/cert.pem /path/to/key.pem` — Nutzt ein eigenes (manuell verwaltetes) TLS-Zertifikat samt privatem Schlüssel.

```bash
tls /etc/ssl/certs/example.crt /etc/ssl/private/example.key
```

`tls internal` — Nutzt Caddys eingebaute lokale CA zur Zertifikatsausstellung. Auf der lokalen Maschine automatisch vertrauenswürdig.

```bash
localhost { tls internal }
```

Schränkt TLS-Protokollversionen und Cipher-Suites ein.

```bash
tls {
    protocols tls1.2 tls1.3
    ciphers TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
}
```

Nutzt die DNS-01-ACME-Challenge (nötig für Wildcard-Zertifikate oder nicht öffentlich erreichbare Server).

```bash
tls {
    dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
```

`caddy trust` — Installiert Caddys lokale Root-CA in die Trust-Stores von System und Browser (für localhost-TLS).

```bash
caddy trust
```

`caddy untrust` — Entfernt Caddys lokale Root-CA aus den Trust-Stores.

```bash
caddy untrust
```

## Header & Komprimierung

`encode gzip zstd` — Aktiviert gzip- und zstd-Komprimierung der Antworten. Caddy wählt das beste vom Client unterstützte Format.

```bash
encode gzip zstd
```

`encode zstd gzip` — Aktiviert Komprimierung und bevorzugt zstd vor gzip.

```bash
encode zstd gzip
```

`header X-Frame-Options DENY` — Setzt einen eigenen Response-Header.

```bash
header X-Frame-Options DENY
```

`header -Server` — Entfernt einen Response-Header. Das Minus-Präfix löscht den Header.

```bash
header -Server
```

Setzt mehrere Security-Header und entfernt den Server-Header in einem Block.

```bash
header {
    X-Content-Type-Options nosniff
    X-Frame-Options DENY
    Referrer-Policy strict-origin-when-cross-origin
    -Server
}
```

`header Cache-Control "public, max-age=31536000, immutable"` — Setzt langfristige Caching-Header für statische Assets.

```bash
header Cache-Control "public, max-age=31536000"
```

`header Access-Control-Allow-Origin *` — Erlaubt alle Origins für CORS (Cross-Origin Resource Sharing).

```bash
header Access-Control-Allow-Origin *
```

## PHP & FastCGI

Bedient eine PHP-Anwendung via PHP-FPM über einen Unix-Socket. Kombiniert FastCGI, try_files und file_server.

```bash
example.com {
    root * /var/www/html
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}
```

`php_fastcgi 127.0.0.1:9000` — Verbindet sich mit PHP-FPM über TCP statt über einen Unix-Socket.

```bash
php_fastcgi 127.0.0.1:9000
```

Komplettes WordPress-Setup mit PHP-FPM, statischen Dateien und Komprimierung.

```bash
example.com {
    root * /var/www/wordpress
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
    encode gzip zstd
}
```

## Matcher & Routing

Leitet /api/* an ein Backend und alles andere an den Dateiserver.

```bash
handle /api/* {
    reverse_proxy localhost:3000
}
handle {
    file_server
}
```

Wie handle, entfernt aber das passende Pfad-Präfix, bevor es an den inneren Block übergeben wird.

```bash
handle_path /static/* {
    root * /var/www/static
    file_server
}
```

Definiert einen benannten Matcher mit @name und referenziert ihn in einer Direktive.

```bash
@api path /api/*
reverse_proxy @api localhost:3000
```

Matcht Requests anhand eines Header-Werts und liefert für Bots einen 403 zurück.

```bash
@bot header User-Agent *bot*
respond @bot 403
```

Kombiniert Matcher: wendet Basic Auth nur auf /admin/* eines bestimmten Hosts an.

```bash
@secure {
    host example.com
    path /admin/*
}
basicauth @secure {
    admin JDJhJDE0JG...
}
```

Nutzt den 'not'-Matcher, um alle außer www auf die www-Domain umzuleiten.

```bash
@notwww not host www.example.com
redir @notwww https://www.example.com{uri}
```

## Logging

`log` — Aktiviert Access-Logging mit Standardwerten (JSON-Format nach stderr).

```bash
log
```

Schreibt Access-Logs in eine Datei.

```bash
log {
    output file /var/log/caddy/access.log
}
```

Access-Log mit automatischer Rotation: max. 100 MB pro Datei, 5 Dateien behalten, max. 30 Tage.

```bash
log {
    output file /var/log/caddy/access.log {
        roll_size 100mb
        roll_keep 5
        roll_keep_for 720h
    }
}
```

Nutzt das menschenlesbare Konsolen-Format statt JSON für die Log-Ausgabe.

```bash
log {
    format console
}
```

Loggt nach stdout im JSON-Format mit Debug-Level (nützlich in Containern).

```bash
log {
    output stdout
    format json
    level DEBUG
}
```

`journalctl -u caddy -f` — Verfolgt Caddys Live-Log-Ausgabe über das systemd-Journal.

```bash
journalctl -u caddy -f
```

`journalctl -u caddy --since "1 hour ago"` — Zeigt Caddy-Logs der letzten Stunde.

```bash
journalctl -u caddy --since "1 hour ago"
```

## Admin-API

`curl -s http://localhost:2019/config/` — Holt die aktuelle Caddy-Konfiguration als JSON über die Admin-API (Standard-Listen: localhost:2019).

```bash
curl -s http://localhost:2019/config/ | jq '.'
```

`curl -X POST http://localhost:2019/load -H 'Content-Type: text/caddyfile' --data-binary @Caddyfile` — Lädt eine Caddyfile über die Admin-API (Reload ohne Ausfallzeit).

```bash
curl -X POST http://localhost:2019/load -H 'Content-Type: text/caddyfile' --data-binary @Caddyfile
```

`curl -X DELETE http://localhost:2019/config/` — Leert die aktuelle Caddy-Konfiguration über die Admin-API.

```bash
curl -X DELETE http://localhost:2019/config/
```

`curl -s http://localhost:2019/reverse_proxy/upstreams` — Listet alle Reverse-Proxy-Upstream-Backends und ihren Health-Status auf.

```bash
curl -s http://localhost:2019/reverse_proxy/upstreams | jq '.'
```

Deaktiviert die Admin-API komplett im globalen Optionsblock (Härtung für die Produktion).

```bash
{
    admin off
}
```

Ändert die Listen-Adresse der Admin-API im globalen Optionsblock.

```bash
{
    admin localhost:2020
}
```

## Praxisbeispiele

Produktionsreife statische Site mit Komprimierung und Security-Headern.

```bash
example.com {
    root * /var/www/html
    encode gzip zstd
    file_server
    header -Server
    header X-Frame-Options DENY
}
```

Reverse Proxy auf eine Node.js- oder andere Backend-App mit Komprimierung und gehärteten Headern.

```bash
app.example.com {
    encode gzip zstd
    reverse_proxy localhost:3000
    header -Server
}
```

Standard-PHP-Site mit PHP-FPM, statischem Dateiserver und gzip.

```bash
example.com {
    root * /var/www/html
    encode gzip
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}
```

Wildcard-Zertifikat per DNS-Challenge, das Subdomains an verschiedene Backends routet.

```bash
*.example.com {
    tls {
        dns cloudflare {env.CF_TOKEN}
    }
    @app host app.example.com
    handle @app {
        reverse_proxy localhost:3000
    }
}
```

`caddy reverse-proxy --from :80 --to localhost:3000` — Startet sofort einen Reverse Proxy von der Kommandozeile aus – ganz ohne Caddyfile.

```bash
caddy reverse-proxy --from :443 --to localhost:3000
```

Liefert für einen Health-Check-Endpunkt einen statischen 200 und leitet alles andere weiter.

```bash
example.com {
    respond /healthz 200
    reverse_proxy localhost:3000
}
```

<!-- PROSE:outro -->
## Fazit

Caddy verschiebt die Messlatte für komfortablen Web-Betrieb: Was bei klassischen Servern manuelle Zertifikatsverwaltung und seitenlange Konfiguration bedeutet, erledigt Caddy mit sinnvollen Defaults und automatischem HTTPS. Damit ein neues Setup reibungslos startet, gilt eine einfache Routine – vor jedem `reload` mit `caddy validate` prüfen und mit `caddy fmt` formatieren. Für automatisches HTTPS müssen außerdem die Ports 80 und 443 offen und die Domain öffentlich erreichbar sein, sonst kann Caddy die ACME-Challenge nicht abschließen.

## Weiterführende Links

- [Caddy – offizielle Dokumentation](https://caddyserver.com/docs/) – Referenz und Handbuch (englisch)
- [Caddyfile-Konzepte](https://caddyserver.com/docs/caddyfile) – Aufbau und Direktiven der Caddyfile (englisch)
- [Caddy auf GitHub](https://github.com/caddyserver/caddy) – Quellcode und Releases (englisch)
<!-- PROSE:outro:end -->

## Verwandte Kommandos

- [apache](https://www.jpkc.com/db/cheatsheets/web-servers/apache/) – der etablierte, modular aufgebaute Webserver-Klassiker
- [certbot](https://www.jpkc.com/db/cheatsheets/web-servers/certbot/) – TLS-Zertifikate manuell via Let's Encrypt verwalten
- [ferron](https://www.jpkc.com/db/cheatsheets/web-servers/ferron/) – moderner, ressourcenschonender Webserver als Alternative

