Skip to Content
DevOpsSSL — Certbot, Let's Encrypt

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-nginx installe le plugin Nginx de Certbot qui modifie automatiquement la config du serveur. Pour Apache, utiliser python3-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.com

Mount /etc/letsencrypt pour conserver les certificats entre les runs. L’option --webroot passe 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.com

Certbot :

  1. Vérifie que exemple.com et www.exemple.com pointent vers le serveur.
  2. Demande le domaine à inclure dans le certificat (SAN).
  3. Demande un email de récupération.
  4. Modifie le bloc server Nginx (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.com

Les certificats sont stockés dans :

CheminContenu
/etc/letsencrypt/live/<domain>/fullchain.pemCertificat complet (intermédiaire + leaf)
/etc/letsencrypt/live/<domain>/privkey.pemClé privée
/etc/letsencrypt/live/<domain>/chain.pemCertificats intermédiaires uniquement
/etc/letsencrypt/live/<domain>/cert.pemCertificat leaf uniquement

Pour Nginx, utiliser fullchain.pem (pas cert.pem seul) comme ssl_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. preload permet 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 renew

Le 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-hook exé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-run simule le renouvellement sans modifier les certificats. Idéal pour vérifier que le --deploy-hook fonctionne (ex. reload Nginx, recharger un service).

Vérification et dépannage

Lister les certificats installés

certbot certificates

Affiche pour chaque certificat : le nom, les domaines, la date d’expiration, le chemin vers les fichiers.

Tester la config Nginx

sudo nginx -t

Toujours 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

ErreurCauseSolution
Failed authorization procedure. No service is listening on port 443Le serveur ne répond pas sur le port 443Vérifier que Nginx écoute bien sur 443 (ss -tlnp | grep 443)
Failed authorization procedure. DNS problemLe domaine ne pointe pas vers le serveurVérifier l’enregistrement A avec dig exemple.com
Certificate is about to expireRenouvellement automatique casséLancer certbot renew --dry-run pour diagnostiquer
nginx: [emerg] BIO_new_file ... failedChemin du certificat invalide après renouvellementVérifier les liens symboliques dans /etc/letsencrypt/live/
403 Forbidden sur .well-known/acme-challenge/Permissions du webrootS’assurer que www-data (ou l’user Nginx) peut écrire dans le webroot
Certificat invalide pour un autre domaineDemander un nouveau certificat avec --nginx ou --manualRecré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 --debug affiche 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.com

Attention : 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 --webroot avec un volume partagé vers le répertoire du webroot du conteneur Nginx.

Pitfalls fréquents

PiègeConséquencePrévention
Oublier www dans les domainesLe sous-domaine www.exemple.com n’a pas de certificatLister tous les domaines à -d dès la première commande
ssl_certificate pointe vers cert.pem seulChaîne incomplète, erreur sur anciens navigateursToujours fullchain.pem
Timer systemd désactivéPas de renouvellement automatiquesystemctl enable --now certbot.timer
--post-hook sans --quietNotifications inutiles dans les logs croncertbot renew --quiet --deploy-hook "..."
Domaine en preload sans HTTPS partoutLe navigateur refuse de se connecter en HTTP sur un sous-domaineNe pas preloader avant d’avoir HTTPS sur TOUS les sous-domaines
Révoquer un certificat pour le réutiliserRate-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.

Ressources