Configurer Let's Encrypt SSL/TLS pour Nginx sur Debian 12 et Ubuntu 24.04
Obtenez et renouvelez automatiquement des certificats TLS gratuits avec Certbot pour Nginx sur Debian 12 ou Ubuntu 24.04. Ce guide couvre la configuration DNS, l'installation de Certbot, la redirection HTTP vers HTTPS, le durcissement TLS, HTTP/2, HSTS et la fin du service OCSP.
Ce tutoriel vous guide dans l'obtention d'un certificat TLS gratuit auprès de Let's Encrypt avec Certbot, la configuration de Nginx pour HTTPS et la mise en place du renouvellement automatique.
Si vous n'avez pas encore installé Nginx, commencez par Installer Nginx sur Debian 12 et Ubuntu 24.04 depuis le dépôt officiel. Pour une vue d'ensemble de la gestion de Nginx sur un VPS, consultez Administration Nginx sur un VPS.
De quoi avez-vous besoin avant de demander un certificat ?
Avant que Certbot puisse émettre un certificat, votre domaine doit pointer vers l'adresse IP de votre serveur, et Nginx doit tourner avec un server block pour ce domaine. Let's Encrypt valide la propriété du domaine en envoyant une requête HTTP à votre serveur. Si le DNS ne résout pas vers votre VPS ou si Nginx n'écoute pas, le challenge échoue.
Vous avez besoin de :
- Un VPS sous Debian 12 ou Ubuntu 24.04 avec Nginx installé depuis le dépôt officiel (Installer Nginx sur Debian 12 et Ubuntu 24.04 depuis le dépôt officiel)
- Un nom de domaine enregistré (nous utiliserons
example.comtout au long du guide) - Un enregistrement A pointant
example.comvers l'adresse IPv4 de votre serveur - Un enregistrement AAAA pointant vers votre adresse IPv6 (si votre serveur en possède une)
- Le port 80 ouvert dans votre pare-feu (Certbot utilise les challenges HTTP-01)
- Un server block Nginx fonctionnel pour votre domaine (Nginx Server Blocks : héberger plusieurs domaines sur un VPS)
Configurer les enregistrements DNS
Créez un enregistrement A chez votre fournisseur DNS :
| Type | Nom | Valeur | TTL |
|---|---|---|---|
| A | example.com | 203.0.113.10 | 300 |
| AAAA | example.com | 2001:db8::1 | 300 |
Remplacez les adresses IP par celles de votre serveur. Définissez un TTL bas (300 secondes) pendant la configuration pour que les changements se propagent rapidement. Vous pourrez l'augmenter par la suite.
Vérifier la résolution DNS
Attendez quelques minutes après la création des enregistrements, puis vérifiez depuis votre machine locale (pas depuis le serveur) :
dig +short example.com A
dig +short example.com AAAA
Vous devriez voir les adresses IP de votre serveur dans la sortie. Si vous ne voyez rien ou une IP différente, l'enregistrement ne s'est pas encore propagé. Patientez et réessayez.
Contrôlez que Nginx répond sur le port 80 depuis votre machine locale :
curl -I http://example.com
Vous devriez obtenir une réponse HTTP/1.1 200 OK avec Server: nginx. Si la connexion expire, vérifiez vos règles de pare-feu.
Comment installer Certbot sur Debian 12 et Ubuntu 24.04 ?
Installez Certbot et son plugin Nginx depuis le dépôt de paquets de votre distribution avec apt. Le plugin Nginx permet à Certbot de modifier automatiquement vos server blocks pour activer TLS.
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
Assurez-vous l'installation :
certbot --version
Sur Debian 12, cela installe Certbot 2.1.0. Sur Ubuntu 24.04, vous obtenez Certbot 2.9.0. Les deux versions fonctionnent pour tout ce qui est présenté dans ce tutoriel.
À noter : si vous avez installé Nginx depuis le dépôt officiel nginx.org (comme recommandé dans Installer Nginx sur Debian 12 et Ubuntu 24.04 depuis le dépôt officiel), le plugin Certbot pour Nginx fonctionnera sans configuration supplémentaire. Il détecte les server blocks dans /etc/nginx/conf.d/ et /etc/nginx/sites-enabled/.
Comment obtenir un certificat Let's Encrypt pour Nginx ?
Lancez certbot --nginx avec votre nom de domaine. Certbot contacte Let's Encrypt, prouve que vous contrôlez le domaine via un challenge HTTP-01, obtient le certificat et modifie votre server block Nginx pour l'utiliser. L'ensemble du processus prend environ 30 secondes.
sudo certbot --nginx -d example.com -d www.example.com
Certbot vous demandera votre adresse e-mail (pour les rappels de renouvellement) et votre accord avec les conditions d'utilisation. Il effectue ensuite les opérations suivantes :
- Place un fichier de challenge HTTP-01 dans votre racine web
- Demande à Let's Encrypt de le vérifier
- Télécharge le certificat signé
- Modifie votre server block Nginx pour ajouter les directives TLS
- Recharge Nginx
Confirmez que le certificat a été émis :
sudo ls -la /etc/letsencrypt/live/example.com/
Vous devriez voir :
lrwxrwxrwx 1 root root ... cert.pem -> ../../archive/example.com/cert1.pem
lrwxrwxrwx 1 root root ... chain.pem -> ../../archive/example.com/chain1.pem
lrwxrwxrwx 1 root root ... fullchain.pem -> ../../archive/example.com/fullchain1.pem
lrwxrwxrwx 1 root root ... privkey.pem -> ../../archive/example.com/privkey1.pem
Ce sont des liens symboliques. fullchain.pem contient votre certificat plus la chaîne de l'autorité de certification intermédiaire. privkey.pem est votre clé privée.
Contrôlez que Nginx tourne avec la nouvelle configuration :
sudo nginx -t && sudo systemctl status nginx
nginx -t teste la syntaxe de la configuration. S'il affiche test is successful, la configuration est valide.
Que modifie Certbot dans votre configuration Nginx ?
Certbot ajoute plusieurs lignes à votre server block. Voici ce qu'il insère (les lignes marquées # managed by Certbot) :
server {
server_name example.com www.example.com;
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# ... your existing location blocks ...
}
Le fichier options-ssl-nginx.conf contient les paramètres TLS par défaut de Certbot. Nous les remplacerons par des paramètres plus stricts dans la section de durcissement ci-dessous.
Certbot crée aussi un second server block pour rediriger HTTP vers HTTPS. Nous améliorerons cette redirection dans la section suivante.
Vous pouvez voir exactement ce qui a changé en comparant votre configuration :
sudo diff /etc/nginx/conf.d/example.com.conf /etc/nginx/conf.d/example.com.conf.bak 2>/dev/null || echo "No backup found. Certbot modifies in place."
Comment rediriger HTTP vers HTTPS dans Nginx ?
Tout le trafic HTTP doit être redirigé vers HTTPS avec une redirection 301 (permanente). Certbot peut ajouter cette redirection automatiquement, mais sa version par défaut utilise une instruction if à l'intérieur du server block existant. C'est un anti-pattern dans Nginx. Un server block dédié est plus propre et plus fiable.
Remplacez la redirection de Certbot par un server block séparé. Éditez votre fichier de configuration (le chemin dépend de votre installation ; généralement /etc/nginx/conf.d/example.com.conf) :
# HTTP -> HTTPS redirect (separate server block, not an if-statement)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Ce bloc va dans le même fichier que votre server block HTTPS, ou dans un fichier séparé. Assurez-vous de supprimer le bloc de redirection généré par Certbot pour éviter les doublons.
Testez et rechargez :
sudo nginx -t
sudo systemctl reload nginx
Assurez-vous la redirection depuis votre machine locale :
curl -I http://example.com
Sortie attendue :
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
Comment durcir les paramètres TLS pour un serveur de production ?
La configuration TLS par défaut de Certbot (options-ssl-nginx.conf) est volontairement conservative. Pour un serveur de production, vous voulez des paramètres plus stricts. Nous suivrons le profil Intermediate de Mozilla issu du SSL Configuration Generator, qui offre un bon équilibre entre sécurité et compatibilité client jusqu'à Firefox 27, Chrome 31 et Android 4.4.2.
Créez un fichier snippet que vous pourrez inclure (include) depuis chaque server block :
sudo nano /etc/nginx/snippets/tls-params.conf
Ajoutez le contenu suivant :
# TLS protocol versions, TLS 1.2 and 1.3 only
# TLS 1.0 and 1.1 are deprecated (RFC 8996)
ssl_protocols TLSv1.2 TLSv1.3;
# Ciphers, Mozilla Intermediate profile (January 2026)
# Source: https://ssl-config.mozilla.org/
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# DH parameters, 2048-bit, RFC 7919 ffdhe2048
ssl_dhparam /etc/nginx/dhparam.pem;
# Session settings
ssl_session_timeout 1d;
ssl_session_cache shared:TLS:10m;
ssl_session_tickets off;
# HSTS, tell browsers to always use HTTPS (2 years)
# Only add includeSubDomains if ALL subdomains use HTTPS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# Hide Nginx version in error pages and headers
server_tokens off;
Générez le fichier de paramètres DH (cela prend quelques secondes) :
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
Confirmez que le fichier a été créé :
sudo ls -la /etc/nginx/dhparam.pem
Mettez maintenant à jour votre server block HTTPS pour utiliser ces paramètres au lieu des valeurs par défaut de Certbot. Supprimez la ligne include /etc/letsencrypt/options-ssl-nginx.conf; et la ligne ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;. Remplacez-les par :
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS hardening (replaces Certbot defaults)
include snippets/tls-params.conf;
# ... your location blocks ...
}
Testez et rechargez :
sudo nginx -t
sudo systemctl reload nginx
Quelles versions TLS et quels chiffrements utiliser ?
Mozilla publie trois profils TLS. Voici la comparaison :
| Profil | Protocoles | Client le plus ancien compatible | Cas d'usage |
|---|---|---|---|
| Modern | TLS 1.3 uniquement | Firefox 63, Chrome 70, Android 10 | Services où tous les clients sont récents |
| Intermediate | TLS 1.2 + 1.3 | Firefox 27, Chrome 31, Android 4.4 | Serveurs web généralistes |
| Old | TLS 1.0 + 1.1 + 1.2 + 1.3 | Firefox 1, Chrome 1, IE 8 | Systèmes hérités uniquement |
Utilisez Intermediate sauf raison spécifique de faire autrement. Ce profil couvre plus de 99,9 % des navigateurs actuels tout en excluant les protocoles faibles. TLS 1.0 et 1.1 ont été officiellement dépréciés par la RFC 8996 en mars 2021.
La liste de chiffrements dans notre snippet n'utilise que des chiffrements AEAD (GCM et ChaCha20-Poly1305). ssl_prefer_server_ciphers off laisse le client choisir son chiffrement préféré. C'est la recommandation de Mozilla, car les clients modernes font de meilleurs choix qu'une préférence statique côté serveur.
Let's Encrypt supporte-t-il encore l'agrafage OCSP ?
Non. Let's Encrypt a arrêté son service OCSP (Online Certificate Status Protocol) le 6 août 2025. Les certificats émis après mai 2025 ne contiennent plus d'URL de répondeur OCSP. Le statut de révocation est désormais publié exclusivement via des listes de révocation de certificats (CRL). Si vous n'utilisez que des certificats Let's Encrypt, supprimez toute directive ssl_stapling de votre configuration Nginx.
Voici la chronologie :
- Décembre 2024. Let's Encrypt a annoncé le plan d'abandon de l'OCSP.
- 30 janvier 2025. Les certificats demandant l'extension OCSP Must-Staple ont commencé à échouer.
- 7 mai 2025. Les nouveaux certificats ont cessé d'inclure les URL de répondeur OCSP. Les URL CRL ont été ajoutées à la place.
- 6 août 2025. Le service OCSP a été complètement arrêté. Tous les certificats précédemment émis avec des URL OCSP ont depuis expiré.
Si vous voyez ssl_stapling on; ou ssl_stapling_verify on; dans un guide ou un snippet de configuration, c'est un conseil obsolète pour les utilisateurs de Let's Encrypt. Ces directives sont inoffensives (Nginx les ignore silencieusement en l'absence d'URL de répondeur OCSP), mais elles ajoutent de l'encombrement inutile. Supprimez-les.
Si vous utilisez des certificats d'une autre autorité de certification qui fournit encore l'OCSP, ces directives restent valides pour ces certificats.
Pourquoi Let's Encrypt a-t-il abandonné l'OCSP ? Deux raisons. L'OCSP est un risque pour la vie privée : à chaque fois qu'un navigateur vérifiait la révocation d'un certificat via OCSP, l'autorité de certification apprenait quel site était visité et depuis quelle adresse IP. À son pic, le service OCSP de Let's Encrypt traitait 340 milliards de requêtes par mois. Le passage aux CRL élimine cette fuite de données privées. Les CRL sont téléchargés en masse par les navigateurs, donc aucune requête individuelle n'est envoyée à l'autorité de certification pour chaque visite.
Comment activer HTTP/2 avec Nginx ?
HTTP/2 multiplexe les requêtes sur une seule connexion, ce qui réduit la latence. Si vous avez installé Nginx depuis le dépôt officiel nginx.org (version 1.25.1 ou ultérieure), activez HTTP/2 avec la directive http2 dans votre server block.
Ajoutez http2 on; dans votre server block HTTPS :
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include snippets/tls-params.conf;
# ... your location blocks ...
}
La directive http2 on; a remplacé la syntaxe obsolète listen 443 ssl http2; dans Nginx 1.25.1. L'ancienne syntaxe fonctionne encore mais produit des avertissements de dépréciation dans le journal d'erreurs. Si vous utilisez le Nginx fourni par la distribution (1.22 sur Debian 12, 1.24 sur Ubuntu 24.04), utilisez l'ancienne syntaxe listen 443 ssl http2; à la place.
Testez et rechargez :
sudo nginx -t
sudo systemctl reload nginx
Contrôlez que HTTP/2 est actif :
curl -I --http2 -s https://example.com | head -1
Sortie attendue :
HTTP/2 200
Si vous voyez HTTP/1.1 à la place, vérifiez que http2 on; est bien dans le bon server block et que votre version de Nginx le supporte.
Comment fonctionne le renouvellement automatique des certificats ?
Les certificats Let's Encrypt expirent après 90 jours. Certbot installe un timer systemd (certbot.timer) qui vérifie deux fois par jour si un certificat arrive à moins de 30 jours de son expiration. Si c'est le cas, il le renouvelle automatiquement. Vous n'avez pas besoin de configurer une tâche cron.
Assurez-vous que le timer est actif :
systemctl status certbot.timer
Vous devriez voir Active: active (waiting) et une ligne indiquant la prochaine heure de déclenchement.
Vérifiez quand le prochain renouvellement aura lieu :
systemctl list-timers certbot.timer
Cela affiche les heures NEXT et LAST d'exécution.
Tester le renouvellement sans renouveler réellement
Lancez un essai à blanc pour vérifier que le processus de renouvellement fonctionne de bout en bout :
sudo certbot renew --dry-run
Cette commande contacte le serveur de staging de Let's Encrypt et simule un renouvellement complet. Si elle affiche Congratulations, all simulated renewals succeeded, votre configuration est correcte.
Configurer un hook de déploiement pour recharger Nginx
Quand Certbot renouvelle un certificat, Nginx doit être rechargé pour prendre en compte les nouveaux fichiers. Configurez un hook de déploiement (deploy hook) qui s'exécute uniquement après un renouvellement réussi :
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Ajoutez :
#!/bin/bash
/usr/bin/systemctl reload nginx
Rendez-le exécutable :
sudo chmod 700 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Confirmez les permissions :
ls -la /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
La sortie attendue affiche -rwx------ (seul root peut lire et exécuter).
Le répertoire de hooks deploy exécute les scripts uniquement après un renouvellement réussi, pas à chaque déclenchement du timer. Cela évite les rechargements inutiles.
Comment vérifier que votre configuration TLS est correcte ?
Après avoir terminé toutes les étapes ci-dessus, lancez ces commandes de vérification. Chacune vérifie un aspect différent de votre configuration.
Vérifier la chaîne de certificats avec OpenSSL
Depuis votre machine locale :
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | openssl x509 -noout -dates -subject -issuer
Sortie attendue :
notBefore=Mar 19 00:00:00 2026 GMT
notAfter=Jun 17 00:00:00 2026 GMT
subject=CN = example.com
issuer=C = US, O = Let's Encrypt, CN = R12
À noter : la date notAfter devrait être environ 90 jours après l'émission. L'émetteur (issuer) devrait être Let's Encrypt. Les intermédiaires RSA actuels sont R12 et R13. Pour les certificats ECDSA, cherchez E7 ou E8.
Vérifier la version TLS et le chiffrement utilisés
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | grep -E "Protocol|Cipher"
Résultat attendu :
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Si vous voyez TLSv1.2, c'est également correct. Cela dépend de la version d'OpenSSL que votre machine locale préfère.
Vérifier les en-têtes HTTPS
curl -I https://example.com
Recherchez :
HTTP/2 200
strict-transport-security: max-age=63072000; includeSubDomains
Si strict-transport-security est absent, vérifiez la ligne add_header dans votre snippet TLS. Le paramètre always garantit que l'en-tête est envoyé même sur les réponses d'erreur.
Résumé des commandes de vérification
| Commande | Ce qu'elle vérifie | Ce qu'il faut chercher |
|---|---|---|
dig +short example.com |
Résolution DNS | L'IP de votre serveur |
curl -I http://example.com |
Redirection HTTP | 301 avec Location: https:// |
curl -I https://example.com |
HTTPS + en-têtes | HTTP/2 200, en-tête HSTS |
openssl s_client -connect ... |
Chaîne de certificats, version TLS | Émetteur Let's Encrypt, TLSv1.2 ou 1.3 |
certbot renew --dry-run |
Processus de renouvellement | all simulated renewals succeeded |
systemctl status certbot.timer |
Timer de renouvellement auto | active (waiting) |
Tester avec SSL Labs
Pour un audit externe approfondi, soumettez votre domaine au SSL Labs Server Test. Avec la configuration de ce guide, vous devriez obtenir un score A ou A+. Le A+ nécessite HSTS, que nous avons activé dans le snippet TLS.
Configuration Nginx complète de référence
Voici le server block complet avec tous les paramètres de ce tutoriel combinés :
# HTTP -> HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS server block
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com www.example.com;
# Let's Encrypt certificate
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS hardening
include snippets/tls-params.conf;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
}
Et le snippet TLS dans /etc/nginx/snippets/tls-params.conf :
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:TLS:10m;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
server_tokens off;
Pour des en-têtes de sécurité supplémentaires comme Content-Security-Policy, X-Frame-Options et Permissions-Policy, consultez Durcissement de la sécurité Nginx sur Ubuntu et Debian.
Quelque chose ne fonctionne pas ?
Certbot affiche « Could not automatically find a matching server block »
Certbot recherche une directive server_name correspondant au domaine passé avec -d. Assurez-vous que votre fichier de server block est dans /etc/nginx/conf.d/ ou /etc/nginx/sites-enabled/ et contient server_name example.com;.
Certbot affiche « Connection refused » ou « Challenge failed » Le port 80 doit être ouvert. Vérifiez votre pare-feu :
sudo ufw status # if using UFW
sudo nft list ruleset # if using nftables
Vérifiez aussi que Nginx écoute sur le port 80 :
sudo ss -tlnp | grep ':80'
« SSL: error » dans le journal d'erreurs Nginx après modification des paramètres TLS Vous avez probablement une erreur de syntaxe dans la chaîne de chiffrements ou un chemin de fichier manquant. Vérifiez :
sudo nginx -t
sudo journalctl -u nginx -n 20 --no-pager
Le navigateur affiche « NET::ERR_CERT_DATE_INVALID » Le certificat a peut-être expiré. Vérifiez l'expiration :
sudo certbot certificates
S'il a expiré, forcez un renouvellement :
sudo certbot renew --force-renewal
certbot renew --dry-run échoue
Cause fréquente : le DNS du domaine ne pointe plus vers ce serveur, ou le port 80 est bloqué. Certbot a besoin d'un accès HTTP-01 pour le renouvellement.
HTTP/2 ne fonctionne pas
Vérifiez votre version de Nginx : nginx -v. Si elle est inférieure à 1.25.1, utilisez listen 443 ssl http2; au lieu de la directive séparée http2 on;. Si elle est en 1.25.1 ou supérieure, assurez-vous que http2 on; est bien dans le bon bloc server (pas dans http ou location).
Prêt à essayer ?
Hebergez vos applications web sur un VPS fiable. →