SSL — Certbot, Let’s Encrypt
Obtenir, installer et renouveler un certificat SSL gratuit avec Certbot et Let’s Encrypt.
Let’s Encrypt est une autorité de certification gratuite et open-source. Certbot est l’outil officiel pour interagir avec elle. Les certificats sont valides 90 jours et se renouvellent automatiquement.
Installation
Ubuntu / Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx
python3-certbot-nginxinstalle le plugin Nginx de Certbot qui modifie automatiquement la config du serveur. Pour Apache, utiliserpython3-certbot-apacheà la place.
Via Docker (serveur en conteneur)
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot/certbot certonly \
--webroot -w /var/www/monsite -d exemple.comMount
/etc/letsencryptpour conserver les certificats entre les runs. L’option--webrootpasse par un fichier dans la racine web (.well-known/acme-challenge/) au lieu de toucher au serveur lui-même.
Obtenir un certificat
Cas simple (Nginx détecté automatiquement)
sudo certbot --nginx -d exemple.com -d www.exemple.comCertbot :
- Vérifie que
exemple.cometwww.exemple.compointent vers le serveur. - Demande le domaine à inclure dans le certificat (SAN).
- Demande un email de récupération.
- Modifie le bloc
serverNginx (ajoute le SSL, ajoute le redirect HTTP → HTTPS).
Sans plugin Nginx (config manuelle)
sudo certbot certonly --webroot \
-w /var/www/exemple.com \
-d exemple.com -d www.exemple.comLes certificats sont stockés dans :
| Chemin | Contenu |
|---|---|
/etc/letsencrypt/live/<domain>/fullchain.pem | Certificat complet (intermédiaire + leaf) |
/etc/letsencrypt/live/<domain>/privkey.pem | Clé privée |
/etc/letsencrypt/live/<domain>/chain.pem | Certificats intermédiaires uniquement |
/etc/letsencrypt/live/<domain>/cert.pem | Certificat leaf uniquement |
Pour Nginx, utiliser
fullchain.pem(pascert.pemseul) commessl_certificate. Sans l’intermédiaire, les navigateurs anciens ne pourront pas valider la chaîne.
Configuration Nginx SSL
Pour la configuration détaillée Nginx (headers, gzip, blocs complets), voir Nginx. Voici le bloc SSL minimal :
server {
listen 443 ssl http2;
server_name exemple.com www.exemple.com;
ssl_certificate /etc/letsencrypt/live/exemple.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exemple.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# ... configuration de l'application ...
}
# Redirect HTTP → HTTPS
server {
listen 80;
server_name exemple.com www.exemple.com;
return 301 https://$host$request_uri;
}HSTS (HTTP Strict Transport Security)
Forcer les navigateurs à utiliser HTTPS sur une durée donnée :
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
includeSubDomainsétend la règle à tous les sous-domaines.preloadpermet de soumettre le domaine à la liste HSTS intégrée aux navigateurs (chrome://settings/security). Ne jamais activer le preload tant qu’on n’est pas sûr de pouvoir maintenir HTTPS partout — un domaine en preload ne peut pas en être retiré rapidement.
Renouvellement automatique
Via le timer systemd (recommandé)
Certbot installe automatiquement un timer systemd :
# Vérifier le status du timer
systemctl status certbot.timer
# Déclencher un renouvellement manuel (uniquement si < 30 jours restants)
sudo certbot renewLe timer exécute certbot renew deux fois par jour. Un certificat est renouvelé s’il reste moins de 30 jours.
Avec cron (alternative)
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
--post-hookexécute une commande après chaque renouvellement réussi, même si aucun certificat n’a changé. Pour éviter les recharges inutiles, utiliser--deploy-hook(exécuté uniquement quand un certificat est réellement renouvelé) :
0 3 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"Test à blanc
sudo certbot renew --dry-runÀ lancer au moins une fois par mois. Le
--dry-runsimule le renouvellement sans modifier les certificats. Idéal pour vérifier que le--deploy-hookfonctionne (ex. reload Nginx, recharger un service).
Vérification et dépannage
Lister les certificats installés
certbot certificatesAffiche pour chaque certificat : le nom, les domaines, la date d’expiration, le chemin vers les fichiers.
Tester la config Nginx
sudo nginx -tToujours lancer nginx -t avant systemctl reload nginx. Un reload sur une config invalide ne redémarre pas — les anciens workers continuent de servir la config précédente.
Tester le certificat en ligne
# Via OpenSSL (local)
echo | openssl s_client -connect exemple.com:443 -servername exemple.com 2>/dev/null | \
openssl x509 -noout -dates -subject
# Vérifier la chaîne complète
echo | openssl s_client -connect exemple.com:443 -servername exemple.com 2>/dev/null | \
openssl x509 -noout -text | grep -A 1 "CA:"Erreurs courantes
| Erreur | Cause | Solution |
|---|---|---|
Failed authorization procedure. No service is listening on port 443 | Le serveur ne répond pas sur le port 443 | Vérifier que Nginx écoute bien sur 443 (ss -tlnp | grep 443) |
Failed authorization procedure. DNS problem | Le domaine ne pointe pas vers le serveur | Vérifier l’enregistrement A avec dig exemple.com |
Certificate is about to expire | Renouvellement automatique cassé | Lancer certbot renew --dry-run pour diagnostiquer |
nginx: [emerg] BIO_new_file ... failed | Chemin du certificat invalide après renouvellement | Vérifier les liens symboliques dans /etc/letsencrypt/live/ |
403 Forbidden sur .well-known/acme-challenge/ | Permissions du webroot | S’assurer que www-data (ou l’user Nginx) peut écrire dans le webroot |
| Certificat invalide pour un autre domaine | Demander un nouveau certificat avec --nginx ou --manual | Recréer le certificat avec les bons domaines (-d) |
Le log Certbot se trouve dans
/var/log/letsencrypt/letsencrypt.log. En cas d’erreur obscure,certbot --debugaffiche les détails complets.
Certbot en contexte Docker
Lorsque l’infrastructure tourne entièrement en Docker, Certbot peut être lancé dans un conteneur éphémère :
docker run -it --rm \
-p 80:80 -p 443:443 \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
-v /etc/nginx/conf.d:/etc/nginx/conf.d \
certbot/certbot certonly \
--nginx -d exemple.comAttention : Certbot modifie les fichiers de config Nginx montés depuis l’hôte. Dans un environnement Docker complexe (Nginx dans un autre conteneur), préférer
--webrootavec un volume partagé vers le répertoire du webroot du conteneur Nginx.
Pitfalls fréquents
| Piège | Conséquence | Prévention |
|---|---|---|
Oublier www dans les domaines | Le sous-domaine www.exemple.com n’a pas de certificat | Lister tous les domaines à -d dès la première commande |
ssl_certificate pointe vers cert.pem seul | Chaîne incomplète, erreur sur anciens navigateurs | Toujours fullchain.pem |
| Timer systemd désactivé | Pas de renouvellement automatique | systemctl enable --now certbot.timer |
--post-hook sans --quiet | Notifications inutiles dans les logs cron | certbot renew --quiet --deploy-hook "..." |
| Domaine en preload sans HTTPS partout | Le navigateur refuse de se connecter en HTTP sur un sous-domaine | Ne pas preloader avant d’avoir HTTPS sur TOUS les sous-domaines |
| Révoquer un certificat pour le réutiliser | Rate-limit Let’s Encrypt (5 certificats/heure) | Supprimer le certificat avec certbot delete au lieu de révoquer |
Rate-limits Let’s Encrypt : 5 certificats par semaine par domaine, 10 échecs d’enregistrement par heure, 30 certificats par domaine par semaine. En cas de dépassement, attendre la fin de la période ou utiliser un staging environment (
--staging) pour les tests.