Skip to content
Learni
Voir tous les tutoriels
DevOps

Comment déployer Let's Encrypt en production en 2026

Read in English

Introduction

En 2026, Let's Encrypt reste l'étalon-or pour les certificats SSL/TLS gratuits et automatisés via le protocole ACME v2. Ce service, géré par l'ISRG, délivre des certificats valides 90 jours, renouvelables sans intervention manuelle. Pour un déploiement en production advanced, il faut dépasser les setups basiques : gérer les rate limits (50 certs/semaine/domaine), implémenter des challenges DNS-01 pour wildcards (*.example.com), intégrer des hooks pour reload sans downtime, et automatiser via systemd timers plutôt que cron obsolète.

Ce tutoriel vous guide pas à pas pour un serveur Ubuntu 24.04 avec Nginx : installation Certbot, config sécurisée, wildcard multi-domaine, monitoring des renews. Résultat : HTTPS robuste, scalable, compliant PCI-DSS. Un pro bookmarque ça pour ses déploiements critiques – zéro config générique, tout concret et testé.

Prérequis

  • Serveur Ubuntu 24.04 LTS (ou Debian 12+).
  • Domaine avec DNS editable (A/AAAA vers IP serveur, ports 80/443 ouverts).
  • Nginx 1.26+ installé (sudo apt install nginx).
  • Accès root/sudo.
  • Provider DNS supportant API (Cloudflare, Route53 pour wildcards).
  • Connaissances TypeScript/Go optionnelles pour hooks avancés.

Installer Certbot et plugins

terminal
# Mise à jour et installation Certbot avec plugins Nginx et DNS
sudo apt update
sudo apt install certbot python3-certbot-nginx python3-certbot-dns-cloudflare -y

# Vérifier version (doit être 2.10+ pour ACME v2)
certbot --version

# Créer répertoire pour renew hooks
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo chown -R root:www-data /etc/letsencrypt/renewal-hooks

Cette commande installe Certbot officiel depuis les dépôts Ubuntu, avec plugins pour Nginx (auto-config) et Cloudflare (DNS-01 wildcard). Le répertoire hooks prépare les scripts post-renew pour reload Nginx sans downtime. Évitez Snap : plus lent et problématique en conteneurs.

Configurer Nginx pour challenge HTTP-01 initial

Avant tout certificat, Nginx doit servir /.well-known/acme-challenge/ sur port 80. Pensez à ça comme une 'porte de vérification' : Let's Encrypt y dépose un token temporaire pour valider le domaine.

Config Nginx HTTP initiale

/etc/nginx/sites-available/default
server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/html;
    index index.html;

    # Challenge ACME Let's Encrypt
    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
        allow all;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

# Créer le répertoire webroot pour challenges
sudo mkdir -p /var/www/letsencrypt
sudo chown -R www-data:www-data /var/www/letsencrypt
sudo nginx -t && sudo systemctl reload nginx

Ce bloc server écoute sur 80, expose /.well-known/acme-challenge/ via webroot dédié pour éviter conflits app. Testez avec nginx -t. Piège : oublier chown bloque Certbot (permissions 755 requises).

Obtenir certificat initial HTTP-01

terminal
# Utiliser webroot pour contrôle total (pas --nginx qui modifie auto)
sudo certbot certonly \
  --webroot -w /var/www/letsencrypt \
  -d example.com -d www.example.com \
  --email admin@example.com \
  --agree-tos --no-eff-email \
  --staging  # Retirez --staging en prod après test

# Vérifier
sudo ls /etc/letsencrypt/live/example.com/

Webroot challenge est précis pour prod : Certbot place tokens dans /var/www/letsencrypt, sans stopper Nginx. --staging évite rate limits (quotas staging illimités). Piège : oubliez --webroot -w et ça échoue sur 'no server block'.

Activer HTTPS avec HSTS et OCSP

Maintenant, migrez vers SSL : redirigez HTTP→HTTPS, activez HSTS (HTTP Strict Transport Security) pour browsers, et stapling OCSP pour privacy. Analogie : HTTPS = tunnel chiffré, HSTS = cadenas permanent.

Config Nginx HTTPS complète

/etc/nginx/sites-available/default
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    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;

    ssl_protocols TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:le_nginx_SSL:10m;

    # HSTS (1 an)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    root /var/www/html;
    location / {
        try_files $uri $uri/ =404;
    }
}

sudo nginx -t && sudo systemctl reload nginx

Fullchain.pem = cert + chain intermédiaire ; privkey.pem = clé privée. TLSv1.3 only pour 2026 security. HSTS preload-ready ; OCSP stapling cache réponses revocation. Testez avec curl -I https://example.com. Piège : paths relatifs cassent tout.

Wildcard via DNS-01 (Cloudflare)

terminal
# Créer credentials Cloudflare (API token avec Zone:DNS:Edit)
sudo mkdir -p /etc/letsencrypt/cloudflare
cat > /etc/letsencrypt/cloudflare/cloudflare.ini << EOF
# Cloudflare API token
# Format: dns_cloudflare_api_token = YOUR_GLOBAL_API_TOKEN
EOF
sudo chmod 600 /etc/letsencrypt/cloudflare/cloudflare.ini

# Obtenir wildcard
sudo certbot certonly \
  --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/cloudflare.ini \
  -d '*.example.com' -d example.com \
  --email admin@example.com --agree-tos --no-eff-email --staging

# Propagation DNS ~60s

DNS-01 pour wildcards/subdomains illimités : Certbot ajoute TXT via API Cloudflare. Token > key (security 2026). Propagation lente ? Ajoutez --dns-cloudflare-propagation-seconds 120. Piège : mauvais perms sur .ini = 'auth error' fatal.

Hook post-renew pour reload Nginx

/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
# Hook exécuté après renew réussi
if [ "$RENEW_REASON" = "renewed" ]; then
    systemctl reload nginx
    logger "Let's Encrypt renewed: reloaded Nginx"
fi

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Ce hook deploy s'exécute post-renew si changé : reload (pas restart) = zéro downtime. Condition RENEW_REASON évite exéc inutile. Loggez pour monitoring. Piège : restart tue connexions actives.

Automatisation avec systemd timer

/etc/systemd/system/certbot.timer
[Unit]
Description=Run certbot twice daily

[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true

[Install]
WantedBy=timers.target

---

[Unit]
Description=Certbot Renewal
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet
---

sudo systemctl daemon-reload
sudo systemctl enable --now certbot.timer

Timer systemd > cron : précis, randomized (anti-thundering herd), persistent. Renew check 2x/jour (90j cert /2). --quiet supprime spam logs. Vérifiez systemctl status certbot.timer. Piège : sans daemon-reload, ignore unit.

Bonnes pratiques

  • Staging first : Toujours --staging pour tests, rate limits staging ∞.
  • Séparez keys : 700 perms sur privkey, jamais git.
  • Monitoring : Alertes sur /var/log/letsencrypt/letsencrypt.log via Logrotate + Prometheus.
  • Backup : certbot certificates --cert-name example.com --dump-all vers S3.
  • Rate limits : <5 failed/domaine/semaine ; utilisez staging.

Erreurs courantes à éviter

  • Port 80 bloqué : Firewall/Cloud bloquent challenge → 'Connection refused'.
  • DNS non propagé : Attendez 5min post-A record ; utilisez dig.
  • Permissions webroot : 755/www-data requis, sinon 'Permission denied'.
  • Wildcard sans DNS-01 : HTTP-01 impossible sur * → staging + API creds.

Pour aller plus loin

Approfondissez avec ACME v3 drafts, intégrez Traefik/Docker (Certbot companion). Découvrez nos formations DevOps Learni pour Kubernetes + Istio TLS auto.