# Renouvellement de certificat en échec : les causes que Certbot ne dit pas

> Un certificat a expiré malgré un cron de renouvellement en place. Tour d'horizon des causes silencieuses les plus fréquentes, entre permissions mal posées et hooks oubliés.

- Auteur : Clément Hadrot
- Publié le : 2023-09-05
- Mis à jour le : 2023-09-05
- Catégorie : Hébergement &amp; serveurs
- URL : https://wpmoderne.dev.wordpress-developpement.fr/hebergement/renouvellement-certificat-echec-causes-silencieuses/

## L’essentiel

- Un hook post-renouvellement qui échoue ne bloque pas le renouvellement lui-même
- Des permissions restreintes sur le dossier live empêchent nginx de lire le nouveau certificat
- Un renouvellement réussi n'est pas toujours un certificat effectivement rechargé

Un serveur hébergeant plusieurs sites clients a vu l'un d'entre eux afficher un avertissement de sécurité, alors que Certbot signalait bien, dans ses propres journaux, un renouvellement réussi la semaine précédente. Contradiction apparente : le certificat était considéré comme renouvelé côté Certbot, mais le certificat effectivement servi par nginx aux visiteurs restait l'ancien, expiré. Ce type de décalage entre « renouvelé » et « effectivement actif » constitue l'une des causes silencieuses les plus fréquentes d'expiration malgré une automatisation apparemment fonctionnelle.

Trois causes distinctes, indépendantes les unes des autres, peuvent chacune produire ce symptôme identique. Les identifier une par une évite de s'arrêter à la première explication plausible sans vérifier les autres.

## Cause 1 : un hook post-renouvellement qui échoue silencieusement

Certbot exécute, après chaque renouvellement réussi, un hook (script) chargé de recharger le service concerné — typiquement `systemctl reload nginx`. Si ce hook échoue (permissions insuffisantes de l'utilisateur exécutant Certbot, chemin de script incorrect après une réorganisation serveur), Certbot journalise malgré tout le renouvellement du certificat lui-même comme réussi : le nouveau certificat existe bien sur le disque, mais nginx continue de servir l'ancien, chargé en mémoire depuis son dernier démarrage.

```
$ journalctl -u certbot.timer --since "-14 days" | grep -i hook
Sep 04 03:12:41 srv1 certbot[8842]: Hook '--deploy-hook' reload-nginx.sh
  returned error code 1
```

La vérification consiste à exécuter manuellement le hook déclaré, en dehors de Certbot, pour observer l'erreur exacte plutôt que de la deviner :

```
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
echo "code retour : $?"
```

> L'essentiel à retenir : Un hook post-renouvellement qui échoue ne bloque pas le renouvellement lui-même ; Des permissions restreintes sur le dossier live empêchent nginx de lire le nouveau certificat ; Un renouvellement réussi n'est pas toujours un certificat effectivement rechargé

## Cause 2 : des permissions qui empêchent nginx de lire le nouveau certificat

Le dossier `/etc/letsencrypt/live/` contient des liens symboliques vers les fichiers réels du certificat, stockés dans `/etc/letsencrypt/archive/`. Une modification de permissions un peu trop restrictive sur ce second dossier — par exemple lors d'un durcissement système appliqué globalement sans distinction — peut empêcher le processus nginx (exécuté sous un utilisateur dédié, pas root) de lire le nouveau fichier, alors que Certbot lui-même, exécuté en root, ne rencontre aucun obstacle pour écrire ce même fichier.

```
ls -la /etc/letsencrypt/archive/exemple.fr/
-rw------- 1 root root 1834 Sep  4 03:12 fullchain5.pem
```

Un fichier lisible uniquement par root, alors que le processus nginx tourne sous `www-data`, empêche le rechargement effectif, sans qu'aucune erreur ne remonte du côté de Certbot puisque son propre travail — générer le certificat — s'est parfaitement déroulé.

## Cause 3 : un renouvellement réussi mais jamais rechargé après un redémarrage manqué

Plus rare mais déjà rencontré : un hook de rechargement correctement exécuté, mais ciblant le mauvais service. Sur un serveur exécutant plusieurs instances nginx (par exemple une instance dans un conteneur, une autre directement sur l'hôte), un hook mal ajusté après une migration partielle vers des conteneurs peut recharger l'instance qui ne sert en réalité aucun trafic réel, laissant l'instance active inchangée.

## La vérification qui distingue les trois causes

Une seule commande permet de distinguer rapidement ce qui est réellement servi de ce qui existe sur le disque, sans hypothèse :

```
echo | openssl s_client -connect exemple.fr:443 -servername exemple.fr 2>/dev/null \
  | openssl x509 -noout -dates
```

Comparer la date affichée par cette commande à la date du fichier réellement présent dans `/etc/letsencrypt/archive/` révèle immédiatement si le problème vient de la génération du certificat (cause improbable si Certbot ne signale aucune erreur) ou de son chargement effectif par le serveur web (les trois causes précédentes).

- Tester manuellement chaque hook de renouvellement en dehors de Certbot, pas seulement lire ses journaux
- Vérifier les permissions du dossier `archive` après tout durcissement système du serveur
- Comparer systématiquement le certificat réellement servi à celui présent sur le disque

> « Certbot dit que ça a marché » et « le certificat servi aux visiteurs est à jour » sont deux affirmations différentes ; seule la seconde compte vraiment.

## En résumé

Un renouvellement Certbot journalisé comme réussi ne garantit pas, à lui seul, qu'un visiteur reçoive effectivement le nouveau certificat. Les hooks de rechargement, les permissions du dossier archive et l'identification précise du service actif méritent chacun une vérification distincte avant de conclure qu'un renouvellement s'est réellement propagé jusqu'au visiteur.
