Caddyfile : exemples de directives réutilisables
Bibliothèque d’exemples de Caddyfile à adapter. Les domaines (exemple.com), chemins et ports sont fictifs. Après chaque modification :
sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddyPour installer Caddy, voir Installer Caddy sur Ubuntu. Les commandes sont dans les principales commandes Caddy.
Réutiliser des blocs avec les snippets
Section intitulée « Réutiliser des blocs avec les snippets »Un snippet est un bloc nommé, défini une fois en haut du Caddyfile et inséré partout avec import. Les exemples ci-dessous sont écrits pour être utilisés ainsi.
(securite) { header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "strict-origin-when-cross-origin" -Server }}
exemple.com { import securite # …}
autre.exemple.com { import securite # …}Options globales
Section intitulée « Options globales »Le bloc sans adresse, placé tout en haut du fichier, définit les réglages communs à tous les sites.
{ # E-mail de contact pour les certificats Let's Encrypt email admin@exemple.com
# Protocoles : HTTP/1.1, HTTP/2 et HTTP/3 servers { protocols h1 h2 h3 }}Sécurité
Section intitulée « Sécurité »En-têtes de sécurité
Section intitulée « En-têtes de sécurité »(securite) { header { # Force HTTPS pendant un an Strict-Transport-Security "max-age=31536000" # Empêche le navigateur de deviner les types de fichiers X-Content-Type-Options "nosniff" # Interdit l'affichage dans une iframe d'un autre site X-Frame-Options "SAMEORIGIN" # Limite les informations envoyées dans l'en-tête Referer Referrer-Policy "strict-origin-when-cross-origin" # Désactive des fonctions du navigateur inutiles Permissions-Policy "camera=(), microphone=(), geolocation=()" # Masque la version du serveur -Server }}Politique de contenu (CSP)
Section intitulée « Politique de contenu (CSP) »Une CSP limite les origines autorisées pour les scripts, styles et images. Exemple strict pour un site statique sans ressources externes :
header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'"Testez toujours une CSP sur un site de test : une règle trop stricte bloque des fonctions du site. Les scripts en ligne exigent 'unsafe-inline' ou une empreinte.
Masquer les fichiers cachés
Section intitulée « Masquer les fichiers cachés »Bloque l’accès aux fichiers commençant par un point (.env, .git…), sauf /.well-known/ utilisé par les certificats et certains services :
(fichiers-caches) { @cachees { path */.* not path /.well-known/* } respond @cachees 404}Limiter la taille des envois
Section intitulée « Limiter la taille des envois »request_body { max_size 10MB}Protection de dossier
Section intitulée « Protection de dossier »Mot de passe (authentification basique)
Section intitulée « Mot de passe (authentification basique) »Générez d’abord un hash du mot de passe :
caddy hash-passwordCollez le résultat dans le Caddyfile. Ici seul le dossier /prive/ est protégé :
exemple.com { root * /var/www/site
basic_auth /prive/* { alice $2a$14$HASH_GENERE_PAR_CADDY_HASH_PASSWORD bob $2a$14$AUTRE_HASH }
file_server}Pour protéger tout le site, retirez le chemin : basic_auth { … }.
Restreindre à certaines adresses IP
Section intitulée « Restreindre à certaines adresses IP »(reseau-local) { @interdit not remote_ip 192.168.0.0/16 10.0.0.0/8 203.0.113.10 respond @interdit 403}
admin.exemple.com { import reseau-local reverse_proxy 127.0.0.1:9000}Derrière un autre proxy (CDN, répartiteur de charge), remote_ip voit l’adresse du proxy : utilisez alors client_ip après avoir déclaré les proxys de confiance (trusted_proxies).
Protéger un dossier ET restreindre par IP
Section intitulée « Protéger un dossier ET restreindre par IP »exemple.com { root * /var/www/site
@prive path /prive/* handle @prive { @interdit not remote_ip 192.168.0.0/16 respond @interdit 403 basic_auth { alice $2a$14$HASH } file_server }
file_server}Reverse proxy
Section intitulée « Reverse proxy »Cas simple
Section intitulée « Cas simple »app.exemple.com { reverse_proxy 127.0.0.1:3000}Caddy gère HTTPS, HTTP/2, HTTP/3 et les WebSockets sans configuration supplémentaire, et ajoute les en-têtes X-Forwarded-*.
Proxy avec en-têtes et réglages courants
Section intitulée « Proxy avec en-têtes et réglages courants »(proxy-app) { reverse_proxy 127.0.0.1:3000 { # Transmet l'adresse du visiteur à l'application header_up X-Real-IP {remote_host}
# Sans mise en mémoire tampon : utile pour le streaming et les événements serveur (SSE) flush_interval -1 }}Par défaut, Caddy transmet l’en-tête Host du visiteur à l’application. Si elle exige son propre nom d’hôte, ajoutez header_up Host {upstream_hostport}.
Proxy d’un sous-chemin
Section intitulée « Proxy d’un sous-chemin »handle_path retire le préfixe avant de transmettre la requête :
exemple.com { root * /var/www/site
handle_path /api/* { reverse_proxy 127.0.0.1:4000 }
file_server}Une requête /api/utilisateurs arrive à l’application sous la forme /utilisateurs.
Répartition de charge et surveillance
Section intitulée « Répartition de charge et surveillance »app.exemple.com { reverse_proxy 10.0.0.11:8080 10.0.0.12:8080 { lb_policy round_robin health_uri /sante health_interval 10s health_timeout 3s }}Les serveurs qui ne répondent pas sur /sante sont retirés de la rotation jusqu’à leur retour.
Application servie en HTTPS en interne
Section intitulée « Application servie en HTTPS en interne »reverse_proxy https://127.0.0.1:8443 { transport http { # À éviter en production : désactive la vérification du certificat tls_insecure_skip_verify }}Serveur web
Section intitulée « Serveur web »Site statique
Section intitulée « Site statique »exemple.com { root * /var/www/site encode zstd gzip file_server}Application monopage (SPA)
Section intitulée « Application monopage (SPA) »Renvoie index.html pour toutes les routes gérées côté navigateur :
exemple.com { root * /var/www/site encode zstd gzip try_files {path} /index.html file_server}Page 404 personnalisée
Section intitulée « Page 404 personnalisée »Le statut HTTP reste 404, ce qui est correct pour le référencement :
(erreur-404) { handle_errors { @notfound `{err.status_code} == 404` rewrite @notfound /404.html file_server }}Redirections
Section intitulée « Redirections »# www vers le domaine nuwww.exemple.com { redir https://exemple.com{uri} permanent}
# Ancienne page vers la nouvelleexemple.com { redir /ancienne-page /nouvelle-page permanent}Lister le contenu d’un dossier
Section intitulée « Lister le contenu d’un dossier »telechargements.exemple.com { root * /var/www/fichiers file_server browse}Optimisations
Section intitulée « Optimisations »Compression
Section intitulée « Compression »encode zstd gzipPour servir des fichiers déjà compressés (générés à l’avance par votre build), évitez la compression à la volée :
file_server { precompressed zstd br gzip}Cache navigateur
Section intitulée « Cache navigateur »Les fichiers dont le nom change à chaque version (avec une empreinte, comme app.a1b2c3.js) peuvent être gardés un an. Les pages HTML doivent être revalidées :
(cache) { @assets path /assets/* /_astro/* *.woff2 header @assets Cache-Control "public, max-age=31536000, immutable"
@html { path / *.html } header @html Cache-Control "no-cache"}Journaux d’accès avec rotation
Section intitulée « Journaux d’accès avec rotation »exemple.com { log { output file /var/log/caddy/exemple.log { roll_size 10MiB roll_keep 5 } format json }}Le dossier de logs doit exister et appartenir à l’utilisateur caddy :
sudo mkdir -p /var/log/caddysudo chown caddy:caddy /var/log/caddyExemple complet
Section intitulée « Exemple complet »Assemblage des snippets dans un Caddyfile :
{ email admin@exemple.com}
(securite) { header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "strict-origin-when-cross-origin" -Server }}
(fichiers-caches) { @cachees { path */.* not path /.well-known/* } respond @cachees 404}
(erreur-404) { handle_errors { @notfound `{err.status_code} == 404` rewrite @notfound /404.html file_server }}
(cache) { @assets path /assets/* /_astro/* header @assets Cache-Control "public, max-age=31536000, immutable"}
exemple.com { root * /var/www/site encode zstd gzip import securite import fichiers-caches import cache import erreur-404
basic_auth /prive/* { alice $2a$14$HASH }
handle_path /api/* { reverse_proxy 127.0.0.1:4000 }
file_server}
www.exemple.com { redir https://exemple.com{uri} permanent}
app.exemple.com { import securite reverse_proxy 127.0.0.1:3000}Pour aller plus loin
Section intitulée « Pour aller plus loin »- Liste des directives : caddyserver.com/docs/caddyfile/directives
- Snippets et import : caddyserver.com/docs/caddyfile/concepts#snippets