Procédure complète, de la création du token OVH jusqu'au renouvellement
automatique. Mise en place le 3 octobre 2026 suralpha.
Les scripts sont publiés : github.com/dzbiker/2s-certificats-ovh
Le port 80 a été fermé sur la Livebox. C'est le bon réflexe : HSTS est actif un
an sur tous les vhosts, donc plus aucun navigateur ne passe par là.
Sauf que certbot --nginx valide en HTTP-01, et cette méthode exige que
Let's Encrypt puisse joindre le port 80. Le numéro de port est figé par la
norme — RFC 8555, §8.3 — pour qu'on ne puisse pas prouver la possession d'un
domaine par un port arbitraire. Il n'est pas configurable.
Le piège, c'est le silence. Rien ne tombe en panne tant qu'aucun certificat
n'entre dans sa fenêtre de renouvellement, trente jours avant l'échéance. Le
journal de certbot affichait sagement « Cert not yet due for renewal » et aucun
échec. Le premier renouvellement réel aurait été tenté vers le 20 octobre,
sur yness.fr — et aurait échoué. Puis les quatre autres, un par mois.
Avec HSTS à un an, un certificat expiré ne donne pas un avertissement qu'on
peut contourner : le navigateur refuse d'ouvrir le site.

La validation DNS-01 n'utilise aucun port : elle écrit un enregistrement
TXT dans la zone par l'API du registrar, puis l'efface. Et c'est la seule
méthode qui permette les certificats génériques.
| Avant | Après | |
|---|---|---|
| Port 80 | obligatoire | fermé |
| Certificats | 13 répertoires, 5 renouvelés | 4 |
| Nouveau sous-domaine | un certificat à émettre | déjà couvert |
| Sous-domaines dans les journaux publics | tous | aucun |
La dernière ligne mérite une explication. Chaque certificat émis est inscrit
dans les journaux de Certificate Transparency, publics et consultables sur
crt.sh. Un certificat par sous-domaine, c'est la cartographie du lab offerte
à qui la cherche : esxi., gophish., eve-ng., zabbix., cyberlab.…
Un certificat générique ne publie que *.massyl.com.
Ce ne sont pas des certificats « meilleurs » : même autorité, même chiffrement,
même durée de 90 jours, toujours gratuits. Ils couvrent simplement plus de noms.

certbot tourne sur l'hôte Proxmox, pas dans le CT 210. Le reverse proxy est
la machine la plus exposée : elle reçoit tout le trafic venu d'Internet. Y
déposer un token capable d'écrire dans la zone DNS reviendrait à offrir le
contrôle du DNS à qui la compromet. L'hôte n'est joignable que depuis le LAN.
Le conteneur ne reçoit que les fichiers de certificat, poussés par pct push.
Autre raison, pratique : le CT 210 tourne sous Ubuntu 20.04 avec certbot 0.40
de 2019. On ne met pas à jour le composant critique de l'infrastructure pour
ça. L'hôte est en Debian 13, et certbot y vit dans un environnement Python
isolé sous /opt/certbot-ovh, sans rien installer à l'échelle du système.
Sur https://api.ovh.com/createToken/, connecté au compte.

Puis les droits — six lignes, et rien d'autre :
GET /domain/zone
GET /domain/zone/*
POST /domain/zone/*/record
POST /domain/zone/*/refresh
PUT /domain/zone/*/record/*
DELETE /domain/zone/*/record/*

Cliquer sur le
+après chaque ligne. Une ligne ajoutée affiche un−à
sa droite ; une ligne qui affiche encore un+n'est pas prise en compte.
Sans le droitDELETE, certbot écrit son enregistrement de validation mais
ne peut plus l'effacer : la zone se remplit de_acme-challengerésiduels à
chaque renouvellement.
À quoi sert quoi :
| Droit | Usage |
|---|---|
GET /domain/zone et /domain/zone/* |
lister et lire les zones |
POST .../record |
écrire le TXT de validation |
POST .../refresh |
forcer la propagation |
DELETE .../record/* |
effacer le TXT après validation |
PUT .../record/* |
utilisé par l'agent DNS, qui met à jour l'IP publique |
Validity : Unlimited. Un token qui expire casserait le renouvellement
automatique un matin, sans prévenir. Ce n'est acceptable que parce que la
portée est étroite : ce token ne peut ni commander, ni résilier, ni voir la
facturation. S'il fuite, on abîme une zone — ça se restaure.
Restricted IPs : vide. L'IP publique est dynamique, c'est toute la raison
d'être du DynHost.
Ce token remplace l'ancien, qui portait
DELETEsur*sans expiration et
pouvait donc résilier des services. Voir Journal.
Sur l'hôte alpha, pas dans un conteneur :
sudo nano /etc/letsencrypt/ovh-credentials.ini
dns_ovh_endpoint = ovh-eu
dns_ovh_application_key = ...
dns_ovh_application_secret = ...
dns_ovh_consumer_key = ...
sudo chmod 600 /etc/letsencrypt/ovh-credentials.ini
Les clés sont écrites directement sur le serveur, et pas rangées dans
P:\Cloud : ce dossier est synchronisé par Nextcloud et recopié sur chaque
poste. Moins il existe de copies d'un secret, mieux c'est.
sudo /opt/certbot-ovh/bin/python /root/verifier-token.py
Étape à ne pas sauter. Les droits qu'on croit avoir demandés et ceux qu'OVH a
réellement accordés ne coïncident pas toujours — c'est exactement l'écart qui
avait fait passer l'ancien token pour restreint alors qu'il était total.
Le script interroge /auth/currentCredential, affiche les droits effectifs, et
alerte si l'un d'eux sort de /domain/zone.
sudo /opt/certbot-ovh/bin/certbot certonly --dns-ovh \
--dns-ovh-credentials /etc/letsencrypt/ovh-credentials.ini \
-d massyl.fr -d '*.massyl.fr' \
--agree-tos -m massyl@belkessa.fr --non-interactive --dry-run
Les apostrophes autour de '*.massyl.fr' sont obligatoires, sinon le shell
remplace l'étoile par la liste des fichiers du répertoire courant.
La commande reste figée environ deux minutes sur
Waiting 120 seconds for DNS changes to propagate : c'est la propagation du
TXT. Descendre sous 60 secondes fait échouer une validation sur deux.
Attendu : The dry run was successful.
Quatre certificats, un par domaine, chacun couvrant la racine et le joker :
| Certificat | Couvre |
|---|---|
massyl.fr |
massyl.fr + *.massyl.fr |
massyl.com |
massyl.com + *.massyl.com |
2sinnovation.com |
2sinnovation.com + *.2sinnovation.com |
yness.fr |
yness.fr + *.yness.fr |
Même commande sans --dry-run. Compter environ deux minutes par domaine.
Le joker ne couvre qu'un seul niveau.
*.2sinnovation.comcouvre
cloud.2sinnovation.commais pasapi.strive.2sinnovation.com, qui est
à deux niveaux. Ce nom existe dans la zone sans vhost ni certificat : le jour
où il en faudra un, il devra être ajouté explicitement, ou couvert par
*.strive.2sinnovation.com.
sudo /root/deployer-certs-210.sh
Copie les certificats dans /etc/ssl/generiques/<domaine>/ du conteneur,
teste la configuration nginx, et ne recharge que si elle est valide.
sudo /root/basculer-vhosts-210.sh
Sauvegarde /etc/nginx, réécrit les chemins ssl_certificate, teste, et
restaure automatiquement si nginx refuse. Puis interroge les sites pour
montrer qu'ils répondent.
Correspondance appliquée :
| Vhost | Certificat |
|---|---|
me.massyl.fr, cloud.massyl.fr, wiki.massyl.fr |
massyl.fr |
2sinnovation.com, me.2sinnovation.com, cloud. et wiki.2sinnovation.com |
2sinnovation.com |
me.massyl.com |
massyl.com |
yness.fr |
yness.fr |
Vérifier dans un navigateur avant de continuer : le cadenas doit annoncer
*.massyl.fr et non plus me.massyl.fr.
sudo /root/retirer-anciens-certs-210.sh
Le script refuse de démarrer tant qu'un vhost actif s'appuie encore sur
/etc/letsencrypt, puis demande de taper RETIRER. Il archive tout, désactive
certbot.timer dans le conteneur et met les fichiers de renouvellement de
côté. Rien n'est supprimé.
Attention au contrôle lui-même :
sites-enabledne contient que des liens
symboliques, etgrep -rles ignore silencieusement en descendant une
arborescence. Un garde-fou écrit avecgrep -rest aveugle. Il faut résoudre
les liens avecreadlink -f, ou utilisergrep -R.
Les huit répertoires de /etc/letsencrypt/live/ sans fichier de renouvellement
— cyberlab, transport, esxi, eve-ng, gophish, zabbix.massyl.com,
plex, portainer — ne se renouvelaient déjà pas. Les génériques les couvrent
tous. Ils partent dans l'archive et seront effacés après le premier
renouvellement automatique réussi.
sudo systemctl enable --now certbot-ovh.timer
sudo systemctl list-timers certbot-ovh.timer
sudo /opt/certbot-ovh/bin/certbot renew --dry-run
Chaque jour vers 3 h, plus un délai aléatoire d'une heure pour ne pas taper sur
Let's Encrypt à la même seconde que tout le monde. Seuls les certificats à
moins de 30 jours de l'échéance sont renouvelés, et chaque renouvellement
réussi rappelle automatiquement le script de livraison, branché en
renewal-hook.

Un certificat ne peut pas couvrir une adresse IP. Ouvrir l'interface par
https://192.168.1.213:8006 donnera toujours cet avertissement, quoi qu'on
fasse. Le certificat générique *.massyl.fr couvre en revanche
pve.massyl.fr : il suffit d'y accéder par ce nom.
Error getting validation data — échec de connexion : la requête n'est
jamais arrivée. Avec DNS-01 ce message ne devrait plus apparaître. S'il
persiste, un fichier de renouvellement utilise encore authenticator = nginx ;
vérifier /etc/letsencrypt/renewal/*.conf.
Validation qui échoue une fois sur deux — augmenter le délai de
propagation. 120 secondes est la valeur sûre chez OVH.
Des _acme-challenge s'accumulent — le token n'a pas le droit DELETE.
too many certificates already issued — 5 certificats identiques par
semaine maximum. Les simulations ne comptent pas dans ce quota.