Ce tutoriel installe un certificat SSL Sectigo ou TrustSign commandé sur HTTPCS avec acme.sh, le client ACME de référence sous Linux. acme.sh obtient le certificat, l’installe puis le renouvelle automatiquement.
Choisissez d’abord votre type de certificat : les prérequis, les commandes et les contrôles s’adaptent. Renseignez ensuite vos informations : elles s’insèrent dans les commandes, prêtes à copier. Chaque étape indique le résultat attendu et les erreurs courantes.
Vos choix adaptent les prérequis, les commandes et les vérifications de la suite du tutoriel.
sudo -i.curl et crontab installées (Debian ou Ubuntu : apt install curl cron)./root/.acme.sh. Ne relancez pas le script d’installation : le tutoriel n’ajoute que ce qui manque pour ce certificat.*.mondomaine.tld couvre les sous-domaines directs (blog.mondomaine.tld), pas les niveaux inférieurs (a.blog.mondomaine.tld). Le domaine nu mondomaine.tld est ajouté automatiquement aux commandes.Les valeurs saisies remplacent les zones surlignées en jaune dans les commandes. Une zone renseignée passe en bleu. Un clic sur une zone jaune amène au champ correspondant.
Rien n’est envoyé ni enregistré : les commandes sont générées dans votre navigateur. Tous les champs sont facultatifs.
Valeur Url du serveur de votre tableau de bord. Tapez « sectigo » ou « trust » pour la retrouver.
Cette URL correspond à un certificat Organisation (OV), alors que vous avez choisi Domaine (DV). Reprenez l’URL affichée dans votre tableau de bord.
Cette URL correspond à un certificat Domaine (DV), alors que vous avez choisi Organisation (OV). Reprenez l’URL affichée dans votre tableau de bord.
Contact du compte ACME, utilisé pour les avis d’expiration.
Valeur kid du tableau de bord : l’identifiant court.
Valeur hmac du tableau de bord : la clé longue. Ne la partagez pas.
Sans http:// ni chemin, par exemple mondomaine.tld.
Un domaine par ligne, tels qu’ils figurent dans votre commande.
Saisissez le domaine sans *. : les commandes demandent à la fois mondomaine.tld et *.mondomaine.tld.
Dossier servi pour ce domaine : directive root sous Nginx, DocumentRoot sous Apache.
Dans Cloudflare, My Profile › API Tokens › Create Token, modèle « Edit zone DNS » limité à ce domaine. Le Zone ID figure sur la page Overview du domaine.
Créez les trois clés en une fois sur la page de votre région : eu.api.ovh.com/createToken ca.api.ovh.com/createToken api.us.ovhcloud.com/createToken eu.api.kimsufi.com/createToken ca.api.kimsufi.com/createToken eu.api.soyoustart.com/createToken ca.api.soyoustart.com/createToken
Option 1, toutes les zones du compte (pré-remplie par le lien) :
/domain/zone/*
Option 2, cette zone seulement : déclarez les deux chemins.
/domain/zone/mondomaine.tld
/domain/zone/mondomaine.tld/*
La page affiche ensuite l’Application Key, l’Application Secret et la Consumer Key : reportez-les dans les champs correspondants.
Dans Gandi, Paramètres utilisateur › Jetons d’accès personnels, avec le droit de gérer la configuration technique des domaines.
Dans le Manager Infomaniak, Développeur › Jetons API : créez un jeton avec la portée domain.
Créez une clé sur developer.hosting.ionos.fr/keys : IONOS affiche un préfixe public et un secret, à reporter dans deux champs séparés.
Dans la console Scaleway, IAM › Clés API : utilisez la Secret Key d’une clé dont la politique comprend ce jeu de permissions :
DomainsDNSFullAccess
Dans AWS IAM, créez une clé d’accès pour un utilisateur autorisé aux actions suivantes :
route53:ListHostedZones
route53:ChangeResourceRecordSets
route53:GetChange
Plus de 150 hébergeurs sont pris en charge : voir la documentation acme.sh.
Commande qui recharge votre logiciel pour qu’il lise le nouveau certificat.
Nom indiqué dans la documentation acme.sh pour votre hébergeur, par exemple dns_gd.
Le script installe acme.sh dans /root/.acme.sh, ajoute l’alias acme.sh et une tâche cron de renouvellement. La dernière commande affiche la version installée.
curl https://get.acme.sh | sh -s email=admin@mondomaine.tld
source ~/.bashrc
acme.sh --version
acme.sh: command not found
L’alias n’est pas encore chargé : lancez source ~/.bashrc ou ouvrez une nouvelle session. Vérifiez aussi que l’installation a été faite avec le même utilisateur (root).
Pre-check failed
La commande crontab est absente. Installez-la (apt install cron) puis relancez l’installation.
curl: (6) Could not resolve host ou délai dépassé
Le serveur n’accède pas à Internet en sortie. Vérifiez sa résolution DNS et le pare-feu sortant : github.com doit être joignable.
Mettez acme.sh à jour et listez les certificats qu’il gère déjà. Ils ne sont pas modifiés par la suite du tutoriel.
acme.sh --upgrade
acme.sh --list
Chaque commande HTTPCS a son propre compte ACME, alors qu’acme.sh ne garde qu’un compte par URL de serveur. Vérifiez si un compte existe déjà pour l’URL de ce certificat :
ls /root/.acme.sh/ca/URL_DU_SERVEUR/account.key
No such file or directory : aucun compte, gardez la configuration commune. Le fichier account.key s’affiche : un autre certificat utilise déjà cette URL, choisissez la configuration séparée, sinon acme.sh réutiliserait l’ancien compte et le serveur ACME refuserait ce domaine.
Listez les identifiants d’API DNS déjà enregistrés, sans afficher leurs valeurs :
grep -o '^SAVED_[A-Za-z_]*' /root/.acme.sh/account.conf
Les variables d’un autre hébergeur (par exemple SAVED_OVH_AK quand ce domaine est chez IONOS) ne gênent pas : chaque hébergeur a ses propres variables. Si les variables de votre hébergeur apparaissent avec un autre compte que celui de ce domaine, choisissez la configuration séparée : réexporter de nouvelles valeurs remplacerait les anciennes et les renouvellements des autres certificats échoueraient.
acme.sh: command not found
acme.sh est installé pour un autre utilisateur ou dans un autre dossier. Cherchez-le avec ls -d /root/.acme.sh /home/*/.acme.sh et travaillez avec ce même utilisateur.
acme.sh --list n’affiche pas les certificats connus
Ils dépendent d’une autre configuration. La ligne cron indique laquelle : crontab -l | grep acme.sh (option --config-home).
Cette commande relie acme.sh à votre compte ACME HTTPCS grâce aux identifiants EAB (External Account Binding). Elle ne s’exécute qu’une fois par serveur.
Cette étape reste nécessaire avec un acme.sh déjà installé : les identifiants EAB sont propres à cette commande HTTPCS.
Configuration séparée : --config-home range ce certificat dans son propre dossier (compte ACME, identifiants DNS, configuration de renouvellement). Gardez cette option dans toutes les commandes suivantes, elle y est déjà ajoutée.
mkdir -p /root/.acme.sh-httpcs-mondomaine.tld && touch /root/.acme.sh-httpcs-mondomaine.tld/account.conf
acme.sh --register-account \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
--server URL_DU_SERVEUR \
--eab-kid VOTRE_KID \
--eab-hmac-key VOTRE_HMAC \
-m admin@mondomaine.tld
Résultat attendu : Registered puis ACCOUNT_THUMBPRINT=….
Already registered au lieu de Registered
Un compte existe déjà pour cette URL dans cette configuration : les nouveaux identifiants EAB ne sont pas utilisés et la demande de certificat sera refusée. Choisissez Déjà installé puis Configuration séparée dans le sélecteur et relancez l’enregistrement. Si vous relancez simplement l’enregistrement de ce même certificat, le message est normal.
externalAccountRequired
Le serveur n’a pas reçu les identifiants EAB : une ligne a été coupée. Chaque \ doit être le dernier caractère de sa ligne, sans espace après. Recopiez le bloc avec le bouton Copier.
unauthorized ou malformed qui mentionne l’EAB
kid et hmac inversés, tronqués ou issus d’un autre certificat. Reprenez-les depuis le tableau de bord, sans espace au début ni à la fin.
Pour prouver le contrôle du domaine, acme.sh dépose un fichier dans le dossier .well-known/acme-challenge du site. Ce test reproduit l’opération avant la vraie demande. Pour un multi-domaines, répétez la ligne curl avec chaque domaine.
mkdir -p /var/www/html/.well-known/acme-challenge
echo ok > /var/www/html/.well-known/acme-challenge/httpcs-test
curl -i http://mondomaine.tld/.well-known/acme-challenge/httpcs-test
rm /var/www/html/.well-known/acme-challenge/httpcs-test
Résultat attendu : HTTP/1.1 200 OK, puis ok à la fin de la réponse.
404 Not Found
Ce dossier n’est pas celui servi pour ce domaine. Retrouvez le bon avec grep -R "root" /etc/nginx/sites-enabled/ (Nginx) ou grep -R "DocumentRoot" /etc/apache2/sites-enabled/ (Apache).
Connection refused ou délai dépassé
Le port 80 est fermé (pare-feu du serveur ou de l’hébergeur, par exemple ufw allow 80/tcp) ou le domaine ne pointe pas vers ce serveur : comparez dig +short A mondomaine.tld avec l’IP du serveur.
dig +short AAAA mondomaine.tld) alors que le site ne répond pas en IPv6. L’autorité de certification peut passer par l’IPv6 : corrigez ou supprimez cet enregistrement.
/.well-known/acme-challenge/ de cette redirection.
acme.sh crée lui-même l’enregistrement TXT de validation grâce à l’API de votre hébergeur DNS. Exportez les identifiants dans la session : acme.sh les enregistre dans /root/.acme.sh/account.conf lors de la première demande et les réutilise à chaque renouvellement. Limitez si possible le jeton à la modification de cette zone.
acme.sh déjà installé : si ces variables figurent déjà dans la liste de l’étape « Faire le point » pour le même compte, inutile de les réexporter, acme.sh les relit. Les identifiants enregistrés pour un autre hébergeur restent intacts.
export CF_Token="A_RENSEIGNER"
export CF_Zone_ID="A_RENSEIGNER"
export OVH_END_POINT="A_RENSEIGNER"
export OVH_AK="A_RENSEIGNER"
export OVH_AS="A_RENSEIGNER"
export OVH_CK="A_RENSEIGNER"
export GANDI_LIVEDNS_TOKEN="A_RENSEIGNER"
export INFOMANIAK_API_TOKEN="A_RENSEIGNER"
export IONOS_PREFIX="A_RENSEIGNER"
export IONOS_SECRET="A_RENSEIGNER"
export SCALEWAY_API_TOKEN="A_RENSEIGNER"
export AWS_ACCESS_KEY_ID="A_RENSEIGNER"
export AWS_SECRET_ACCESS_KEY="A_RENSEIGNER"
Exportez les variables indiquées pour votre hébergeur dans la documentation acme.sh, sous la forme export NOM="valeur".
Vérifiez que la zone est bien gérée par cet hébergeur : les serveurs de noms affichés doivent lui appartenir.
dig +short NS mondomaine.tld
Error add txt for domain
L’API a refusé l’ajout : identifiants erronés ou jeton sans droit d’écriture sur la zone. Pour OVHcloud, créez le jeton sur eu.api.ovh.com/createToken avec les droits GET, POST, PUT et DELETE sur /domain/zone/*.
invalid domain ou zone introuvable
acme.sh ne trouve la zone dans aucun domaine du compte lié à ces identifiants. Si dig +short NS montre bien l’hébergeur choisi, la zone appartient à un autre compte chez cet hébergeur (OVHcloud : autre identifiant client) ou le jeton n’a pas le droit de la lire. Recréez le jeton en étant connecté au compte qui gère la zone. La réponse de l’API s’affiche en relançant la commande avec --debug 2 : This service does not exist indique un autre compte, This call has not been granted un droit manquant. Chez OVHcloud, un droit sur /domain/zone/mondomaine.tld/* ne couvre pas /domain/zone/mondomaine.tld : ajoutez aussi ce chemin en GET.
acme.sh demande le certificat au serveur ACME HTTPCS, réalise la validation choisie puis télécharge le certificat dans /root/.acme.sh/.
Gardez les guillemets simples autour de '*.mondomaine.tld' : sans eux, le shell remplace * par les fichiers du dossier courant.
acme.sh --issue \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
--server URL_DU_SERVEUR \
-d mondomaine.tld \
-w /var/www/html
acme.sh --issue \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
--server URL_DU_SERVEUR \
-d mondomaine.tld \
--dns dns_xxx
acme.sh --issue \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
--server URL_DU_SERVEUR \
-d mondomaine.tld \
--dns \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
Résultat attendu : Cert success., suivi des chemins du certificat et de la clé.
Résultat attendu : acme.sh s’arrête volontairement et affiche pour chaque nom une ligne Domain: '_acme-challenge.mondomaine.tld' et une ligne TXT value: '…'. Gardez ces valeurs pour l’étape suivante.
Certificat Organisation : le domaine a déjà été contrôlé pendant la validation de l’organisation. acme.sh peut alors afficher Already verified, skip et passer directement à l’émission. C’est normal.
rejectedIdentifier, unauthorized ou commande refusée
Un nom demandé ne fait pas partie de votre commande HTTPCS. Utilisez exactement les domaines commandés ; pour un wildcard, le domaine nu et *.domaine.
externalAccountRequired à cette étape
L’URL passée à --server diffère de celle de l’enregistrement : acme.sh tente de créer un nouveau compte sans EAB. Utilisez la même URL dans les deux commandes.
*.mondomaine.tld
Un wildcard ne peut pas être validé par HTTP. Choisissez une validation DNS dans le sélecteur.
Verify error avec Invalid response et un code 404
Le dossier passé à -w n’est pas celui du site. Refaites le test de l’étape précédente.
Timeout ou Connection refused
Le port 80 n’est pas joignable depuis Internet ou le domaine pointe ailleurs. Refaites le test de l’étape précédente.
invalid domain puis Error adding TXT record
acme.sh ne trouve la zone dans aucun domaine du compte lié à ces identifiants. Si dig +short NS montre bien l’hébergeur choisi, la zone appartient à un autre compte chez cet hébergeur (OVHcloud : autre identifiant client) ou le jeton n’a pas le droit de la lire. Recréez le jeton en étant connecté au compte qui gère la zone. La réponse de l’API s’affiche en relançant la commande avec --debug 2 : This service does not exist indique un autre compte, This call has not been granted un droit manquant. Chez OVHcloud, un droit sur /domain/zone/mondomaine.tld/* ne couvre pas /domain/zone/mondomaine.tld : ajoutez aussi ce chemin en GET.
It seems that your ovh key is changed, let’s clear consumer key first.
Message normal à la première utilisation de ces clés OVHcloud : acme.sh oublie l’ancienne Consumer Key enregistrée et utilise celle que vous avez exportée.
--dnssleep 300 pour attendre cinq minutes avant la vérification.
Dans l’interface de votre hébergeur DNS, créez un enregistrement de type TXT pour chaque valeur affichée par acme.sh, sur le nom _acme-challenge. La plupart des interfaces ajoutent le domaine automatiquement : saisissez alors seulement _acme-challenge, pas le nom complet.
Wildcard : acme.sh affiche deux valeurs pour le même nom _acme-challenge.mondomaine.tld, une pour le domaine nu et une pour *.mondomaine.tld. Créez deux enregistrements TXT distincts ; ne remplacez pas le premier par le second.
Attendez la propagation, puis vérifiez que toutes les valeurs sont visibles :
dig +short TXT _acme-challenge.mondomaine.tld @1.1.1.1
Quand toutes les valeurs apparaissent, finalisez la demande :
acme.sh --renew \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
-d mondomaine.tld \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
Le mode DNS manuel ne se renouvelle pas tout seul. Les certificats ACME ont une durée courte, de quelques mois : vous devrez refaire ces étapes avant chaque échéance (date notAfter du certificat). Pour automatiser, passez au DNS automatique dès que possible.
Verify error ou Invalid status
Une valeur manque ou n’est pas encore propagée. La commande dig doit afficher toutes les valeurs. Attendez la durée du TTL de la zone puis relancez --renew.
dig ne renvoie rien
Le nom est sans doute doublé (_acme-challenge.mondomaine.tld.mondomaine.tld). Corrigez l’enregistrement en saisissant seulement _acme-challenge.
--issue génère de nouvelles valeurs. Mettez à jour les TXT avec les dernières valeurs affichées.
Copiez la clé et le certificat complet (fullchain) dans /etc/ssl. acme.sh mémorise ces chemins et la commande de rechargement, et les réutilise à chaque renouvellement. Ne pointez jamais le serveur web directement vers les fichiers de /root/.acme.sh/.
acme.sh --install-cert -d mondomaine.tld \
--config-home /root/.acme.sh-httpcs-mondomaine.tld \
--key-file /etc/ssl/private/mondomaine.tld-acme.key \
--fullchain-file /etc/ssl/certs/mondomaine.tld-acme.crt \
--reloadcmd "COMMANDE_DE_RECHARGEMENT"
Vérifiez la présence des deux fichiers :
ls -l /etc/ssl/private/mondomaine.tld-acme.key /etc/ssl/certs/mondomaine.tld-acme.crt
Vérifiez qu’acme.sh a mémorisé cette installation. Sans ces paramètres, un renouvellement ne recopierait pas les fichiers et ne rechargerait pas le serveur web.
grep -o '^Le_\(RealKeyPath\|RealFullChainPath\|ReloadCmd\)' /root/.acme.sh/mondomaine.tld_ecc/mondomaine.tld.conf
Résultat attendu : Le_RealKeyPath, Le_RealFullChainPath et Le_ReloadCmd.
--install-cert ci-dessus : acme.sh enregistre les chemins et la commande de rechargement à ce moment.
No such file or directory sur le fichier .conf
Le certificat a été émis avec une clé RSA : son dossier ne porte pas le suffixe _ecc. Retirez _ecc du chemin.
is not an issued domain, skip
Le nom passé à -d doit être le premier domaine de l’étape d’obtention : colonne Main_Domain de acme.sh --list.
Reload error
La commande de rechargement a échoué, souvent à cause d’une configuration invalide. Corrigez la configuration à l’étape suivante puis relancez cette commande.
Permission denied
Lancez la commande en root (sudo -i).
Ouvrez le fichier du site dans /etc/nginx/sites-available/ (ou /etc/nginx/conf.d/) et adaptez son bloc server HTTPS. Retirez les anciennes lignes ssl_certificate du site, puis testez et rechargez Nginx.
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mondomaine.tld;
ssl_certificate /etc/ssl/certs/mondomaine.tld-acme.crt;
ssl_certificate_key /etc/ssl/private/mondomaine.tld-acme.key;
# reste de votre configuration existante
}
nginx -t && systemctl reload nginx
Ouvrez le fichier du site dans /etc/apache2/sites-available/ et adaptez son bloc VirtualHost du port 443. Activez le module SSL, testez puis rechargez Apache. Sur Red Hat, Rocky ou Alma, le service se nomme httpd.
<VirtualHost *:443>
ServerName mondomaine.tld
ServerAlias *.mondomaine.tld
SSLEngine on
SSLCertificateFile /etc/ssl/certs/mondomaine.tld-acme.crt
SSLCertificateKeyFile /etc/ssl/private/mondomaine.tld-acme.key
# reste de votre configuration existante
</VirtualHost>
a2enmod ssl
apachectl configtest && systemctl reload apache2
Indiquez à votre logiciel ces deux fichiers, la clé puis le certificat complet, puis rechargez-le :
/etc/ssl/private/mondomaine.tld-acme.key
/etc/ssl/certs/mondomaine.tld-acme.crt
cannot load certificate au test nginx -t
Le chemin du fichier est faux. Comparez-le avec le résultat de la commande ls -l de l’étape précédente.
nginx -T | grep -nE "server_name|ssl_certificate".
Invalid command 'SSLEngine'
Le module SSL n’est pas activé : lancez a2enmod ssl.
apachectl -S.
Interrogez le site comme le ferait un navigateur :
openssl s_client -connect mondomaine.tld:443 -servername mondomaine.tld </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
Résultat attendu : issuer mentionne Sectigo ou TrustSign, notAfter donne la date d’expiration et la ligne X509v3 Subject Alternative Name liste tous vos domaines.
Wildcard : la liste doit contenir DNS:*.mondomaine.tld et DNS:mondomaine.tld. Pour tester un sous-domaine, remplacez la valeur de -servername par ce sous-domaine.
Ouvrez ensuite le site dans un navigateur et cliquez sur le cadenas : le certificat doit être valide et émis par Sectigo ou TrustSign.
unable to get local issuer certificate ou chaîne incomplète
Le serveur envoie le certificat seul au lieu du certificat complet. Utilisez le fichier installé avec --fullchain-file.
NET::ERR_CERT_COMMON_NAME_INVALID
Le nom visité ne figure pas dans le certificat. Un wildcard ne couvre qu’un niveau de sous-domaine.
openssl montre le nouveau certificat, le serveur est correct.
acme.sh vérifie ses certificats chaque jour via cron. Il renouvelle celui-ci avant son expiration, le réinstalle et relance la commande de rechargement, sans action de votre part.
Configuration séparée : la tâche cron existante ne voit pas ce dossier, et acme.sh --install-cronjob n’ajoute pas de seconde ligne. Ajoutez-la vous-même :
(crontab -l; echo '0 4 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" --config-home "/root/.acme.sh-httpcs-mondomaine.tld" > /dev/null') | crontab -
DNS manuel : aucun renouvellement automatique. Notez la date de la colonne Renew et refaites les étapes DNS avant cette date, ou passez au DNS automatique.
crontab -l | grep acme.sh
acme.sh --list --config-home /root/.acme.sh-httpcs-mondomaine.tld
Résultat attendu : une ligne cron qui contient acme.sh --cron, et votre domaine dans acme.sh --list avec la date du prochain renouvellement (colonne Renew).
Configuration séparée : deux lignes acme.sh --cron, dont une avec --config-home.
Vérifiez la durée du certificat installé :
openssl x509 -noout -dates -in /etc/ssl/certs/mondomaine.tld-acme.crt
Résultat attendu : notAfter donne la date d’expiration. La date de la colonne Renew de acme.sh --list doit tomber avant : acme.sh renouvelle bien avant l’échéance.
acme.sh --install-cronjob.
acme.sh --cron --debug pour lire l’erreur. Causes fréquentes : jeton API DNS révoqué, port 80 fermé depuis, ou commande HTTPCS expirée (le compte ACME n’est valable que pendant la durée de la commande).
L’installation est terminée quand le site sert le nouveau certificat, que le navigateur le reconnaît et que acme.sh --list affiche une date de renouvellement.