Tutoriel

Certificats SSL gratuits avec Let's Encrypt sur VPS

Sécurité & Monitoring8 min de lecture4 étapes

Le HTTPS n'est plus une option : navigateurs, SEO et clients l'exigent. Sur un VPS que vous maîtrisez de bout en bout, Let's Encrypt délivre des certificats reconnus, gratuits et renouvelés tout seuls. Ce guide couvre l'installation pas-à-pas de certbot avec Nginx, les certificats wildcard via DNS challenge Cloudflare, la vérification du renouvellement automatique avec le timer systemd, la surveillance de l'expiration et les erreurs les plus fréquentes — rate-limits ACME, port 80 bloqué, propagation DNS.

Sommaire· Pourquoi gérer Let's Encrypt soi-même sur un VPS1/10
  1. 01Pourquoi gérer Let's Encrypt soi-même sur un VPS
  2. 02Ce que vous gagnez en self-hébergeant la chaîne TLS
  3. 03Prérequis avant de commencer
  4. 04Installer certbot et obtenir un certificat Nginx
  5. 05Certificat wildcard avec DNS challenge Cloudflare
  6. 06Hardening TLS Nginx : TLS 1.2/1.3, HSTS et cipher suites
  7. 07Surveiller l'expiration des certificats
  8. 08Dépannage : rate-limits, port 80 bloqué, propagation DNS
  9. 09Comparatif : certbot vs acme.sh vs Caddy HTTPS automatique
  10. 10Tester avant la production

Pourquoi gérer Let's Encrypt soi-même sur un VPS

Let's Encrypt est une autorité de certification gratuite qui émet des certificats TLS validés par challenge automatisé (HTTP-01 ou DNS-01). Sur un hébergement mutualisé, vous subissez la config TLS du fournisseur : versions de protocole imposées, pas d'OCSP stapling, renouvellement opaque. Sur un VPS, vous tenez le certbot (ou acme.sh), le reverse proxy et la terminaison TLS. Vous décidez des protocoles (TLS 1.2/1.3 uniquement), des suites de chiffrement, du HSTS et de l'agrafage OCSP. Vous pouvez aussi émettre un certificat wildcard (*.votre-domaine.com) via le challenge DNS-01, couvrir plusieurs domaines dans un seul certificat (SAN), et brancher le renouvellement sur vos propres alertes. Bref : un contrôle total sur la sécurité de transport, condition d'un score A+ sur SSL Labs et d'une note de confiance maximale côté navigateur.

Ce que vous gagnez en self-hébergeant la chaîne TLS

  • Certificats 100% gratuits, valables 90 jours et renouvelés automatiquement sans intervention.
  • Wildcard *.votre-domaine.com possible via le challenge DNS-01 : un seul certificat pour tous vos sous-domaines.
  • Maîtrise complète de la config : TLS 1.3, suites de chiffrement modernes, HSTS et OCSP stapling.
  • Certificats SAN multi-domaines (votre-domaine.com, www.votre-domaine.com, api.votre-domaine.com) sur une même IP.
  • Renouvellement scriptable et observable : hooks de reload, alertes Slack/e-mail avant expiration.
  • Aucune dépendance à un panneau tiers : la même recette fonctionne sur tous vos VPS et environnements.

Prérequis avant de commencer

La terminaison TLS consomme très peu de ressources : un VPS 1 vCPU / 512 Mo à 1 Go de RAM suffit largement pour servir le HTTPS d'un ou plusieurs sites.

Côté réseau : votre nom de domaine doit pointer vers l'IP publique du VPS (enregistrement A/AAAA propagé). Vérifiez la propagation avant de lancer certbot : dig +short votre-domaine.com doit renvoyer l'IP de votre VPS. Un challenge qui échoue pour propagation DNS non terminée compte comme tentative et vous rapproche des rate-limits ACME.

Ports 80 et 443 ouverts dans le pare-feu — le port 80 est indispensable pour le challenge HTTP-01 (certbot y dépose un fichier de défi temporaire) :

ufw allow 80/tcp
ufw allow 443/tcp
ufw reload

Pour un certificat wildcard (*.votre-domaine.com), le challenge HTTP-01 ne suffit pas : prévoyez un token API auprès de votre fournisseur DNS (Cloudflare, OVH…) afin d'automatiser le challenge DNS-01.

Installer certbot et obtenir un certificat Nginx

  1. Installer certbot et le plugin Nginx

    Sur Debian/Ubuntu :

    apt update
    apt install -y certbot python3-certbot-nginx

    Le plugin python3-certbot-nginx lit votre config Nginx, y injecte la configuration TLS et remplace la directive listen 80 par un bloc 443 ssl. Si vous préférez garder la main sur Nginx, utilisez --nginx (automatique) ou --standalone / --webroot (manuel).

  2. Pointer le domaine et ouvrir les ports

    Créez un enregistrement A votre-domaine.com (et AAAA si IPv6) vers l'IP du VPS, puis autorisez le trafic web :

    ufw allow 80,443/tcp

    Confirmez la résolution avec dig +short votre-domaine.com avant d'aller plus loin — un challenge échoue toujours si le DNS ne pointe pas encore.

  3. Émettre le certificat avec le plugin Nginx

    La méthode la plus directe — certbot modifie votre vhost Nginx et gère le renouvellement :

    certbot --nginx -d votre-domaine.com -d www.votre-domaine.com

    Certbot vous demande un e-mail (alertes d'expiration) et vous invite à accepter les CGU. Il émet le certificat, modifie /etc/nginx/sites-available/<vhost>, ajoute un redirect HTTP→HTTPS et recharge Nginx sans coupure.

    Les fichiers sont déposés dans /etc/letsencrypt/live/votre-domaine.com/ : fullchain.pem (certificat + chaîne) et privkey.pem (clé privée).

  4. Vérifier le renouvellement automatique

    Certbot installe un timer systemd qui tente le renouvellement deux fois par jour :

    systemctl status certbot.timer

    Pour simuler un renouvellement sans émettre de nouveau certificat :

    certbot renew --dry-run

    Si la simulation réussit, votre chaîne de renouvellement est opérationnelle. Assurez-vous que Nginx se recharge après un renouvellement effectif — certbot ajoute automatiquement un hook --deploy-hook "systemctl reload nginx" dans /etc/letsencrypt/renewal/<domaine>.conf avec le plugin Nginx.

Certificat wildcard avec DNS challenge Cloudflare

Un certificat *.votre-domaine.com couvre tous vos sous-domaines avec un seul fichier. Il est obligatoire si vous créez des sous-domaines dynamiquement ou si vous ne voulez pas émettre un certificat par sous-domaine.

Le challenge HTTP-01 ne peut pas valider un wildcard — il faut le challenge DNS-01, qui demande à certbot de créer temporairement un enregistrement TXT _acme-challenge.votre-domaine.com.

Avec Cloudflare (API token) :

apt install -y python3-certbot-dns-cloudflare

Créez un fichier de credentials Cloudflare (permissions : 600) :

mkdir -p /etc/letsencrypt/cloudflare
chmod 700 /etc/letsencrypt/cloudflare
cat > /etc/letsencrypt/cloudflare/credentials.ini << 'EOF'
dns_cloudflare_api_token = VOTRE_TOKEN_API_CLOUDFLARE
EOF
chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

Émettez le certificat wildcard :

certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  -d votre-domaine.com \
  -d '*.votre-domaine.com'

Certbot crée l'enregistrement TXT, attend la propagation (par défaut 10 secondes — augmentable avec --dns-cloudflare-propagation-seconds 30), obtient le certificat, puis supprime l'enregistrement TXT.

Alternative avec acme.sh :

acme.sh --issue --dns dns_cf -d votre-domaine.com -d '*.votre-domaine.com'

acme.sh utilise la variable d'environnement CF_Token ou CF_Key + CF_Email selon votre mode d'authentification Cloudflare.

Hardening TLS Nginx : TLS 1.2/1.3, HSTS et cipher suites

Le plugin certbot configure un HTTPS fonctionnel, mais la configuration par défaut n'est pas optimale pour un score A+ SSL Labs. Voici les directives à ajouter dans votre bloc server (ou dans un fichier inclus comme /etc/nginx/snippets/ssl-params.conf) :

# Protocoles : TLS 1.2 minimum, TLS 1.3 recommandé
ssl_protocols TLSv1.2 TLSv1.3;

# Suites de chiffrement modernes (Mozilla Intermediate)
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;
ssl_prefer_server_ciphers off;

# Session TLS
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# HSTS (6 mois, sous-domaines inclus, preload)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

# En-têtes de sécurité complémentaires
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

Redirigez tout le port 80 vers 443 dans un bloc server séparé :

server {
    listen 80;
    server_name votre-domaine.com www.votre-domaine.com;
    return 301 https://$host$request_uri;
}

Rechargez sans coupure : nginx -s reload. Testez ensuite sur SSL Labs — vous devriez obtenir A+.

Surveiller l'expiration des certificats

Le renouvellement automatique peut échouer silencieusement : timer systemd désactivé, port 80 bloqué après une modification du pare-feu, token API Cloudflare révoqué… Un certificat expiré en production interrompt le service pour tous vos visiteurs.

Vérification manuelle :

echo | openssl s_client -connect votre-domaine.com:443 -servername votre-domaine.com 2>/dev/null \
  | openssl x509 -noout -dates

Script d'alerte par e-mail (à placer dans cron ou systemd) :

#!/bin/bash
# Alerte si le certificat expire dans moins de 14 jours
cert_file="/etc/letsencrypt/live/votre-domaine.com/fullchain.pem"
if ! openssl x509 -checkend 1209600 -noout -in "$cert_file" 2>/dev/null; then
  echo "ALERTE : certificat votre-domaine.com expire dans moins de 14 jours" \
    | mail -s "[SSL] Expiration imminente" [email protected]
fi

-checkend 1209600 correspond à 14 jours en secondes (14 × 86 400).

Avec Uptime Kuma : ajoutez un moniteur de type « Certificate Expiry » qui alerte à J-14 — sans script à maintenir.

Dépannage : rate-limits, port 80 bloqué, propagation DNS

Rate-limits ACME « too many certificates already issued »
Let's Encrypt limite à 5 certificats par domaine registrable et par semaine (enregistrement de type .com). Si vous atteignez cette limite en testant, basculez sur l'environnement de staging :

certbot --nginx --staging -d votre-domaine.com

Le staging délivre des certificats non reconnus par les navigateurs, mais sans limite de taux. Une fois votre configuration validée, supprimez le certificat de staging et rééemettez en production.

Port 80 bloqué
Le challenge HTTP-01 exige que Let's Encrypt atteigne http://votre-domaine.com/.well-known/acme-challenge/. Vérifiez :

curl -I http://votre-domaine.com/.well-known/acme-challenge/test
# attendu : 404 (la route existe, le fichier n'existe pas encore)
ufw status | grep 80

Si le port 80 est bloqué par un pare-feu amont (fournisseur cloud, Cloudflare en mode proxy), temporairement ouvrez-le ou basculez en challenge DNS-01.

Cloudflare proxy actif
Si votre domaine est derrière Cloudflare (icône orange), assurez-vous que le mode SSL de Cloudflare est Full (Strict) — en mode Flexible, Cloudflare communique avec votre serveur en HTTP et nginx qui redirige HTTP→HTTPS produit une boucle infinie (HTTP 525/526).

Propagation DNS insuffisante
Pour le challenge DNS-01, attendez au moins 60 secondes après la création du TXT avant de relancer certbot. Vérifiez :

dig TXT _acme-challenge.votre-domaine.com +short

Si la valeur n'apparaît pas encore, patientez avant de retenter.

Comparatif : certbot vs acme.sh vs Caddy HTTPS automatique

Faites défiler le tableau

Critèrecertbotacme.shCaddy (HTTPS auto)
Installation`apt install certbot`Script bash, aucune dépendance systèmeBinaire unique, inclus
Intégration Nginx/ApachePlugin natif (`--nginx`, `--apache`)Hooks `--install-cert` manuelsGère son propre reverse proxy
Wildcard DNS-01Via plugin DNS (`python3-certbot-dns-*`)Natif, nombreux providers DNS intégrésVia module `tls.dns.*` (Caddy v2)
RenouvellementTimer systemd (automatique)Cronjob généré à l'installationNatif, sans configuration
Courbe d'apprentissageFaible — commandes intuitivesMoyenne — nombreuses optionsTrès faible — `Caddyfile` minimaliste
Cas d'usage idéalServeur dédié Nginx/Apache existantEnvironnements complexes, multi-providers DNSNouveaux projets, reverse proxy intégré

Tester avant la production

Avant de mettre en production, testez contre l'environnement de staging de Let's Encrypt (--staging chez Certbot, --server letsencrypt_test chez acme.sh) : la limite de production est de 5 émissions par domaine et par semaine, et un script mal réglé peut vite vous y faire buter.

Ajoutez aussi un certificat de monitoring d'expiration : une sonde qui exécute openssl x509 -checkend 604800 (7 jours) et déclenche une alerte si le renouvellement automatique a silencieusement échoué — un cron cassé est la cause numéro un d'un HTTPS expiré en pleine nuit.

Consultez la page de releases certbot sur GitHub pour vérifier la version disponible avant d'écrire un tutoriel ou un script d'installation.

Déployez votre VPS Cloud avec HTTPS prêt à l'emploi

Le template VPS Cloud ServOrbit arrive avec Docker, un reverse proxy et la chaîne Let's Encrypt préconfigurée : certificats émis et renouvelés automatiquement, score SSL Labs A+ dès le premier déploiement. Concentrez-vous sur votre application, pas sur la plomberie TLS.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet