Publié le : 09/08/2025

De l’Émission ACME au SMTP Chiffré : Guide Complet : acme.sh + HestiaCP + Exim4 (TLS)

Acme.sh HestiaCP Exim4

Marre des certificats qui se renouvellent d’un côté mais que votre SMTP refuse de l’autre ?
Ce guide pas-à-pas montre comment émettre avec acme.sh, déployer automatiquement dans HestiaCP et activer le TLS/SNI dynamique d’Exim4 pour des soumissions 587 et SMTPS 465 fiables et cohérentes.
Hooks prêts à l’emploi, commandes reproductibles et tests openssl : tout pour passer de l’ACME au SMTP chiffré sans surprise.

1. Introduction

1.1Pourquoi externaliser les certificats avec acme.sh ?

Le module Let’s Encrypt intégré de HestiaCP repose surtout sur le challenge HTTP‑01 (et parfois sur l’interface) ; il devient contraignant si :

  • Votre serveur SMTP / mail est derrière des proxys, tunnels, ou ne sert pas directement le port 80.
  • Vous souhaitez des wildcards (*.domaine.tld) ou un multi‑SAN en DNS‑01.
  • Vous voulez un contrôle fin (ECC vs RSA, hooks personnalisés, script de déploiement).

acme.sh est léger (bash pur), indépendant, offre DNS‑01 sur de nombreux fournisseurs (Cloudflare, Route53, etc.) et une API simple pour déployer / régénérer.

1.2 Objectifs du guide

  1. Obtenir un certificat Let’s Encrypt (wildcard ou multi‑SAN) avec acme.sh via DNS‑01 (Cloudflare).
  2. L’installer proprement dans l’écosystème Hestia (répertoires attendus par Exim4).
  3. Activer / renforcer TLS sur Exim4 (ports 25, 587, 465 facultatif) et masquer AUTH avant chiffrement.
  4. Automatiser le renouvellement avec un hook unique.
  5. Sécuriser (protocoles, permissions) et diagnostiquer les erreurs.

1.3 Architecture Flux Certificat

diagramme de chaîne TLS : acme hestia exim4 clients smtp

2. Concepts & Terminologie

TermeDescriptionImpact Exim4
ACMEProtocole d’automatisation d’émission de certificats (RFC 8555)Utilisé par Let’s Encrypt via acme.sh
DNS‑01Challenge prouvant le contrôle du domaine par enregistrement TXTPermet wildcard et sans ouverture HTTP/80
HTTP‑01Challenge via fichier HTTP sur port 80Peu pratique si reverse proxy complexe
WildcardCert couvrant *.domaine.tld + (optionnel) le domaine apexCouvre mail., smtp., etc.
SANSubject Alternative Name – liste des FQDN inclusPermet un seul cert multi‑hôtes
FullchainCert feuille + intermédiaire(s)Éviter chain incomplete chez clients
STARTTLS (25/587)Négociation TLS après EHLOMode opportuniste ou forcé sur submission
SMTPS (465)TLS implicite dès la connexionHéritage, encore utilisé par certains clients
SNIIndication du nom serveur dans ClientHelloExim4 peut choisir un cert par host

3. Pré‑requis

  1. Accès root au serveur HestiaCP (Debian/Ubuntu).
  2. HestiaCP installé avec Exim4 actif.
  3. DNS contrôlé (exemple Cloudflare) et possibilité de créer un token API à permissions limitées (Zone:DNS:Edit + Zone:Zone:Read).
  4. Ports ouverts : 25 (SMTP serveur), 587 (submission STARTTLS), 465 (optionnel SMTPS).
  5. Résolution DNS : mail.domaine.tld (ou smtp.) pointe vers l’IP publique du serveur.
  6. Version Exim4 ≥ 4.94 recommandée (TLS moderne & SNI corrects).

4. Installation & Mise à Jour d’acme.sh

4.1 Installation

curl https://get.acme.sh | sh
source ~/.bashrc   # ou relogin pour charger alias
~/.acme.sh/acme.sh --version

4.2 Structure

~/.acme.sh/
  ├── acme.sh              (script)
  ├── domaine.tld_ecc/     (cert ECC)
  └── domaine.tld/         (cert RSA si émis)

4.3 Forcer Let’s Encrypt comme CA

acme.sh --set-default-ca --server letsencrypt

4.4 Mise à jour

acme.sh --upgrade
# rollback (rare) : acme.sh --upgrade --rollback

5. Émission d’un Certificat (Wildcard / Multi‑SAN)

5.1 Créer un Token Cloudflare minimal

Permissions : Zone.Zone:Read, Zone.DNS:Edit, restreint à la zone concernée.

5.2 Exporter les variables d’environnement

export CF_Token="CLF_T0K3N_LONG"
# (Ancienne méthode si token indisponible)
# export CF_Key="GLOBAL_API_KEY"
# export CF_Email="email@cloudflare"

Pour vérifier que le token est actif et valide, nous pouvons exécuter la commande :

curl -s -H "Authorization: Bearer $CF_Token"      https://api.cloudflare.com/client/v4/user/tokens/verify | jq .

5.3 Commande d’émission (ECC recommandé)

acme.sh --issue \
  -d domaine.tld \
  -d '*.domaine.tld' \
  --dns dns_cf \
  --keylength ec-256

5.4 Vérifier SAN & Dates

openssl x509 -in ~/.acme.sh/domaine.tld_ecc/domaine.tld.cer -noout -ext subjectAltName -dates -subject

Attendu : DNS:domaine.tld, DNS:*.domaine.tld.

5.5 Variante RSA (si compat héritage nécessaire)

acme.sh --issue -d domaine.tld -d '*.domaine.tld' --dns dns_cf --keylength 2048

5.6 Erreurs Fréquentes

ErreurCauseSolution
« No CF token specified »Variable non exportéeExporter CF_Token avant commande
TXT not foundPropagation DNS lenteAttendre + utiliser --dnssleep si besoin
Rate limitTrop d’émissionsRegrouper SAN, éviter --force répétitif
SAN manquant (pas wildcard)Oubli -d '*.domaine.tld'Ré‑émettre avec wildcard + --force

6. Stratégies de Gestion de Certificats Exim4

StratégieDescriptionQuandAvantagesInconvénients
Wildcard uniquedomaine.tld + *.domaine.tldMulti sous‑domaines simplesUn seul renouvellementRé‑émission pour autre domaine racine
Multi‑SANmail.domaineA, mail.domaineB, etc.Peu de domaines diversUn cert pour toutAjout = ré‑émettre
Certs multiples (SNI)1 cert par mail.domaineXHébergement multi‑clientsIsolation, révocation cibléeGestion plus complexe
ECC onlyCourant moderneClients récentsHandshake plus légerVieux MTA/clients rares incompatibles
ECC + RSADeux jeux de certsEnvironnement hétérogèneCompat maximaleMaintenance double

Conseil : commencer avec un wildcard ECC unique. Ajouter RSA uniquement si un client concret échoue.

7. Comprendre la Config TLS Générée par Hestia

Hestia injecte dans la config Exim4 (fichier auto‑généré) une expression SNI ressemblant à :

tls_certificate = \
  ${if and { { eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}} \
             { exists{/usr/local/hestia/ssl/mail/$tls_in_sni.crt} } } \
     {/usr/local/hestia/ssl/mail/$tls_in_sni.crt} \
     {/usr/local/hestia/ssl/certificate.crt} }

Même logique pour tls_privatekey.

Logique :

  1. Si un fichier spécifique /usr/local/hestia/ssl/mail/<FQDN>.crt existe (ex: mail.domaine.tld.crt), il est utilisé.
  2. Sinon Exim4 retombe sur le fallback global /usr/local/hestia/ssl/certificate.crt (souvent auto‑signé par défaut).

Conséquence : Vous devez déployer le certificat wildcard dans ces chemins pour qu’Exim l’utilise sans modifier la macro.

8. Méthodes de Déploiement du Certificat

8.1 Déploiement direct (recommandé)

acme.sh --install-cert écrit directement dans les chemins qu’Exim attend.

acme.sh --install-cert -d domaine.tld --ecc \
  --fullchain-file /usr/local/hestia/ssl/mail/mail.domaine.tld.crt \
  --key-file      /usr/local/hestia/ssl/mail/mail.domaine.tld.key \
  --reloadcmd     "chown root:Debian-exim /usr/local/hestia/ssl/mail/mail.domaine.tld.key; \
                    chmod 640 /usr/local/hestia/ssl/mail/mail.domaine.tld.key; \
                    cp /usr/local/hestia/ssl/mail/mail.domaine.tld.crt /usr/local/hestia/ssl/certificate.crt; \
                    cp /usr/local/hestia/ssl/mail/mail.domaine.tld.key /usr/local/hestia/ssl/certificate.key; \
                    chown root:Debian-exim /usr/local/hestia/ssl/certificate.key; \
                    chmod 640 /usr/local/hestia/ssl/certificate.key; \
                    chmod 644 /usr/local/hestia/ssl/mail/mail.domaine.tld.crt /usr/local/hestia/ssl/certificate.crt; \
                    systemctl reload exim4"

8.2 Variante Script (multi‑domaines)

Créer /usr/local/bin/deploy-mail-cert.sh :

#!/usr/bin/env bash
set -euo pipefail
FQDN="$1"      # ex: mail.domaine.tld
CRT_SRC="$2"   # fullchain source
KEY_SRC="$3"
MAIL_DIR="/usr/local/hestia/ssl/mail"
mkdir -p "$MAIL_DIR"
cp "$CRT_SRC" "$MAIL_DIR/$FQDN.crt"
cp "$KEY_SRC" "$MAIL_DIR/$FQDN.key"
chown root:Debian-exim "$MAIL_DIR/$FQDN.key"
chmod 640 "$MAIL_DIR/$FQDN.key"; chmod 644 "$MAIL_DIR/$FQDN.crt"
# Met à jour fallback (optionnel)
cp "$CRT_SRC" /usr/local/hestia/ssl/certificate.crt
cp "$KEY_SRC" /usr/local/hestia/ssl/certificate.key
chown root:Debian-exim /usr/local/hestia/ssl/certificate.key
chmod 640 /usr/local/hestia/ssl/certificate.key; chmod 644 /usr/local/hestia/ssl/certificate.crt
systemctl reload exim4

chmod +x /usr/local/bin/deploy-mail-cert.sh

Installer :

acme.sh --install-cert -d domaine.tld --ecc \
  --fullchain-file /tmp/fullchain.pem \
  --key-file      /tmp/priv.key \
  --reloadcmd     "/usr/local/bin/deploy-mail-cert.sh mail.domaine.tld /tmp/fullchain.pem /tmp/priv.key"

8.3 Comparatif

MéthodeAvantageInconvénient
DirecteSimplicité, aucun fichier intermédiaireMoins flexible multi‑cibles
ScriptExtensible (multi FQDN, logs)Maintenance script
SymlinkUn seul masterFragile lors d’écrasement Hestia

9. Configuration TLS Exim4 : Paramètres Clés

Créer un fichier macros précoce : /etc/exim4/conf.d/main/01_local_tls_macros :

MAIN_TLS_ENABLE = yes
MAIN_TLS_ADVERTISE_HOSTS = *
# Ports SMTP (server, submission, SMTPS)
daemon_smtp_ports = 25 : 587 : 465
# SMTPS implicite
tls_on_connect_ports = 465

(Vous n’indiquez pas ici tls_certificate car l’expression SNI générée par Hestia le gère.)

Masquer AUTH avant TLS (si non déjà présent) dans un override tardif :
/etc/exim4/conf.d/main/40_local_auth_tls.conf :

auth_advertise_hosts = ${if eq{$tls_in_cipher}{}{}{*}}

Regénérer & recharger :

update-exim4.conf
systemctl reload exim4

9.1 Vérifier paramètres effectifs

exim -bP daemon_smtp_ports
exim -bP tls_on_connect_ports
exim -bP tls_certificate
exim -bP tls_privatekey

10. Port 465 (SMTPS) vs 587 (Submission)

Aspect465 (SMTPS implicite)587 (Submission STARTTLS)
Standardisation actuelleHéritage (réactivé officiel RFC 8314)Recommandé moderne
Négociation TLSDirecte (moins d’aller‑retour)Upgrade après EHLO
Compat clients anciensCertains insistent sur 465Tous supportent 587
Durcissement AUTHDéjà chiffré dès connexionNécessite cacher AUTH avant TLS

Conseil : Garder 587 obligatoire + 465 pour compat (ou monitoring séparé). Si simplification : retirer 465 (enlever de daemon_smtp_ports).

11. Sécurité & Bonnes Pratiques TLS SMTP

11.1 Protocoles & Ciphers

Dans un override (ex. 50_local_tls_policies.conf) :

openssl_options = +no_sslv2 +no_sslv3 +no_tlsv1 +no_tlsv1_1
# (GnuTLS selon build ; adapter si nécessaire)

Pour ciphers, Exim peut utiliser tls_require_ciphers (OpenSSL) :

tls_require_ciphers = HIGH:!aNULL:!MD5:!RC4:!3DES:!CAMELLIA:!DES:!EXP:!PSK:!SRP:!DSS

11.2 Chaîne Complète

Toujours déployer le fullchain (cert + intermédiaire). Sans cela : Verify return code: 21 côté clients.

11.3 Permissions Clé

chown root:Debian-exim /usr/local/hestia/ssl/mail/mail.domaine.tld.key
chmod 640 /usr/local/hestia/ssl/mail/mail.domaine.tld.key

11.4 STARTTLS Opportuniste vs Strict

  • Port 25 (serveur à serveur) : opportuniste (permettre plain fallback pour compat, sauf politique MTA‑STS / DANE avancée).
  • Port 587 : exiger TLS avant AUTH (déjà couvert par auth_advertise_hosts).

11.5 MTA-STS / DANE (aperçu)

Non traité en détail ici ; préparez en veillant à une politique TLS stable & publication DNS (TLSA) si adoption DANE.

12. Automatisation du Renouvellement

acme.sh crée un cron quotidien (~/.acme.sh/acme.sh --cron). Le renouvellement se lance à ~60 jours pour un cert LE (validité 90 jours).

12.1 Test de renouvellement forcé

acme.sh --renew -d domaine.tld --ecc --force

Vérifier que le hook :

  • Met à jour les fichiers.
  • Recharge Exim4 (systemctl reload exim4).

12.2 Vérification Post‑Renouvellement

openssl s_client -connect mail.domaine.tld:587 -starttls smtp -servername mail.domaine.tld </dev/null 2>/dev/null | openssl x509 -noout -dates

Comparer la nouvelle date notAfter.

12.3 Monitoring Expiration (cron simple)

#!/usr/bin/env bash
CRT="/usr/local/hestia/ssl/mail/mail.domaine.tld.crt"
EXP=$(date -d "$(openssl x509 -in $CRT -noout -enddate | cut -d= -f2)" +%s)
NOW=$(date +%s)
DAYS=$(( (EXP-NOW)/86400 ))
if [ $DAYS -lt 20 ]; then
echo "ALERTE: Certificat SMTP expire dans $DAYS jours" | mail -s "Certificat SMTP" [email protected]
fi

13. Tests & Vérifications Post‑Déploiement

13.1 STARTTLS Submission (587)

openssl s_client -connect mail.domaine.tld:587 -starttls smtp -servername mail.domaine.tld </dev/null 2>/dev/null | grep -E 'subject=|issuer=|Verify'

13.2 SMTPS (465)

openssl s_client -connect mail.domaine.tld:465 -servername mail.domaine.tld </dev/null 2>/dev/null | grep -E 'subject=|issuer=|Verify'

13.3 Vérifier annonce AUTH après TLS

  1. Lancer handshake STARTTLS.
  2. Après chiffrement, envoyer :
EHLO test

Attendu : ligne 250-AUTH PLAIN LOGIN (si auth active), absente en clair avant STARTTLS.

13.4 Paramètres Exim

exim -bP tls_certificate
tls_privatekey=$(exim -bP tls_privatekey)

13.5 Outils externes

  • CheckTLS ou Hardenize : audit public.
  • SSL Labs (SMTP) via projets tiers (affiche protocole, ciphers, chaîne).

14. Dépannage (Troubleshooting)

SymptômeAnalyseCorrectif
tls_certificate = \ (vide)Expression SNI retombe sur fallback inexistantDéployer mail.<domaine>.crt ou fallback certificate.crt
Self‑signed toujours présentéFichiers personnalisés absents / non lisiblesCopier cert/clé dans /usr/local/hestia/ssl/mail/, permissions 640 clé
Cannot load private keyPermissions ou format cléchown root:Debian-exim, chmod 640, vérifier BEGIN PRIVATE KEY
Pas de STARTTLS sur 587MAIN_TLS_ENABLE absent / macro non chargéeAjouter macros + update-exim4.conf
AUTH visible avant TLSauth_advertise_hosts non configuréAjouter override (voir §9)
Erreur verify code 21Intermédiaire manquantUtiliser fullchain en déploiement
ECC rejeté par clientClient obsolèteFournir aussi un RSA (multi-cert + SNI ou multi-SAN)
Nouveau domaine non chiffréCert non déployé sous nom exactCréer mail.nvdom.tld.crt/.key + reload

15. Scénarios d’Évolution

ScénarioAction rapide
Ajouter mail.client2.tldÉmettre cert dédié ou ré‑émettre multi‑SAN ; déployer mail.client2.tld.crt
Passer d’un wildcard à multi‑certGénérer certs individuels + script boucle copie
Migrer HTTP‑01 → DNS‑01Émettre nouveau cert DNS‑01 (sans downtime), recharger Exim
Ajouter RSA parallèleÉmettre RSA, adapter expression SNI (préfixer nom), prioriser ECC

16. Monitoring & Alerting

16.1 Indicateurs Clés

  • Jours avant expiration
  • Pourcentage connexions TLS vs total (analyser logs
  • Échecs handshake / erreurs clé

16.2 Script Stats (exemple simple)

grep -i STARTTLS /var/log/exim4/mainlog | wc -l

(Pour ratio, comparer aux lignes <= / => trafic total.)

16.3 Intégration Basique

  • Cron journalier : test openssl + si échec → mail admin.
  • Webhook (curl) vers outil externe (UptimeRobot, Healthchecks.io).

17. FAQ Spécifique Exim4

Wildcard ou multi‑cert ? Wildcard unique suffit dans 80% des cas. Multi‑cert si clients isolés / résiliation granulaire.

Faut‑il garder le fallback Hestia auto‑signé ? Non, remplacez-le par un public pour éviter présentation accidentelle self‑signed.

Comment forcer AUTH seulement après TLS ? auth_advertise_hosts = ${if eq{$tls_in_cipher}{}{}{*}}.

Dois‑je maintenir le port 465 ? Optionnel. Conservez-le si des clients historiques l’utilisent ; sinon 587 suffit.

Puis-je partager un cert entre domaines non inclus ? Non. Chaque FQDN demandé par le client doit figurer en SAN ou être couvert par un wildcard approprié.

Pourquoi le cert ne change pas après renouvellement ? Hook absent ou pas de reload Exim (systemctl reload exim4).

18. Checklist Finale Mise en Production

ItemOK
Cert wildcard émis (SAN correct)
Fichiers déployés /usr/local/hestia/ssl/mail/mail.domaine.tld.*
Permissions clé 640 root:Debian-exim
Fallback remplacé (/usr/local/hestia/ssl/certificate.crt)
daemon_smtp_ports inclut 587 (et 465 si voulu)
tls_on_connect_ports contient 465 (si utilisé)
AUTH masqué avant TLS
Tests openssl 25/587/465 OK (verify code 0)
Cron acme.sh présent & test renew forcé OK
Monitoring expiration (<20j) actif
Logs Exim sans erreurs TLS

19. Annexes

19.1 Commandes acme.sh Essentielles

# Wildcard ECC
a cme.sh --issue -d domaine.tld -d '*.domaine.tld' --dns dns_cf --keylength ec-256
# Installation + hook
acme.sh --install-cert -d domaine.tld --ecc --fullchain-file /usr/local/hestia/ssl/mail/mail.domaine.tld.crt --key-file /usr/local/hestia/ssl/mail/mail.domaine.tld.key --reloadcmd "systemctl reload exim4"
# Forcer renouvellement (test)
acme.sh --renew -d domaine.tld --ecc --force

19.2 Exemple 01_local_tls_macros

MAIN_TLS_ENABLE = yes
MAIN_TLS_ADVERTISE_HOSTS = *
daemon_smtp_ports = 25 : 587 : 465
tls_on_connect_ports = 465

19.3 Séquence de Tests OpenSSL (copier-coller)

# Submission STARTTLS
openssl s_client -connect mail.domaine.tld:587 -starttls smtp -servername mail.domaine.tld </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
# SMTPS
openssl s_client -connect mail.domaine.tld:465 -servername mail.domaine.tld </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
# Port 25 (opportuniste)
openssl s_client -connect mail.domaine.tld:25 -starttls smtp -servername mail.domaine.tld </dev/null 2>/dev/null | grep -i "Verify return code"

19.4 Exemple Hook Multi‑Actions Minimal

#!/usr/bin/env bash
# /usr/local/bin/deploy-mail-cert.sh
set -e
CRT="/usr/local/hestia/ssl/mail/mail.domaine.tld.crt"
KEY="/usr/local/hestia/ssl/mail/mail.domaine.tld.key"
chown root:Debian-exim "$KEY"; chmod 640 "$KEY"; chmod 644 "$CRT"
cp "$CRT" /usr/local/hestia/ssl/certificate.crt
cp "$KEY" /usr/local/hestia/ssl/certificate.key
chown root:Debian-exim /usr/local/hestia/ssl/certificate.key
chmod 640 /usr/local/hestia/ssl/certificate.key; chmod 644 /usr/local/hestia/ssl/certificate.crt
systemctl reload exim4

19.5 Profil Ciphers (intermédiaire) Exemple

# OpenSSL style
# (Adapter selon exigences PCI/legacy)
tls_require_ciphers = "ECDHE+AESGCM:ECDHE+CHACHA20:!aNULL:!MD5:!RC4:!3DES:!DES:!EXP:!DSS"
TL:DR - smtp tls

20. TL;DR / Résumé Express

  1. Émettre wildcard via acme.sh --issue -d domaine -d '*.domaine' --dns dns_cf.
  2. Installer cert directement dans /usr/local/hestia/ssl/mail/mail.domaine.crt|.key avec --install-cert + hook reload Exim.
  3. Vérifier macros Exim : MAIN_TLS_ENABLE, daemon_smtp_ports, tls_on_connect_ports.
  4. Masquer AUTH avant TLS (auth_advertise_hosts).
  5. Tester openssl sur 587 (STARTTLS) & 465 (SMTPS) → verify code 0.
  6. Remplacer fallback auto‑signé Hestia par le public.
  7. Cron acme.sh gère renouvellement ; script hook recharge Exim.
  8. Monitorer expiration & erreurs handshake.
  9. Ajouter nouveaux domaines en déposant leurs .crt/.key SNI.
  10. Garder config simple (ECC unique) jusqu’à besoin réel de RSA / multi‑cert.
Les mots clés rattachés à cet article : Cryptage  -  Email  -  Smtp  -  SSL

Nos clients

Une vingtaine de clients nationaux et internationaux