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 Design
Vergleich 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 caddy
Docker
docker run -d \
--name caddy \
-p 80:80 \
-p 443:443 \
-v caddy_data:/data \
-v caddy_config:/config \
-v ./Caddyfile:/etc/caddy/Caddyfile \
caddy
Service
systemctl enable --now caddy
systemctl status caddy
Caddyfile 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
}
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-password
Rate 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
}
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.json
{
"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 caddyfile
Konfiguration testen
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
caddy fmt --overwrite /etc/caddy/Caddyfile
Zertifikat-Probleme
# Zertifikate befinden sich in
ls ~/.local/share/caddy/certificates/
# Manuelles Zertifikat anfordern
caddy trust
Zusammenfassung
| 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.