Call-Informatique
Call-Informatique
Le média tech
 HTTPS avec Certbot et Nginx : configuration avancée et harden...
CybersécuritéGuides9 min de lecture

HTTPS avec Certbot et Nginx : configuration avancée et harden...

Configuration complète de Certbot avec Nginx : certificats Let's Encrypt, hardening TLS 1.3, en-têtes de sécurité, renouvellement automatisé et dépannage avancé.

HTTPS avec Certbot et Nginx : configuration avancée et hardening SSL

Ce guide couvre l'installation de Certbot, l'obtention de certificats Let's Encrypt, le durcissement de la configuration TLS sur Nginx et la mise en place d'un monitoring de renouvellement. On cible une note A+ sur SSL Labs.

Pré-requis

  • Serveur Ubuntu 22.04 LTS ou Debian 12 avec accès root
  • Nginx installé et opérationnel
  • Nom de domaine avec enregistrement DNS A et AAAA (si IPv6) pointant vers le serveur
  • Ports 80 et 443 ouverts (pare-feu et éventuel security group cloud)

Vérification rapide :

bash
## Confirmer que Nginx répond et que le DNS est résolu
nginx -v
curl -sI http://mondomaine.fr | head -5
dig +short mondomaine.fr

Installation de Certbot via Snap

Snap garantit une version à jour indépendante des dépôts de la distribution.

bash
## Installer et mettre à jour le runtime Snap
sudo snap install core && sudo snap refresh core

## Supprimer toute version apt résiduelle
sudo apt remove certbot -y 2>/dev/null

## Installer Certbot avec le plugin Nginx
sudo snap install —classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

## Vérifier l'installation
certbot —version
certbot plugins

La commande certbot plugins doit lister "nginx" parmi les plugins disponibles.

Configuration Nginx pré-Certbot

Avant de lancer Certbot, préparez un bloc serveur propre. Certbot modifiera ce fichier, mais partir d'une base solide évite les surprises.

bash
sudo nano /etc/nginx/sites-available/mondomaine.fr

Contenu :

nginx
server {
    listen 80;
    listen [::]:80;
    server_name mondomaine.fr www.mondomaine.fr;

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

    # Nécessaire pour la validation HTTP-01 de Let's Encrypt
    location /.well-known/acme-challenge/ {
        root /var/www/mondomaine.fr;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}
bash
## Activer le site et tester la configuration
sudo ln -sf /etc/nginx/sites-available/mondomaine.fr /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Obtention du certificat

Méthode automatique (recommandée)

bash
sudo certbot —nginx \
  -d mondomaine.fr \
  -d www.mondomaine.fr \
  —non-interactive \
  —agree-tos \
  —email admin@mondomaine.fr \
  —redirect

Options expliquées :

  • —non-interactive : pas de questions interactives
  • —redirect : redirection HTTP vers HTTPS automatique
  • —agree-tos : acceptation des conditions Let's Encrypt

Méthode manuelle (certonly)

Si vous préférez configurer Nginx vous-même :

bash
sudo certbot certonly —nginx \
  -d mondomaine.fr \
  -d www.mondomaine.fr \
  —agree-tos \
  —email admin@mondomaine.fr

Les certificats sont stockés dans /etc/letsencrypt/live/mondomaine.fr/.

Certificat wildcard (DNS-01)

Pour un certificat couvrant tous les sous-domaines :

bash
sudo certbot certonly \
  —manual \
  —preferred-challenges dns \
  -d "*.mondomaine.fr" \
  -d mondomaine.fr \
  —agree-tos \
  —email admin@mondomaine.fr

Certbot demandera d'ajouter un enregistrement DNS TXT _acme-challenge.mondomaine.fr. Ajoutez-le chez votre registrar, attendez la propagation (dig TXT _acme-challenge.mondomaine.fr), puis validez.

Pour automatiser les wildcards, utilisez un plugin DNS (Cloudflare, OVH, etc.) :

bash
## Exemple avec Cloudflare
sudo snap install certbot-dns-cloudflare

## Créer le fichier de credentials
sudo mkdir -p /etc/letsencrypt
cat << 'EOF' | sudo tee /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = VOTRE_TOKEN_CLOUDFLARE
EOF
sudo chmod 600 /etc/letsencrypt/cloudflare.ini

## Obtenir le certificat wildcard automatiquement
sudo certbot certonly \
  —dns-cloudflare \
  —dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "*.mondomaine.fr" \
  -d mondomaine.fr

Hardening SSL/TLS — Viser la note A+

La configuration par défaut de Certbot donne une note A. Pour atteindre A+, il faut renforcer plusieurs paramètres.

Générer des paramètres Diffie-Hellman

bash
## Générer des paramètres DH de 4096 bits (prend 2-5 minutes)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

Snippet de configuration SSL durci

Créez un fichier de paramètres SSL réutilisable :

bash
sudo nano /etc/nginx/snippets/ssl-hardening.conf
nginx
## Protocoles — TLS 1.2 minimum, TLS 1.3 préféré
ssl_protocols TLSv1.2 TLSv1.3;

## Suites de chiffrement modernes
## Le serveur choisit (pas le client)
ssl_prefer_server_ciphers on;
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';

## Paramètres Diffie-Hellman renforcés
ssl_dhparam /etc/nginx/dhparam.pem;

## Cache de session SSL
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

## OCSP Stapling — le serveur vérifie la validité du certificat
## pour que le navigateur n'ait pas à le faire
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

## HSTS — forcer HTTPS pendant 1 an, inclure les sous-domaines
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

## En-têtes de sécurité supplémentaires
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Configuration Nginx complète post-hardening

bash
sudo nano /etc/nginx/sites-available/mondomaine.fr
nginx
## Redirection HTTP vers HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name mondomaine.fr www.mondomaine.fr;
    return 301 https://$host$request_uri;
}

## Bloc HTTPS principal
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name mondomaine.fr www.mondomaine.fr;

    # Certificats Let's Encrypt
    ssl_certificate /etc/letsencrypt/live/mondomaine.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mondomaine.fr/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/mondomaine.fr/chain.pem;

    # Importer le snippet de hardening
    include /etc/nginx/snippets/ssl-hardening.conf;

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

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

    # Bloquer les fichiers sensibles
    location ~ /\. {
        deny all;
    }

    # Logs séparés
    access_log /var/log/nginx/mondomaine.fr.access.log;
    error_log /var/log/nginx/mondomaine.fr.error.log;
}
bash
## Tester et appliquer
sudo nginx -t && sudo systemctl reload nginx

Gestion du renouvellement

Vérifier le timer systemd

Certbot installé via Snap crée un timer systemd automatiquement :

bash
## Vérifier que le timer est actif
systemctl list-timers | grep certbot

## Ou via Snap
sudo snap logs certbot -n 20

Test de renouvellement

bash
## Simulation complète sans modification
sudo certbot renew —dry-run

Hook post-renouvellement

Pour recharger Nginx après chaque renouvellement :

bash
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
bash
#!/bin/bash
## Hook de déploiement — recharger Nginx après renouvellement
systemctl reload nginx
echo "$(date): Nginx rechargé après renouvellement du certificat" >> /var/log/letsencrypt-renewal.log
bash
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Script de monitoring d'expiration

Créez un script qui vérifie la date d'expiration et alerte si le certificat expire dans moins de 14 jours :

bash
sudo nano /usr/local/bin/check-ssl-expiry.sh
bash
#!/bin/bash
## Vérifier l'expiration du certificat SSL
## Usage : check-ssl-expiry.sh mondomaine.fr [jours_seuil]

DOMAIN="${1:-mondomaine.fr}"
THRESHOLD="${2:-14}"

EXPIRY_DATE=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null \
  | openssl x509 -noout -enddate 2>/dev/null \
  | cut -d= -f2)

if [ -z "$EXPIRY_DATE" ]; then
    echo "ERREUR: Impossible de récupérer le certificat de $DOMAIN"
    exit 2
fi

EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null || date -jf "%b %d %T %Y %Z" "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ "$DAYS_LEFT" -lt "$THRESHOLD" ]; then
    echo "ALERTE: Le certificat de $DOMAIN expire dans $DAYS_LEFT jours ($EXPIRY_DATE)"
    exit 1
else
    echo "OK: Le certificat de $DOMAIN expire dans $DAYS_LEFT jours ($EXPIRY_DATE)"
    exit 0
fi
bash
sudo chmod +x /usr/local/bin/check-ssl-expiry.sh

## Ajouter en cron pour vérification quotidienne
echo "0 8 * * * root /usr/local/bin/check-ssl-expiry.sh mondomaine.fr 14" \
  | sudo tee /etc/cron.d/check-ssl-expiry

Configuration Certbot avancée

Fichier CLI par défaut

Pour éviter de répéter les options à chaque commande :

bash
sudo nano /etc/letsencrypt/cli.ini
ini
## Configuration par défaut de Certbot
email = admin@mondomaine.fr
authenticator = nginx
installer = nginx
agree-tos = true
no-eff-email = true
key-type = ecdsa
elliptic-curve = secp384r1
rsa-key-size = 4096

Le paramètre key-type = ecdsa génère des certificats avec des clés elliptiques, plus petites et plus rapides que RSA.

Révoquer un certificat

bash
## Révoquer par chemin de certificat
sudo certbot revoke —cert-path /etc/letsencrypt/live/mondomaine.fr/cert.pem

## Supprimer les fichiers locaux après révocation
sudo certbot delete —cert-name mondomaine.fr

Certificats multi-domaines (SAN)

bash
sudo certbot —nginx \
  -d mondomaine.fr \
  -d www.mondomaine.fr \
  -d api.mondomaine.fr \
  -d blog.mondomaine.fr \
  —expand

L'option —expand ajoute les nouveaux domaines au certificat existant.

Dépannage

Erreur : "Could not automatically find a matching server block"

Certbot ne trouve pas de directive server_name correspondante dans Nginx.

bash
## Vérifier que le server_name est correct
grep -r server_name /etc/nginx/sites-enabled/

## Le domaine dans la commande certbot doit correspondre exactement

Erreur : "Connection refused" ou "Timeout" lors de la validation

Le port 80 est bloqué. Vérifications :

bash
## Tester si le port 80 est ouvert depuis l'extérieur
curl -sI http://mondomaine.fr/.well-known/acme-challenge/test

## Vérifier le pare-feu
sudo ufw status
sudo iptables -L -n | grep -E '80|443'

## Vérifier qu'aucun autre service n'utilise le port 80
sudo ss -tlnp | grep ':80'

Erreur : "Too many certificates already issued"

Let's Encrypt impose des limites de débit :

  • 50 certificats par domaine enregistré par semaine
  • 5 duplicatas par semaine
  • 300 nouveaux ordres par compte par 3 heures

Pour les tests, utilisez l'environnement staging :

bash
sudo certbot —nginx —staging -d mondomaine.fr

Erreur : "OCSP stapling not working"

bash
## Vérifier l'OCSP stapling
openssl s_client -connect mondomaine.fr:443 -status < /dev/null 2>/dev/null \
  | grep -A 4 "OCSP Response"

## Si "no response sent", vérifier le resolver DNS dans la config Nginx
## et que ssl_trusted_certificate pointe vers chain.pem

Erreur : "SSL routines:ssl3_read_bytes:tlsv1 alert protocol version"

Un client tente de se connecter avec TLS 1.0 ou 1.1 (désactivés par le hardening). C'est normal et voulu. Si vous devez supporter d'anciens clients :

nginx
## Déconseillé mais possible
ssl_protocols TLSv1.2 TLSv1.3;
## Ne PAS réactiver TLS 1.0/1.1

Vérifier la note SSL Labs en ligne de commande

bash
## Tester la configuration SSL depuis le terminal
curl -s "https://api.ssllabs.com/api/v3/analyze?host=mondomaine.fr&publish=off" \
  | jq '.endpoints[0].grade'

Résumé des fichiers et chemins

| Fichier | Rôle |

|————-|———|

| /etc/letsencrypt/live/domaine/fullchain.pem | Certificat complet (cert + intermédiaire) |

| /etc/letsencrypt/live/domaine/privkey.pem | Clé privée |

| /etc/letsencrypt/live/domaine/chain.pem | Certificat intermédiaire (OCSP) |

| /etc/letsencrypt/live/domaine/cert.pem | Certificat seul (rarement utilisé) |

| /etc/letsencrypt/renewal/domaine.conf | Configuration de renouvellement |

| /etc/letsencrypt/cli.ini | Options par défaut de Certbot |

| /etc/nginx/snippets/ssl-hardening.conf | Snippet de durcissement SSL |

| /etc/nginx/dhparam.pem | Paramètres Diffie-Hellman |

| /etc/letsencrypt/renewal-hooks/deploy/ | Scripts post-renouvellement |

Avec cette configuration, le certificat se renouvelle automatiquement, Nginx est rechargé à chaque renouvellement, et le monitoring prévient en cas de problème. La note A+ sur SSL Labs confirme que la chaîne de confiance et le chiffrement sont au niveau des bonnes pratiques actuelles.

Sur le même sujet

À lire aussi

#tutoriel#guide-technique#ssl-tls#lets-encrypt#nginx-hardening