Caddy en reverse proxy Docker : configuration Compose avec HTTPS automatique
Faites tourner Caddy comme reverse proxy Docker : une stack compose, un réseau partagé, reverse_proxy vers les noms de service et HTTPS automatique, et quand les labels de caddy-docker-proxy sont utiles.
En bref : faites tourner Caddy dans son propre conteneur qui publie les ports 80 et 443, rattachez-le avec vos conteneurs applicatifs à un même réseau Docker partagé, et pointez `reverse_proxy` vers chaque nom de service et son port interne (par exemple `reverse_proxy app:3000`). Caddy résout le nom via le DNS intégré de Docker et obtient automatiquement un certificat TLS pour chaque adresse de site.
Ce guide présente d'abord l'approche par Caddyfile simple, puis la variante caddy-docker-proxy pilotée par labels, et explique quand chacune convient sur un seul VPS. Si vous faites tourner Caddy directement sur l'hôte plutôt que dans Docker, voir le guide reverse proxy Caddy de base.
Comment les éléments s'articulent
Seul le conteneur Caddy publie des ports vers l'extérieur. Chaque conteneur backend rejoint un réseau bridge défini par l'utilisateur (ici nommé `web`) et n'expose son port que sur ce réseau. Le serveur DNS intégré de Docker, disponible sur les réseaux définis par l'utilisateur, permet à Caddy de joindre `app:3000` par nom de service ou de conteneur : vous ne codez jamais en dur des IP de conteneurs qui changent à chaque recréation.
Ne pas publier les backends compte plus qu'il n'y paraît : Docker écrit ses propres règles iptables, si bien qu'un port publié avec `ports:` peut être joignable depuis Internet même quand ufw indique qu'il est bloqué. Utilisez `expose:` ou aucun mappage de port pour tout ce qui doit rester derrière le proxy.
| Composant | Rôle | Publié sur l'hôte ? |
|---|---|---|
| conteneur caddy | Terminaison TLS, routage par nom d'hôte, redirection HTTP vers HTTPS | Oui : 80/tcp, 443/tcp, 443/udp |
| réseau web | Réseau bridge partagé avec DNS intégré pour les noms de service | Non |
| conteneurs applicatifs | Vos services (applications web, API, tableaux de bord) | Non, joignables uniquement via Caddy |
| volume caddy_data | Certificats, clés privées, compte ACME | Non, mais doit persister |
Pas à pas : Caddyfile simple avec docker compose
- 01.Pointez un enregistrement A (et AAAA si vous utilisez IPv6) pour chaque nom d'hôte vers le VPS avant de démarrer Caddy, sinon l'émission des certificats échouera.
- 02.Créez une fois le réseau partagé : `docker network create web`.
- 03.Créez `/opt/proxy/compose.yaml` et `/opt/proxy/Caddyfile` comme ci-dessous, puis lancez `docker compose up -d` dans `/opt/proxy`.
- 04.Rattachez chaque stack applicative au réseau externe `web` et démarrez-la avec `docker compose up -d`.
- 05.Suivez l'émission du premier certificat avec `docker compose logs -f caddy` dans `/opt/proxy`.
- 06.Après modification du Caddyfile, rechargez sans interruption : `docker compose exec -w /etc/caddy caddy caddy reload`.
# /opt/proxy/compose.yaml
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certificates and ACME account keys
- caddy_config:/config
networks:
- web
volumes:
caddy_data:
caddy_config:
networks:
web:
external: trueRattacher une application et écrire le Caddyfile
Chaque stack applicative déclare le même réseau externe. Le nom du service devient le nom d'hôte que Caddy contacte. Le volume `caddy_data` est celui que vous ne devez jamais perdre : le supprimer oblige Caddy à redemander tous les certificats, ce qui peut se heurter aux limites de débit ACME.
# /opt/app/compose.yaml
services:
app:
image: ghcr.io/example/app:latest
restart: unless-stopped
expose:
- "3000" # reachable on the network, NOT published on the host
networks:
- web
networks:
web:
external: true
# /opt/proxy/Caddyfile
{
email [email protected]
}
app.example.com {
reverse_proxy app:3000
}
grafana.example.com {
reverse_proxy grafana:3000
}
api.example.com {
reverse_proxy api-1:8080 api-2:8080 {
lb_policy round_robin
health_uri /healthz
health_interval 10s
}
}Backends Caddy : upstreams, répartition de charge et health checks
Dans le vocabulaire de Caddy, un backend est un upstream de `reverse_proxy`. Vous pouvez lister plusieurs upstreams dans une seule directive, choisir une `lb_policy` comme `round_robin`, `least_conn` ou `ip_hash`, et ajouter des health checks actifs avec `health_uri` pour que les conteneurs défaillants sortent de la rotation. Les vérifications passives (`fail_duration`, `max_fails`) sont utiles aussi quand l'application n'a pas d'endpoint de santé.
Caddy définit par défaut `X-Forwarded-For`, `X-Forwarded-Proto` et `X-Forwarded-Host` sur les requêtes proxifiées. Configurez votre application pour qu'elle fasse confiance à la plage réseau du proxy, afin qu'elle voie la vraie IP du client et génère des liens `https://`. WebSockets et gRPC fonctionnent via `reverse_proxy` sans réglage supplémentaire ; pour du gRPC en clair, utilisez `reverse_proxy h2c://service:50051`.
Des labels au lieu d'un Caddyfile : caddy-docker-proxy
Ceux qui cherchent un « Caddy proxy manager » veulent généralement ce que propose Nginx Proxy Manager : ajouter un conteneur et obtenir un nom d'hôte et un certificat sans modifier de fichier central. Caddy n'a pas d'interface graphique officielle, mais le projet communautaire caddy-docker-proxy (github.com/lucaslorentz/caddy-docker-proxy) génère le Caddyfile à partir des labels des conteneurs et recharge Caddy quand des conteneurs démarrent ou s'arrêtent.
Il a besoin d'un accès en lecture au socket Docker, ce qui équivaut de fait à root sur l'hôte. Montez-le en lecture seule, maintenez l'image du proxy à jour, et préférez le Caddyfile simple si vous ne faites tourner qu'une poignée de services.
services:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- CADDY_INGRESS_NETWORKS=web
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- caddy_data:/data
networks:
- web
whoami:
image: traefik/whoami
networks:
- web
labels:
caddy: whoami.example.com
caddy.reverse_proxy: "{{upstreams 80}}"
volumes:
caddy_data:
networks:
web:
external: trueCaddyfile simple ou caddy-docker-proxy
| Caddyfile simple | Labels caddy-docker-proxy | |
|---|---|---|
| La configuration se trouve dans | Un seul fichier versionné dans git | Des labels répartis dans les fichiers compose |
| Accès au socket Docker | Inutile | Requis (sensible pour la sécurité) |
| Nouveau service | Modifier le Caddyfile, lancer `caddy reload` | Ajouter des labels, démarrer le conteneur |
| Image | `caddy:2` officielle | Image communautaire basée sur Caddy |
| Débogage | Lire directement le fichier | Examiner la configuration générée dans les journaux |
| Idéal pour | Petits VPS stables | Nombreux services éphémères ou souvent modifiés |
Le faire tourner sur un VPS
Sur un VPS KVM NoctisNode, vous disposez d'un accès root complet et d'une IPv4 dédiée : publier 80 et 443 depuis un seul conteneur Caddy et masquer tout le reste est simple. Un Wisp (1 vCPU, 1 Go de RAM) suffit pour Caddy et quelques conteneurs légers ; les stacks plus lourdes conviennent à Pulse ou Umbra. Les détails d'émission des certificats et les pannes possibles sont couverts dans comment fonctionne le HTTPS automatique de Caddy, et le transfert TCP brut ou SSH dans proxy TCP et SSH avec Caddy. Verrouillez le SSH de l'hôte avec le guide de durcissement SSH.
FAQ
QComment faire de Caddy un reverse proxy vers un conteneur Docker ?
APlacez Caddy et le conteneur sur le même réseau Docker défini par l'utilisateur et utilisez `reverse_proxy service-name:port` dans le Caddyfile. N'utilisez pas `localhost`, car dans le conteneur Caddy il désigne Caddy lui-même.
QPourquoi Caddy renvoie-t-il 502 Bad Gateway pour mon conteneur ?
AEn général, les conteneurs ne sont pas sur un réseau partagé, le port est erroné (utilisez le port interne du conteneur, pas un port publié sur l'hôte), ou l'application n'écoute que sur 127.0.0.1 dans son conteneur. Faites-la écouter sur 0.0.0.0 et vérifiez `docker network inspect web`.
Qcaddy-docker-proxy est-il sûr ?
AIl fonctionne bien, mais il nécessite le socket Docker, qui donne un contrôle équivalent à root sur l'hôte. Montez-le en lecture seule, maintenez l'image à jour et évitez d'exposer l'endpoint d'administration de Caddy.
QOù Caddy stocke-t-il les certificats dans Docker ?
ADans `/data` à l'intérieur de l'image officielle : montez-y un volume nommé. Le perdre signifie réémettre tous les certificats, avec le risque d'atteindre les limites de débit ACME.
QExiste-t-il un Caddy proxy manager avec interface web ?
ACaddy n'a pas d'interface web officielle ; il se configure avec un Caddyfile, du JSON ou son API d'administration. Des outils à base de labels comme caddy-docker-proxy offrent un fonctionnement similaire : on ajoute un conteneur et c'est parti.