Caddy als Reverse Proxy für Docker - einfacher als Nginx

Caddy als Reverse Proxy für Docker - einfacher als Nginx

Caddy besorgt automatisch TLS-Zertifikate von Let's Encrypt und hat eine deutlich einfachere Konfigurationssyntax als Nginx.

Warum Caddy?

  • Automatisches HTTPS: Let's Encrypt-Zertifikate werden automatisch angefordert und erneuert
  • Einfache Syntax: reverse_proxy myapp:3000 — eine Zeile pro Service
  • Kein Reload-Daemon: Caddy kann ohne Restart neu geladen werden
  • Zwei Ansätze: Statische Konfiguration oder dynamisch via Labels (wie Traefik)

Ansatz 1: Statische Caddyfile

services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config
    networks:
      - proxy

  myapp:
    image: myapp:latest
    networks:
      - proxy   # Caddy muss im selben Netzwerk sein

volumes:
  caddy-data:
  caddy-config:

networks:
  proxy:

Caddyfile:

myapp.example.com {
    reverse_proxy myapp:3000
}

api.example.com {
    reverse_proxy api:8080
    header {
        X-Frame-Options DENY
        X-Content-Type-Options nosniff
    }
}

# Lokale Entwicklung (kein TLS)
:8080 {
    reverse_proxy myapp:3000
}

Caddy erkennt automatisch: FQDN → TLS via Let's Encrypt, IP/Localhost → kein TLS.

Konfiguration neu laden

docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Kein Container-Restart nötig — Caddy lädt die Konfiguration live neu.

Ansatz 2: caddy-docker-proxy (Label-basiert)

Das Plugin lucaslorentz/caddy-docker-proxy funktioniert wie Traefik: Container tragen Labels, Caddy konfiguriert sich automatisch.

services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - caddy-data:/data
    networks:
      - proxy
    labels:
      caddy.email: admin@example.com   # Let's Encrypt E-Mail

  myapp:
    image: myapp:latest
    networks:
      - proxy
    labels:
      caddy: myapp.example.com
      caddy.reverse_proxy: "{{upstreams 3000}}"

  api:
    image: api:latest
    networks:
      - proxy
    labels:
      caddy: api.example.com
      caddy.reverse_proxy: "{{upstreams 8080}}"
      caddy.header.X-Frame-Options: DENY

volumes:
  caddy-data:

networks:
  proxy:
    external: true   # geteilt zwischen mehreren Compose-Stacks

Wenn ein neuer Container mit Caddy-Labels gestartet wird, erkennt Caddy das automatisch und konfiguriert sich neu.

Externes Netzwerk für mehrere Stacks

Wenn Caddy über mehrere Compose-Stacks hinweg als Proxy dienen soll:

# Netzwerk einmalig anlegen
docker network create proxy

# In jedem Compose-Stack:
networks:
  proxy:
    external: true

Zusammenfassung

Für einfache Setups mit wenigen Services: statische Caddyfile — übersichtlich, alles an einem Ort, leicht versionierbar. Für dynamische Umgebungen mit vielen Containern: caddy-docker-proxy — Services konfigurieren sich selbst per Label, kein manueller Caddy-Reload nötig.