Caddy ist ein moderner Webserver mit automatischem HTTPS. Er bezieht und erneuert Let's Encrypt Zertifikate vollautomatisch und benötigt minimale Konfiguration.
Vorteile von Caddy
Features
- Automatisches HTTPS (Let's Encrypt)
- Automatische HTTP/2 und HTTP/3
- Einfache Caddyfile-Syntax
- Reverse Proxy integriert
- Zero-Downtime Reloads
- Modulares DesignVergleich mit Nginx
| Feature | Caddy | Nginx | |---------|-------|-------| | HTTPS | Automatisch | Manuell/Certbot | | Konfiguration | Einfach | Komplex | | Performance | Gut | Exzellent | | Erweiterungen | Go Plugins | C Module |
Installation
Debian/Ubuntu
# Repository hinzufügen
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
# Installieren
apt update
apt install caddyDocker
docker run -d \
--name caddy \
-p 80:80 \
-p 443:443 \
-v caddy_data:/data \
-v caddy_config:/config \
-v ./Caddyfile:/etc/caddy/Caddyfile \
caddyService
systemctl enable --now caddy
systemctl status caddyCaddyfile Grundlagen
Minimale Konfiguration
# /etc/caddy/Caddyfile
example.com {
root * /var/www/html
file_server
}Mit Reverse Proxy
app.example.com {
reverse_proxy localhost:3000
}Mehrere Sites
example.com {
root * /var/www/example
file_server
}
api.example.com {
reverse_proxy localhost:8080
}
www.example.com {
redir https://example.com{uri}
}Reverse Proxy
Einfacher Proxy
app.example.com {
reverse_proxy localhost:3000
}Mit Header-Anpassung
app.example.com {
reverse_proxy localhost:3000 {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}Load Balancing
app.example.com {
reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
lb_policy round_robin
health_uri /health
health_interval 10s
}
}Sticky Sessions
app.example.com {
reverse_proxy localhost:3001 localhost:3002 {
lb_policy cookie
}
}WebSocket
app.example.com {
reverse_proxy localhost:3000
@websocket {
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @websocket localhost:3000
}Statische Dateien
File Server
example.com {
root * /var/www/html
file_server
}Mit Index und Browse
files.example.com {
root * /var/www/files
file_server browse
}SPA (Single Page Application)
app.example.com {
root * /var/www/app
try_files {path} /index.html
file_server
}Mit Komprimierung
example.com {
root * /var/www/html
encode gzip zstd
file_server
}SSL/TLS Konfiguration
Automatisches HTTPS
# HTTPS ist automatisch aktiviert für Domains
example.com {
respond "Hello, HTTPS!"
}Eigene Zertifikate
example.com {
tls /etc/ssl/certs/cert.pem /etc/ssl/private/key.pem
reverse_proxy localhost:3000
}Interne CA (Self-Signed)
localhost {
tls internal
respond "Hello, localhost!"
}On-Demand TLS
{
on_demand_tls {
ask http://localhost:5000/check
}
}
https:// {
tls {
on_demand
}
reverse_proxy localhost:3000
}Middleware und Direktiven
Basic Auth
admin.example.com {
basicauth {
admin $2a$14$... # bcrypt hash
}
reverse_proxy localhost:8080
}Hash erstellen:
caddy hash-passwordRate Limiting
{
order rate_limit before basicauth
}
api.example.com {
rate_limit {remote.ip} 10r/s
reverse_proxy localhost:8080
}IP Filtering
admin.example.com {
@allowed remote_ip 192.168.1.0/24 10.0.0.0/8
handle @allowed {
reverse_proxy localhost:8080
}
respond "Forbidden" 403
}Headers
example.com {
header {
X-Frame-Options "DENY"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
Strict-Transport-Security "max-age=31536000"
-Server
}
reverse_proxy localhost:3000
}Logging
example.com {
log {
output file /var/log/caddy/access.log
format json
}
reverse_proxy localhost:3000
}Rewrite und Redirect
Redirect
# HTTP zu HTTPS (automatisch)
# www zu non-www
www.example.com {
redir https://example.com{uri} permanent
}
# Pfad-Redirect
example.com {
redir /old-path /new-path permanent
reverse_proxy localhost:3000
}Rewrite
example.com {
rewrite /api/* /api/v1{uri}
reverse_proxy localhost:3000
}Strip Prefix
example.com {
handle_path /api/* {
reverse_proxy localhost:8080
}
}PHP mit Caddy
PHP-FPM
example.com {
root * /var/www/html
php_fastcgi unix//run/php/php8.2-fpm.sock
file_server
}Laravel
laravel.example.com {
root * /var/www/laravel/public
php_fastcgi unix//run/php/php8.2-fpm.sock
file_server
encode gzip
@static {
path_regexp static \.(css|js|gif|ico|jpg|jpeg|png|svg|woff|woff2)$
}
header @static Cache-Control "public, max-age=31536000"
}WordPress
wordpress.example.com {
root * /var/www/wordpress
php_fastcgi unix//run/php/php8.2-fpm.sock
file_server
@disallowed {
path /xmlrpc.php
path *.sql
path /wp-content/uploads/*.php
}
respond @disallowed 404
encode gzip
}Praktische Beispiele
Node.js App mit Static Files
app.example.com {
# Statische Dateien
handle /static/* {
root * /var/www/app
file_server
}
# API
handle /api/* {
reverse_proxy localhost:3000
}
# Frontend
handle {
root * /var/www/app/dist
try_files {path} /index.html
file_server
}
encode gzip
}Multi-Tenant Setup
*.example.com {
@tenant1 host app1.example.com
handle @tenant1 {
reverse_proxy localhost:3001
}
@tenant2 host app2.example.com
handle @tenant2 {
reverse_proxy localhost:3002
}
handle {
respond "Unknown tenant" 404
}
}API Gateway
api.example.com {
# Auth Service
handle /auth/* {
reverse_proxy auth:3000
}
# User Service
handle /users/* {
reverse_proxy users:3000
}
# Order Service
handle /orders/* {
reverse_proxy orders:3000
}
# Rate Limiting
rate_limit {remote.ip} 100r/m
# Headers
header {
Access-Control-Allow-Origin "*"
Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
}
}JSON-Konfiguration
API-basierte Konfiguration
# Konfiguration abrufen
curl localhost:2019/config/
# Konfiguration setzen
curl localhost:2019/config/ -X POST -H "Content-Type: application/json" -d @config.jsonJSON-Format
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [":443"],
"routes": [{
"match": [{"host": ["example.com"]}],
"handle": [{
"handler": "reverse_proxy",
"upstreams": [{"dial": "localhost:3000"}]
}]
}]
}
}
}
}
}Troubleshooting
Logs prüfen
journalctl -u caddy -f
# Oder mit Debug
caddy run --config /etc/caddy/Caddyfile --adapter caddyfileKonfiguration testen
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
caddy fmt --overwrite /etc/caddy/CaddyfileZertifikat-Probleme
# Zertifikate befinden sich in
ls ~/.local/share/caddy/certificates/
# Manuelles Zertifikat anfordern
caddy trustZusammenfassung
| Direktive | Funktion | |-----------|----------| | reverse_proxy | Proxy zu Backend | | file_server | Statische Dateien | | root | Dokumentenwurzel | | encode | Komprimierung | | tls | SSL-Konfiguration | | header | HTTP-Header | | basicauth | Authentifizierung | | log | Logging |
| Matcher | Beispiel | |---------|----------| | @name path /api/ | Pfad-Match | | @name host example.com | Host-Match | | @name remote_ip 10.0.0.0/8 | IP-Match | | @name header Accept json* | Header-Match |
| Befehl | Funktion | |--------|----------| | caddy run | Vordergrund starten | | caddy start | Hintergrund starten | | caddy reload | Konfiguration neu laden | | caddy validate | Konfiguration prüfen |
Fazit
Caddy ist ideal wenn automatisches HTTPS und einfache Konfiguration wichtig sind. Die Caddyfile-Syntax ist intuitiv und deutlich kürzer als Nginx-Konfigurationen. Für die meisten Anwendungsfälle reicht die Standard-Installation ohne zusätzliche Module. Die automatische Zertifikatsverwaltung spart erheblichen Aufwand. Für sehr hohe Performance-Anforderungen bleibt Nginx die bessere Wahl.