Skip to main content
Un seul certificat sert toutes les surfaces TLS de l’instance : HTTPS/JMAP (443), la soumission STARTTLS (587), SMTPS (465) et IMAPS (993). Qui l’obtient dépend de la topologie choisie au premier démarrage.

Topologie directe : ACME intégré

Quand OxiMail possède les ports 80/443, il provisionne et renouvelle lui-même son certificat auprès de Let’s Encrypt :
Le premier certificat est obtenu au premier démarrage (l’assistant l’attend jusqu’à 90 secondes) ; les renouvellements sont automatiques avant expiration. Le port 80 doit rester joignable depuis Internet pour le défi HTTP-01. L’assistant publie aussi un enregistrement CAA qui restreint l’émission à Let’s Encrypt : un durcissement par défaut cohérent avec cette configuration. Un renouvellement ne redémarre jamais rien. Le nouveau certificat est permuté atomiquement (ArcSwap, ADR-016) : les connexions en cours terminent sur l’ancien, les nouvelles poignées de main reçoivent le nouveau, sur tous les écouteurs à la fois, SMTP et IMAP compris. L’écouteur HTTPS suit aussi : il gardait jusqu’ici le certificat de son démarrage jusqu’au redémarrage suivant, si bien qu’après un renouvellement ou une rotation de clé il servait encore le certificat précédent alors que l’enregistrement TLSA de son port avait changé. Un renouvellement raté garde le certificat en service. Quand une commande échoue, le certificat servi reste en place tant qu’il n’a pas expiré, et rien n’est republié : les TLSA gardent l’épingle de la clé réellement servie. L’échec est retenté après 1 heure, puis 2, 4, 8 et 16 heures, puis une fois par jour. Seul un certificat expiré cède la place à un autosigné, et ce substitut garde la clé servie : l’empreinte publiée reste valide (une empreinte 3 1 1 ignore les dates). Il fabriquait une nouvelle clé et réépinglait les enregistrements TLSA sur elle. Il en va de même au démarrage : si la commande de démarrage échoue, un certificat persisté non expiré est servi (même entré dans sa fenêtre de renouvellement, ou privé d’un nom tout juste configuré) et la commande est retentée selon ce calendrier. Une box qui n’a rien de persisté sert un autosigné provisoire, et cet autosigné compte lui-même comme une raison de renouveler : il est retenté selon le même calendrier. Un renouvellement raté remplaçait un certificat encore valide par un autosigné et republiait l’épingle DANE de cette clé autosignée, et une première commande ratée laissait la box sur son autosigné pendant une soixantaine de jours. Ajouter un nom renouvelle. La décision de renouveler compare les noms réellement portés par le certificat servi à [tls] acme_domains, pas seulement sa date d’expiration : un nom ajouté à la liste est obtenu au prochain démarrage, et le journal dit laquelle des deux raisons s’applique, « la date approche » ou « il manque un nom que vous avez configuré », puisqu’elles n’appellent pas la même réaction. Le contrôle a lieu au démarrage, pas vingt-quatre heures après, parce qu’un redémarrage après un changement de réglage est le moment où l’on attend que le changement s’applique. Il ne regardait que la date, si bien que la box gardait son ancien certificat jusqu’à deux mois pendant que le nouveau nom refusait toute connexion, avec un journal qui annonçait le certificat chargé.

Topologie proxy inverse

Derrière Caddy ou Nginx, le proxy possède 80/443 et le certificat des noms web. L’assistant écrit pourtant acme_enabled = true : OxiMail commande le certificat de son propre nom d’hôte, celui des ports mail, et le proxy relaie le chemin du challenge HTTP-01 vers le http_bind d’OxiMail. Deux points restent importants :
  • SMTP (25/587/465) et IMAPS (993) ne passent pas par le proxy : OxiMail y termine le TLS lui-même, avec le certificat qu’il a commandé. L’autre voie est acme_enabled = false avec [tls] cert_path/key_path pointés sur les fichiers de certificat du proxy ; OxiMail les recharge alors à chaud quand ils changent, mais qui tient le proxy tient la clé privée du nom mail. Choisissez l’une des deux. acme_enabled = true et un cert_path ne forment pas un mode : les ports mail démarrent sur le fichier, le premier renouvellement ACME le remplace, la surveillance du fichier le remet, et les enregistrements TLSA suivent le dernier des deux. oximail doctor le signale sous tls_cert_source, et oximail setup verify avertit.
  • Le proxy doit transmettre tout sauf le chemin de défi ACME, avec X-Forwarded-For depuis une adresse de [server] trusted_proxies : voir premier démarrage pour l’extrait généré et la règle CORS. Un proxy sur la même machine atteint plutôt OxiMail par un socket Unix ([server] bind = "unix:<chemin>", ce que l’assistant installe) : seul le groupe du proxy peut l’ouvrir, le pair est le proxy, une requête sans en-tête de transfert qui nomme un client est refusée (400), et aucune entrée trusted_proxies n’est nécessaire ; doctor client_address_mode avertit quand il en reste une. Une entrée de trusted_proxies qui n’est pas une adresse de loopback permet à qui se trouve à cette adresse de fixer l’IP cliente que la box journalise, limite et bannit. oximail doctor --reachability vérifie, sous trusted_proxies, que chaque entrée de ce genre sert encore le nom de la box sur 443, pour qu’un proxy parti ailleurs ne reste pas de confiance.
Ce que garde un proxy, et qu’une box directe n’a pas. Une box qui termine elle-même le 443 offre HTTP/2 et HTTP/1.1 (ALPN h2, http/1.1). Elle n’offre ni HTTP/3 ni Encrypted Client Hello : la bibliothèque TLS d’OxiMail n’a pas encore de côté serveur pour ECH. Si les noms web ont besoin d’ECH, gardez devant eux un proxy qui le prend en charge.

Le couplage DANE

Si vous publiez des enregistrements DANE TLSA (authentification du courrier), l’enregistrement qu’OxiMail publie est l’épingle 3 1 1, une empreinte de la clé publique du certificat. Un renouvellement certifie par défaut la même clé ([tls] acme_reuse_key = true) : l’épingle ne change pas au renouvellement, et un expéditeur qui valide DANE ne rencontre jamais un certificat qui ne correspond plus à l’enregistrement qu’il a en cache. acme_reuse_key = false donne une clé neuve à chaque renouvellement : l’épingle bouge alors à chaque fois et les TLSA doivent suivre. Si la clé stockée ne se relit pas, le renouvellement certifie une clé neuve et journalise une erreur qui annonce le changement d’épingle. dane_enabled = true (le défaut) exige toujours un fournisseur [dns] configuré : après un renouvellement, OxiMail republie lui-même les TLSA (API Cloudflare, ou mise à jour dynamique sur votre propre serveur DNS avec rfc2136, voir les fournisseurs DNS), ou journalise l’état des enregistrements en mode manual. Un serveur avec DANE actif et sans fournisseur DNS refuse de démarrer plutôt que de vous préparer une casse silencieuse. Un certificat renouvelé hors d’OxiMail avec une nouvelle clé attend son empreinte. Avec [tls] cert_path, le surveillant de fichiers mettait d’abord en service le certificat renouvelé, puis réépinglait après coup. Quand la source (le client ACME d’un proxy inverse, par exemple) fabriquait une nouvelle clé à chaque renouvellement, chaque expéditeur qui valide DANE voyait une discordance pendant au moins le TTL, et différait le courrier, à chaque renouvellement. Quand OxiMail publie lui-même les enregistrements TLSA (fournisseur cloudflare ou rfc2136, DANE actif), le surveillant publie désormais l’empreinte 3 1 1 de la nouvelle clé à côté de celle servie, continue de servir le certificat actuel, et bascule une fois l’empreinte publiée depuis deux TTL (2 x 3600 s, RFC 7671 §8.1) ; l’ancienne empreinte est alors retirée. Un certificat servi à environ trois heures de son expiration est basculé tout de suite. Le journal annonce l’attente et nomme le remède à la source : garder la clé d’un renouvellement à l’autre (reuse_private_keys dans Caddy, par exemple), et plus aucun renouvellement n’attend. oximail cert renew --force garde aussi la clé quand acme_reuse_key est actif : seul le certificat est mis de côté, et une copie de la clé est rangée sous key.pem.pre-renew-<horodatage>.

Changer de clé volontairement

Changer de clé est un geste délibéré, fait de sorte qu’un validateur ne tienne jamais seulement une épingle que le certificat servi ne vérifie pas (publier avant de basculer, RFC 7671 §8.1) :
  1. Publier. Sans --apply, la commande dit ce qu’elle ferait. --apply génère une clé neuve, la met en attente et publie son épingle 3 1 1 à côté de l’épingle actuelle sur chaque port épinglé : 25, 465 et 587, ou 25 seul sur un MX de secours (quels ports). Quand [dns] provider vaut "cloudflare" ou "rfc2136" et [smtp] dane_enabled = true, OxiMail publie lui-même les enregistrements ; sinon la commande les affiche pour que vous les publiiez à la main, avec un TTL de 3600 secondes au plus.
  2. Attendre. Le serveur vérifie une fois par heure, et une fois au démarrage. Il attend que le DNS public montre la nouvelle épingle sur chacun de ces ports, puis encore deux TTL (2 x 3600 s), pour que chaque résolveur qui gardait l’ancien jeu ait relu le nouveau. Il ne bascule jamais avant. Si la nouvelle épingle disparaît du DNS après avoir été vue, l’attente recommence.
  3. Basculer. Le serveur commande un certificat sur la clé en attente et le sert, sans redémarrage. Dans ce même cas (fournisseur cloudflare ou rfc2136 et DANE actif), le rappel de renouvellement retire ensuite l’ancienne épingle ; sinon retirez vous-même les anciens enregistrements 3 1 1 quand le journal annonce la bascule. Une bascule qui échoue laisse le certificat précédent en service et se retente à la vérification suivante.
Relancer la commande pendant une rotation montre où elle en est (--json pour les scripts), et --apply republie alors une épingle dont la publication a échoué. oximail dane rotate --cancel --apply abandonne la rotation avant la bascule : la clé en attente est rangée et la nouvelle épingle retirée par OxiMail (fournisseur cloudflare ou rfc2136 et DANE actif) ou laissée à retirer par vous. Code de sortie 0 quand c’est fait ou lu, 1 quand l’épingle n’a pas pu être publiée sur tous les ports (relancez --apply), 2 en cas de refus ou d’échec. La rotation exige [tls] acme_enabled, parce que la bascule est une commande de certificat ; sinon la commande refuse. Derrière un proxy inverse, changez la clé là où le certificat est fabriqué, puis réépinglez avec oximail dane publish. oximail doctor rend compte d’une rotation sous dane_key_rotation : son étape et son âge, avec un avertissement quand la nouvelle épingle n’est toujours pas visible après 24 heures, ou quand la bascule a plus de deux heures de retard. L’état de la rotation vit dans le répertoire acme/ du répertoire de données (le parent de [storage] blob_path) : key-rotation.json et la clé en attente key.next.pem, si bien qu’un redémarrage reprend là où la rotation s’était arrêtée. À la bascule, la clé précédente est gardée sous key.pem.pre-rotate-<horodatage>. Le fichier de la clé en attente est renommé, jamais supprimé : key.next.pem.switched-<horodatage> ou key.next.pem.cancelled-<horodatage>.

Échange de clés post-quantique

Chaque surface TLS qu’OxiMail termine lui-même (25, 465, 587, 993, et le 443 quand aucun frontal ne se trouve devant) propose en tête le groupe hybride X25519MLKEM768, avec le X25519 classique en repli. Rien n’est cassé au passage : un pair qui ne connaît pas le groupe hybride négocie X25519 exactement comme avant. Il n’y a pas de réglage pour l’activer, c’est la posture livrée. La menace visée est « récolter maintenant, déchiffrer plus tard » : un adversaire enregistre le trafic d’aujourd’hui pour le déchiffrer quand la machine capable de le faire existera. Être en retard là-dessus ne se rattrape pas après coup, d’où un défaut plutôt qu’une option. Ce n’est pas théorique pour le courrier : Gmail propose déjà le groupe hybride sur 25, 465, 587 et 993, le courrier sortant vers lui négocie donc du post-quantique dès aujourd’hui. Vérifiez au lieu de supposer. Cette propriété précise a été fausse en silence pendant des mois ici : la fonctionnalité était compilée alors que le fournisseur de cryptographie installé n’en avait aucune implémentation, si bien que chaque session retombait sur le X25519 classique pendant que la configuration se lisait comme le contraire. Un repli de ce genre est invisible : aucune erreur, aucune ligne de journal, rien qui échoue. Avec OpenSSL 3.5 ou plus récent :
Lancez-le sur chaque port que vous servez. Un frontal placé devant le 443 répond pour lui-même, pas pour OxiMail : contrôlez les ports courrier séparément. Les connexions sortantes utilisent la même pile. Le client HTTP qui sert les webhooks, le push et le déploiement des liens tourne sur la même implémentation TLS que le serveur : ces requêtes ont donc gagné le groupe hybride elles aussi. Il fait confiance au magasin de certificats du système d’exploitation et non à une liste de racines embarquée, et c’est délibéré : un point de terminaison dont le certificat remonte à une autorité privée installée sur la machine continue de fonctionner.

Inspecter et dépanner

setup verify lit cert_strategy (operator-cert-path quand cert_path est posé, et il gagne ; acme-http-01 ; none) et renewal_owner (operator, oximail, none) dans la configuration, contrôle le certificat lui-même (un fichier cert_path absent, ou un certificat ACME encore en attente pendant que la box sert un autosigné), nomme les trois pannes classiques d’après installation avec leur remède (DNS non propagé ou qui résout ailleurs, un CDN par exemple ; certificat en attente ; port 25 sortant bloqué, un échec quand la box envoie en direct et un avertissement quand un relais porte tout le courrier sortant), et liste egress_endpoints, ce que la box doit pouvoir joindre déduit de sa configuration (SMTP :25, DNS, l’autorité ACME si active, l’API Cloudflare si configurée, le rapport d’usage s’il est actif), pour un pare-feu en refus par défaut. Code de sortie 0, 1 dégradé (un avertissement, une pièce facultative absente), 2 un contrôle en échec ; chaque contrôle non réussi porte un champ remediation (CLI). doctor pose une seconde question que le contrôle du certificat ne peut pas poser : si l’utilisateur du service peut lire le certificat, sa clé, les clés de signature du courrier et celle des notifications. Un certificat valide quand on le lit en root, mais lien vers le magasin d’un autre logiciel dont l’utilisateur oximail ne peut pas traverser les répertoires, démarre très bien le service et ne chiffre rien ; le contrôle demande la réponse au système au lieu de réimplémenter les règles de permission, donc la traversée des répertoires est couverte, et il nomme le fichier, son propriétaire et le maillon exact qui bloque. Il s’exécute contre l’utilisateur de l’unité que ce binaire génère, si bien que sur une box encore en root il est un pré-vol de la bascule. Échecs courants :
  • Port 80 injoignable : le défi HTTP-01 ne peut pas aboutir. Ouvrez-le dans le pare-feu ou le groupe de sécurité ; il ne sert jamais que les défis et les redirections.
  • Limité par Let’s Encrypt : des tentatives d’émission échouées en boucle (généralement une erreur DNS) peuvent atteindre les limites par domaine de LE ; corrigez la cause avant de réessayer. Les tentatives du serveur lui-même s’espacent jusqu’à une commande par jour (voir « un renouvellement raté » plus haut), si bien que c’est d’ordinaire un oximail cert renew --force relancé en boucle qui atteint la limite.
  • Des expéditeurs DANE rebondissent après un renouvellement : la clé servie a changé et les TLSA n’ont pas suivi. Avec acme_reuse_key actif, un renouvellement garde la clé ; une clé neuve veut dire acme_reuse_key = false ou une clé stockée illisible (le journal dit laquelle). Vérifiez la configuration du fournisseur [dns] et les journaux de renouvellement, et comparez avec oximail dane verify.
Avec l’ACME intégré, le certificat, sa clé et le compte ACME (cert.pem, key.pem, account.json) vivent dans acme/ sous le répertoire de données, le parent de [storage] blob_path (/var/lib/oximail/acme/ avec les chemins par défaut de l’assistant). oximail backup ne copie pas ce répertoire : il sauvegarde la base et les blobs. Gardez-le dans la sauvegarde de l’hôte si vous publiez DANE, car une key.pem perdue donne une clé neuve à l’émission suivante, donc une nouvelle épingle 3 1 1. Avec cert_path/key_path, les fichiers sont là où ces clés pointent. L’assistant d’installation crée un /etc/oximail/tls/ vide, un endroit commode pour une telle copie ; le serveur lui-même n’y écrit rien.