by thenoiser / apo33
Objectif : remplacer le renouvellement manuel du certificat Let's Encrypt (challenge DNS-01 à copier-coller à la main tous les ~60-90 jours) par un système entièrement automatisé, piloté par l'API Gandi, avec un token valable jusqu'à 1 an.
<note important>
Ce tutoriel fait suite à/remplace la méthode manuelle décrite dans “Comment faire sa web radio” (renouvellement manuel via certbot certonly –manual –preferred-challenges dns). Le principe reste le DNS-01 (pas besoin du port 80 ouvert, fonctionne même derrière un reverse proxy ou sur une machine sans exposition web directe), mais la pose/suppression du challenge TXT est déléguée à l'API Gandi.
</note>
Interface Gandi → Paramètres → Jetons d'accès personnels → Créer.
certbot-dns-automation)Copier le token immédiatement (affiché une seule fois).
<note tip> Test de validation rapide, avant même de toucher à certbot :
curl -H "Authorization: Bearer VOTRE_TOKEN" \ https://api.gandi.net/v5/livedns/domains/votredomaine.org
Doit renvoyer du JSON avec les infos du domaine. Une erreur 403 Forbidden = mauvaise organisation ou permissions incomplètes — retourner corriger le token (Gandi ne permet pas d'éditer un token existant, il faut le supprimer et en recréer un).
</note>
<note warning>
Ne pas utiliser pip install –break-system-packages en direct : conflit quasi garanti avec les paquets système (cffi notamment). Utiliser pipx, qui isole proprement l'environnement.
</note>
sudo apt install -y pipx sudo pipx install certbot sudo pipx inject certbot certbot-dns-gandi sudo pipx ensurepath
<note important>
Si un certbot système existe déjà (/usr/bin/certbot, installé via apt), pipx ne le remplace pas automatiquement sur le PATH — il faut appeler explicitement le binaire pipx :
which certbot # montre souvent encore /usr/bin/certbot sudo /root/.local/bin/certbot plugins # vérifie que dns-gandi apparaît bien ici
Toujours utiliser /root/.local/bin/certbot explicitement dans la suite de ce tuto (obtention, renouvellement, timer) pour être sûr de viser la bonne installation.
</note>
sudo mkdir -p /etc/letsencrypt sudo nano /etc/letsencrypt/gandi.ini
dns_gandi_token = VOTRE_TOKEN
<note important>
Le nom de la clé est dns_gandi_token (pas dns_gandi_api_token, erreur courante qui donne “Missing property in credentials configuration file”).
</note>
sudo chmod 600 /etc/letsencrypt/gandi.ini sudo chown root:root /etc/letsencrypt/gandi.ini
sudo /root/.local/bin/certbot certonly \ --authenticator dns-gandi \ --dns-gandi-credentials /etc/letsencrypt/gandi.ini \ --key-type ecdsa \ --deploy-hook "systemctl reload nginx" \ -d sousdomaine.votredomaine.org
<note tip> Si l'erreur suivante apparaît :
Incorrect TXT record "..." found at _acme-challenge.sousdomaine... Hint: ... try increasing --dns-gandi-propagation-seconds (currently 10 seconds)
C'est un simple problème de timing de propagation DNS, pas un problème de credentials. Relancer avec un délai plus long :
sudo /root/.local/bin/certbot certonly \ --authenticator dns-gandi \ --dns-gandi-credentials /etc/letsencrypt/gandi.ini \ --key-type ecdsa \ --dns-gandi-propagation-seconds 45 \ -d sousdomaine.votredomaine.org \ --force-renewal
Une fois un essai réussi avec un délai donné, cette valeur est automatiquement sauvegardée dans /etc/letsencrypt/renewal/<domaine>.conf (dns_gandi_propagation_seconds = 45) — les renouvellements futurs en bénéficient sans réglage supplémentaire.
</note>
<note important>
Ne pas se fier au timer certbot.timer/snap.certbot.renew.timer déjà présent sur le système : il utilise le certbot système (/usr/bin/certbot), qui ne connaît pas le plugin dns-gandi. Créer un timer dédié qui pointe explicitement vers le certbot pipx.
</note>
sudo nano /etc/systemd/system/certbot-renew.service
[Unit] Description=Certbot renewal (pipx, dns-gandi) [Service] Type=oneshot ExecStart=/root/.local/bin/certbot renew --quiet
sudo nano /etc/systemd/system/certbot-renew.timer
[Unit] Description=Run certbot renewal twice daily [Timer] OnCalendar=*-*-* 03,15:00:00 RandomizedDelaySec=1800 Persistent=true [Install] WantedBy=timers.target
sudo systemctl daemon-reload sudo systemctl enable --now certbot-renew.timer sudo systemctl list-timers | grep certbot-renew
Désactiver l'ancien timer système pour éviter tout conflit/doublon :
sudo systemctl disable --now certbot.timer 2>/dev/null sudo systemctl disable --now snap.certbot.renew.timer 2>/dev/null
sudo /root/.local/bin/certbot renew --dry-run
Doit afficher Congratulations, all simulated renewals succeeded.
<note warning>
Section sensible. Si le certificat doit être utilisé par un Apache ancien (ex: Apache 2.4.6 / OpenSSL 1.0.2k sur CentOS 7, cas du serveur SME), le fichier fullchain.pem moderne (certificat + tous les intermédiaires concaténés) peut faire planter mod_ssl au démarrage avec :
AH01903: Failed to configure CA certificate chain! AH02312: Fatal error initialising mod_ssl, exiting.
Ce n'est pas un problème de contenu invalide, mais de format non supporté par cette version d'OpenSSL — et comme SME régénère toute la config Apache d'un coup à chaque événement, cette erreur peut interrompre TOUS les sites du serveur, pas seulement celui concerné. </note>
Ne jamais découper fullchain.pem à la main avec awk/sed (source d'erreurs de parsing PEM très facile) — utiliser directement les fichiers déjà séparés par certbot :
# Sur la machine où le cert a été obtenu : sudo cat /etc/letsencrypt/live/sousdomaine.votredomaine.org/cert.pem # certificat seul (feuille) sudo cat /etc/letsencrypt/live/sousdomaine.votredomaine.org/chain.pem # chaîne d'intermédiaires seule sudo cat /etc/letsencrypt/live/sousdomaine.votredomaine.org/privkey.pem # clé privée
Copier ces trois fichiers tels quels vers le serveur cible (ex: via heredoc cat > fichier << 'EOF' ... EOF), dans un dossier dédié ne touchant à aucun certificat existant :
mkdir -p /etc/pki/tls/certs/sousdomaine/ # coller cert.pem, chain.pem, privkey.pem chmod 600 /etc/pki/tls/certs/sousdomaine/privkey.pem chmod 644 /etc/pki/tls/certs/sousdomaine/cert.pem /etc/pki/tls/certs/sousdomaine/chain.pem chown root:root /etc/pki/tls/certs/sousdomaine/*
Valider en pur openssl, sans toucher à Apache, avant toute intégration :
openssl x509 -in /etc/pki/tls/certs/sousdomaine/cert.pem -noout -subject -dates openssl crl2pkcs7 -nocrl -certfile /etc/pki/tls/certs/sousdomaine/chain.pem | openssl pkcs7 -print_certs -noout
La deuxième commande doit lister 2-3 certificats intermédiaires proprement, sans erreur bad end line ni no start line.
Ne jamais éditer httpd.conf directement (régénéré automatiquement). Créer un fragment isolé, conditionné au domaine concerné uniquement :
mkdir -p /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/WebAppVirtualHost cat > /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/WebAppVirtualHost/06SSLCertPersonnalise << 'EOF' { my $name = $domain->key; if ($name eq 'sousdomaine.votredomaine.org') { $OUT .= " SSLCertificateFile /etc/pki/tls/certs/sousdomaine/cert.pem\n"; $OUT .= " SSLCertificateKeyFile /etc/pki/tls/certs/sousdomaine/privkey.pem\n"; $OUT .= " SSLCertificateChainFile /etc/pki/tls/certs/sousdomaine/chain.pem\n"; } } EOF
<note tip>
La condition if ($name eq '...') isole strictement ce fragment à un seul domaine — aucun risque pour les autres vhosts, actuels ou futurs, qui utilisent le même template WebAppVirtualHost.
</note>
# Backup de sécurité avant toute manip cp /etc/httpd/conf/httpd.conf /root/httpd.conf.backup-$(date +%Y%m%d-%H%M%S) # Régénère le fichier SANS toucher au service actif /sbin/e-smith/expand-template /etc/httpd/conf/httpd.conf httpd -t
Test isolé obligatoire avant tout redémarrage réel (voir détail complet dans le tuto PeerTube, section 7.5) :
cp /etc/httpd/conf/httpd.conf /tmp/httpd-test.conf sed -i \ -e 's|^Listen 0\.0\.0\.0:80|Listen 0.0.0.0:8081|' \ -e 's|^Listen 0\.0\.0\.0:443|Listen 0.0.0.0:8444|' \ -e 's|^Listen \[::\]:80|Listen [::]:8081|' \ -e 's|^Listen \[::\]:443|Listen [::]:8444|' \ -e 's|^PidFile.*|PidFile /tmp/httpd-test.pid|' \ /tmp/httpd-test.conf /usr/sbin/httpd -f /tmp/httpd-test.conf -DFOREGROUND & sleep 3 jobs # "En cours d'exécution" = le certificat charge correctement tail -15 /var/log/httpd/error_log kill %1
Seulement si ce test réussit, appliquer pour de vrai :
systemctl restart httpd-e-smith.service # nom exact du service à vérifier au préalable systemctl status httpd-e-smith.service --no-pager curl -Ik http://domaineprincipal.org # confirmer que le site principal répond toujours
<note important> En cas d'échec (service qui refuse de démarrer) : supprimer immédiatement le fragment custom fautif, régénérer sans lui, relancer le service. Le site principal doit revenir en quelques secondes.
rm /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/WebAppVirtualHost/06SSLCertPersonnalise /sbin/e-smith/signal-event domain-modify sousdomaine.votredomaine.org systemctl restart httpd-e-smith.service
</note>
sudo systemctl list-timers | grep certbot pour confirmer que le timer est toujours actif