Développement Web

Caddy reverse proxy 2026 : guide complet (HTTPS auto, HTTP/3, Caddyfile)

10 min de lecture

📚 Cet article s’intègre dans notre parcours self-hosting Afrique de l’Ouest. Pour la stratégie complète (Coolify, Hetzner, Docker, sauvegarde, sécurité), voir le guide pilier self-hosting 2026.

Caddy est en 2026 (informations vérifiées en avril 2026, susceptibles d’évoluer) le reverse proxy moderne par excellence : HTTPS automatique sans configuration, syntaxe Caddyfile minimaliste, performance proche de Nginx, et écosystème de plugins riche (HTTP/3, Brotli, rate limiting, OAuth2, fail2ban). Pour les développeurs et PME africaines qui veulent un reverse proxy production-ready avec un minimum de friction, Caddy bat Nginx en simplicité et offre des fonctionnalités modernes (HTTP/3 natif) sans plugin tiers. Voici le guide pratique 2026.

Ce guide général couvre l’écosystème complet. Les articles connexes détaillent : installation Caddy sur VPS, Caddy vs Nginx vs Traefik, headers sécurité CSP HSTS, rate limiting et fail2ban.

Pourquoi Caddy en 2026

  • HTTPS automatique via Let’s Encrypt, sans configuration. Renouvellement transparent.
  • Caddyfile lisible : 3 lignes pour servir un site avec HTTPS
  • HTTP/3 natif (QUIC) sans configuration : meilleur pour les utilisateurs mobiles africains
  • Reverse proxy stateful avec health checks, load balancing, sticky sessions
  • File server performant pour servir du statique
  • API REST de configuration pour automatisation
  • Plugins riches : OAuth2 proxy, rate limiting, IP filtering, geo blocking
  • Open-source Apache 2.0, écrit en Go (un binaire unique)

Caddy vs Nginx

Nginx reste plus utilisé en production en 2026 grâce à son inertie historique. Mais pour un nouveau projet, Caddy est généralement le meilleur choix : courbe d’apprentissage très douce, HTTPS qui marche sans réfléchir, configuration 5x plus courte. Voir notre comparatif détaillé.

Cas d’usage typiques

  • Reverse proxy devant Node.js, Go, PHP-FPM, Python WSGI
  • Servir un site Astro/Next.js statique buildé
  • Multi-domaine sur un seul VPS
  • Termination TLS pour Docker Compose stack
  • Edge proxy avec rate limiting et auth

Étape 1 — Installer Caddy

# Ubuntu/Debian
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

# Vérifier
caddy version
systemctl status caddy

Voir notre tutoriel installation détaillé.

Étape 2 — Premier Caddyfile

# /etc/caddy/Caddyfile

# Site statique
exemple.sn {
    root * /var/www/exemple.sn
    file_server
    encode gzip zstd
}

# Reverse proxy vers app Node.js
api.exemple.sn {
    reverse_proxy 127.0.0.1:3000
}

# Multi-blocks pour la même config
*.exemple.sn, exemple.sn {
    redir https://www.exemple.sn{uri}
}
sudo systemctl reload caddy
# HTTPS automatique apparaît en quelques secondes

Étape 3 — Headers et sécurité

api.exemple.sn {
    reverse_proxy 127.0.0.1:3000
    
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
        Permissions-Policy "geolocation=(), camera=(), microphone=()"
    }
}

Voir notre tutoriel headers sécurité.

Étape 4 — Compression et cache

exemple.sn {
    root * /var/www/site/dist
    file_server
    
    # Brotli + gzip + zstd
    encode gzip zstd
    
    # Cache long pour assets fingerprintés
    @assets path *.js *.css *.woff2 *.png *.jpg *.svg *.webp
    header @assets Cache-Control "public, max-age=31536000, immutable"
    
    # HTML pas caché
    @html path *.html
    header @html Cache-Control "public, max-age=0, must-revalidate"
}

Étape 5 — Reverse proxy avancé

api.exemple.sn {
    reverse_proxy {
        to 127.0.0.1:3000 127.0.0.1:3001 127.0.0.1:3002
        lb_policy round_robin
        health_uri /health
        health_interval 10s
        health_timeout 3s
        
        transport http {
            keepalive 30s
            keepalive_idle_conns 32
        }
        
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

Étape 6 — Rate limiting

Caddy a un plugin officieux caddy-ratelimit. Voir notre tutoriel rate limiting et fail2ban.

Étape 7 — Wildcard et DNS-01

Pour un certificat *.exemple.sn, Caddy utilise le DNS-01 challenge. Configuration via plugin DNS provider (Cloudflare, OVH, Gandi) :

# Builder Caddy avec plugin Cloudflare
xcaddy build --with github.com/caddy-dns/cloudflare

# Caddyfile
*.exemple.sn {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    reverse_proxy 127.0.0.1:3000
}

Étape 8 — JSON config et API

Caddy supporte aussi un format JSON natif (plus verbeux mais plus puissant) et une API REST de configuration sur localhost:2019. Pratique pour automatiser via Ansible ou un orchestrateur.

Adaptation Afrique de l’Ouest

Pour une PME ouest-africaine, Caddy supprime toute la complexité Nginx + Certbot + cron renouvellement. HTTP/3 améliore la perf perçue sur connexions mobiles 4G instables (très fréquentes en Afrique). Avec quelques lignes de Caddyfile, vous gérez 10 domaines, 5 reverse proxies, et la sécurité headers.

Erreurs fréquentes

ErreurCauseSolution
HTTPS challenge failDNS pas propagéVérifier dig, attendre, retenter
« too many requests » Let’s EncryptRate limit hitTester avec staging CA d’abord
502 Bad GatewayBackend pas démarréVérifier service backend, port
Permission denied port 80/443Pas root, capability manquantesetcap cap_net_bind_service ou systemd

Dans la continuité

Etape 1 : Comprendre pourquoi Caddy bat Nginx pour la majorite des projets en 2026

Caddy embarque TLS automatique via Let’s Encrypt et ZeroSSL, HTTP/3 active par defaut, configuration declarative en Caddyfile lisible, et rechargement a chaud sans interruption. Pour un VPS qui sert un Outline, un Mailcow webmail, un Wazuh dashboard et un blog WordPress, Caddy elimine 80 pour cent de la friction Nginx (certbot, snippets, redemarrages). Tarification : Caddy est entierement open source sous licence Apache 2.0, zero cout de licence.

Resultat attendu de ce tutoriel : un Caddy en production qui sert 4 sous-domaines en HTTPS automatique, avec headers de securite stricts et logs structures.

Etape 2 : Installer Caddy sur Debian 12 ou Ubuntu 24.04

Sur un VPS frais, installez Caddy depuis le depot officiel Cloudsmith maintenu par l’equipe Caddy. Cela vous garantit la derniere version stable (2.8.x en mai 2026) et les modules officiels.

# Installation Caddy sur Debian 12 / Ubuntu 24.04
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' |   sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' |   sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy

Sortie attendue : Caddy installe en service systemd, ecoutant sur les ports 80 et 443. Verifiez avec systemctl status caddy que le service est actif et n’a pas plante au demarrage.

Etape 3 : Pointer les DNS vers le serveur avant tout test TLS

Caddy demande un certificat Let’s Encrypt en defi HTTP-01 ou TLS-ALPN-01, ce qui exige que le domaine resolve deja vers l’IP du serveur. Creez les enregistrements A pour wiki, mail, siem, blog dans la zone DNS de votredomaine.sn pointant vers l’IPv4 du VPS, et idealement aussi des AAAA pour l’IPv6. Attendez 5 a 30 minutes la propagation.

# Verification rapide depuis Dakar via dig
dig +short wiki.votredomaine.sn
# Doit afficher l'IP de votre VPS

Si la resolution echoue, Caddy se mettra en boucle de retry et generera des erreurs Let’s Encrypt rate-limit. Mieux vaut attendre que dig reponde correctement avant de lancer Caddy avec un nouveau domaine.

Etape 4 : Ecrire un Caddyfile minimal pour un seul site

Le Caddyfile vit dans /etc/caddy/Caddyfile. Pour un premier test, redirigez un domaine vers une appli locale ecoutant sur le port 3000 (Outline, par exemple).

wiki.votredomaine.sn {
    reverse_proxy localhost:3000
    encode zstd gzip
}

Rechargez avec sudo systemctl reload caddy. Caddy detecte le nouveau domaine, demande un certificat Let’s Encrypt en quelques secondes et commence a servir HTTPS. Verifiez dans un navigateur, le cadenas doit etre vert et le certificat valide 90 jours.

Etape 5 : Ajouter plusieurs sites avec headers de securite stricts

Pour servir plusieurs apps avec des headers durcis (HSTS, X-Frame-Options, CSP, Permissions-Policy), structurez le Caddyfile avec des snippets reutilisables.

(secure_headers) {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
        Permissions-Policy "geolocation=(), microphone=(), camera=()"
        -Server
    }
}

wiki.votredomaine.sn {
    import secure_headers
    reverse_proxy localhost:3000
}

siem.votredomaine.sn {
    import secure_headers
    reverse_proxy localhost:443 {
        transport http {
            tls_insecure_skip_verify
        }
    }
}

Sortie attendue : les deux sous-domaines repondent en HTTPS avec les headers de securite presents (verifiez avec curl -I https://wiki.votredomaine.sn). Le snippet secure_headers evite la duplication.

Etape 6 : Activer HTTP/3 et la compression Brotli pour les performances

Caddy 2.8+ active HTTP/3 par defaut sur le port UDP 443. Verifiez que votre pare-feu (UFW, iptables, security group cloud) ouvre bien UDP 443 en plus de TCP 80 et TCP 443. Sans cela, HTTP/3 echouera silencieusement et les clients basculeront en HTTP/2.

# Verifier l'ouverture UDP 443 sur Debian/Ubuntu
sudo ufw allow 443/udp
sudo ufw status verbose

Sortie attendue : la regle 443/udp ALLOW dans le statut UFW. Testez ensuite l’activation HTTP/3 avec curl --http3 -I https://wiki.votredomaine.sn qui doit repondre HTTP/3 200. Les utilisateurs en 4G a Dakar ou Abidjan beneficient d’une latence reduite de 15 a 30 pour cent vs HTTP/2.

Etape 7 : Configurer les logs structures en JSON pour Wazuh ou Loki

Pour exploiter les logs Caddy dans un SIEM, basculez du format console au format JSON et stockez les logs dans un fichier dedie par site.

wiki.votredomaine.sn {
    log {
        output file /var/log/caddy/wiki-access.log {
            roll_size 50mb
            roll_keep 10
        }
        format json
    }
    reverse_proxy localhost:3000
}

Sortie attendue : un fichier JSON avec une ligne par requete contenant timestamp, methode, URL, code reponse, taille, user agent, IP cliente. Wazuh et Loki ingerent nativement ce format pour des dashboards de trafic et detection d’anomalies.

Etape 8 : Mettre en place le rate limiting et la protection anti-bot

Caddy n’a pas de rate limiting natif dans son binaire standard, mais le plugin caddy-ratelimit de Mholt s’ajoute via xcaddy. Recompilez Caddy avec ce module pour limiter par exemple les tentatives de login WordPress ou le bruteforce SSH expose en HTTPS.

# Reconstruire Caddy avec le plugin ratelimit
sudo apt install -y golang-go
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
~/go/bin/xcaddy build --with github.com/mholt/caddy-ratelimit
sudo mv caddy /usr/bin/caddy
sudo systemctl restart caddy

Configurez ensuite une limite de 10 requetes par minute par IP sur /wp-login.php ou /api/auth. Resultat attendu : les bots qui martelent vos endpoints sensibles recoivent un 429 Too Many Requests apres la 11e requete.

Etape 9 : Surveiller Caddy avec Prometheus et alerter sur les erreurs TLS

Caddy expose un endpoint d’admin sur localhost:2019 avec des metriques Prometheus. Branchez Prometheus et Grafana pour visualiser le trafic, les codes 5xx, les renouvellements TLS, l’usage CPU/RAM. Alertez quand un renouvellement Let’s Encrypt echoue ou quand le taux de 5xx depasse 1 pour cent sur 5 minutes.

Sur le même thème, voyez aussi notre tutoriel sur l’installation Mailcow (compatible Caddy en frontal), et notre guide Wazuh pour la conformite (PCI, GDPR, ARTCI au Senegal).

Etape 10 : Mettre en place le wildcard DNS-01 pour les sous-domaines dynamiques

Si vous creez regulierement de nouveaux sous-domaines (apps internes, environnements de staging), demander un certificat HTTP-01 pour chaque cas devient lourd. Passez au defi DNS-01 wildcard via votre fournisseur DNS (Cloudflare, OVH, Gandi). Compilez Caddy avec le module DNS de votre provider, configurez l’API token, et obtenez un seul certificat *.votredomaine.sn valide pour tous les sous-domaines.

# Compilation Caddy avec module Cloudflare DNS
~/go/bin/xcaddy build --with github.com/caddy-dns/cloudflare
sudo mv caddy /usr/bin/caddy && sudo systemctl restart caddy

Sortie attendue : un binaire Caddy enrichi du provider DNS. Dans le Caddyfile, declarez la zone wildcard et le token via la directive tls. Resultat : ajout d’un nouveau sous-domaine = ajout d’un bloc Caddyfile et reload, sans aucune validation HTTP-01 individuelle.

Etape 11 : Sauvegarder la configuration et les certificats Caddy

Caddy stocke ses certificats dans /var/lib/caddy/.local/share/caddy. Sauvegardez ce dossier en plus du Caddyfile pour pouvoir restaurer rapidement sans redemander 50 certificats Let’s Encrypt (et risquer un rate limit). Le rate limit Let’s Encrypt 2026 reste a 50 certificats par domaine racine et par semaine, c’est vite atteint sur un audit ou un incident.

# Sauvegarde quotidienne via cron
0 4 * * * tar czf /mnt/backups/caddy-$(date +\%Y\%m\%d).tar.gz   /etc/caddy /var/lib/caddy /var/log/caddy &&   find /mnt/backups -name "caddy-*.tar.gz" -mtime +14 -delete

Sortie attendue : une archive .tar.gz par jour, retention 14 jours. Stockez ces backups hors du serveur (S3, Backblaze B2). En cas de reinstallation, vous restaurez le dossier et Caddy reprend immediatement avec ses certificats en cache, sans nouveau defi.

Partager