bg-tutorials

Comment configurer un certificat SSL dans HAProxy

HAProxy est un répartiteur de charge TCP et HTTP qui termine le TLS, ce qui signifie qu’il déchiffre le trafic en périphérie et transmet du HTTP en clair à vos serveurs backend. C’est ce qui en fait la seule machine du parcours qui a besoin du certificat, et elle veut ce certificat sous une forme précise : un seul fichier, contenant le certificat, les intermédiaires éventuels et la clé privée.

Ce guide couvre l’ensemble du parcours : générer une CSR, assembler le fichier PEM, rédiger le frontend et le backend, vérifier la configuration et recharger sans interrompre les connexions actives. Les commandes ont été exécutées avec HAProxy 3.4, la branche à support à long terme actuelle, publiée en juin 2026 et maintenue jusqu’au T2 2031.

Ce que HAProxy attend : un seul fichier PEM

La plupart des serveurs prennent le certificat, la chaîne et la clé comme trois paramètres distincts. HAProxy n’en prend qu’un seul. Son manuel de configuration décrit le mot-clé crt comme désignant « un fichier PEM contenant à la fois les certificats requis et les clés privées associées », construit en concaténant des fichiers PEM, et ajoute que « si votre CA nécessite un certificat intermédiaire, celui-ci peut aussi être concaténé dans ce fichier ».

Deux comportements méritent d’être connus avant de commencer, car ils vous font gagner du temps par la suite :

  • La clé peut se trouver à côté du certificat plutôt qu’à l’intérieur. Si le fichier ne contient aucune clé privée, HAProxy recherche le même chemin avec .key ajouté. Ainsi, mydomain.pem plus mydomain.pem.key fonctionne aussi bien qu’un seul fichier combiné.
  • Vous pouvez pointer crt vers un répertoire. HAProxy charge tous les fichiers qu’il y trouve et sélectionne le bon certificat pour chaque requête à l’aide du SNI. C’est ainsi que vous pouvez servir plusieurs sites depuis un seul frontend sans avoir une ligne bind par site.

Générer la CSR et la clé privée

Une CSR est la demande encodée que vous remettez à l’autorité de certification. Générez-la sur la machine HAProxy, ou n’importe où vous pouvez garder la clé privée en sécurité, puisque la clé ne quitte jamais votre côté.

openssl req -new -newkey rsa:2048 -nodes 
  -keyout mydomain.key -out mydomain.csr 
  -subj "/C=US/ST=California/L=San Jose/O=Your Company/CN=mydomain.com" 
  -addext "subjectAltName=DNS:mydomain.com,DNS:www.mydomain.com"

La ligne -addext n’est pas facultative en pratique. Les navigateurs ont cessé de faire correspondre les noms d’hôte au Common Name il y a des années et ne lisent désormais que le Subject Alternative Name, si bien qu’une CSR ne portant qu’un CN produit un certificat qui échoue dans tous les navigateurs actuels. Listez chaque nom que le certificat doit couvrir, y compris le domaine nu et la forme www si vous servez les deux.

Retirez les options -subj et -addext si vous préférez être invité pour chaque champ. Dans les deux cas, vous obtenez deux fichiers : mydomain.csr à soumettre, et mydomain.key à conserver. Vérifiez que la CSR contient bien ce que vous attendez avant de la soumettre, soit avec notre décodeur de CSR, soit localement :

openssl req -noout -text -verify -in mydomain.csr

Vérifiez que les entrées SAN sont bien listées et que la signature se vérifie. Si vous préférez ne pas utiliser du tout la ligne de commande, notre générateur de CSR produit la même paire directement dans le navigateur. Pour en savoir plus sur les commandes sous-jacentes, consultez notre guide des commandes OpenSSL.

Faire délivrer le certificat

Soumettez la CSR à la CA, choisissez le type de certificat qui correspond à ce que vous protégez, et terminez la validation. Un certificat mono-domaine couvre un seul nom d’hôte, un wildcard couvre tous les sous-domaines de premier niveau, et un certificat multi-domaines (SAN) couvre une liste de noms sans lien entre eux. Derrière un répartiteur de charge, le multi-domaines est le choix courant, puisqu’une seule instance HAProxy dessert généralement plusieurs sites.

La CA renvoie une archive contenant votre certificat et la chaîne intermédiaire, généralement sous forme de fichier CA bundle. Les deux sont déjà au format PEM, ce qui est ce dont vous avez besoin. Planifiez le renouvellement dès maintenant plutôt que plus tard : depuis le 15 mars 2026, un certificat TLS reconnu publiquement ne peut être valide plus de 200 jours, une durée qui passera à 100 jours en mars 2027 et à 47 jours en mars 2029, si bien que le remplacement manuel cessera assez vite d’être praticable.

Construire le fichier PEM que HAProxy va lire

Créez un répertoire pour les certificats et assemblez-y le fichier. Regroupez tout au même endroit dès le départ ; répartir cela entre un répertoire personnel, /etc/haproxy et /etc/ssl est le meilleur moyen de finir par modifier un fichier pendant que HAProxy en lit un autre.

sudo mkdir -p /etc/haproxy/certs
sudo chmod 700 /etc/haproxy/certs

Concaténez le certificat, puis les intermédiaires, puis la clé privée. La redirection doit s’exécuter en tant que root, donc passez par un pipe vers tee plutôt que d’écrire sudo cat ... > /etc/haproxy/certs/..., qui échoue avec une erreur de permission car le shell ouvre le fichier de sortie en tant que votre propre utilisateur avant même que sudo ne s’exécute :

cat mydomain.crt intermediate.crt mydomain.key 
  | sudo tee /etc/haproxy/certs/mydomain.pem > /dev/null

Ce fichier contient désormais votre clé privée en texte clair, verrouillez-le donc avant d’aller plus loin :

sudo chown root:root /etc/haproxy/certs/mydomain.pem
sudo chmod 600 /etc/haproxy/certs/mydomain.pem

Des permissions réservées à root sont ici correctes, ce n’est pas un obstacle. HAProxy est démarré avec des privilèges de superutilisateur, ce qui, selon son manuel, est nécessaire pour qu’il puisse ensuite basculer vers son propre utilisateur non privilégié, et c’est durant ce démarrage qu’il lit le certificat. Il n’est pas nécessaire d’élargir les permissions pour que l’utilisateur haproxy puisse lire la clé, et vous ne devriez pas le faire.

Si vous avez construit la CSR sur une autre machine, copiez d’abord les fichiers, puis supprimez les copies du répertoire de transit ensuite :

scp mydomain.crt intermediate.crt mydomain.key sysadmin@haproxy-server:/home/sysadmin/

Configurer HAProxy

Ouvrez /etc/haproxy/haproxy.cfg dans un éditeur en terminal directement sur le serveur, comme nano ou vim. Modifiez-le sur place plutôt que sur un poste de travail, afin de ne jamais recharger un fichier différent de celui que vous avez testé.

Le frontend

Un seul frontend peut accepter à la fois le HTTP en clair et le HTTPS. Liez le port 80 pour la redirection, liez le port 443 avec le certificat, et envoyez tout le reste vers le backend :

frontend web_frontend
    mode http
    bind *:80
    bind *:443 ssl crt /etc/haproxy/certs/mydomain.pem alpn h2,http/1.1

    http-request redirect scheme https code 301 unless { ssl_fc }

    default_backend web_servers

alpn h2,http/1.1 propose HTTP/2 et revient à HTTP/1.1 en repli. La redirection ne se déclenche que lorsque la requête n’est pas arrivée via TLS, ce que teste ssl_fc, si bien que les requêtes sur le port 443 passent directement.

Placez toutes les options TLS sur cette seule ligne bind

C’est là que les configurations HAProxy dérapent le plus souvent, et cela échoue silencieusement. Les guides présentent fréquemment le durcissement TLS comme une seconde étape, en montrant une nouvelle ligne bind pour le port 443 avec des options supplémentaires. Si vous ajoutez cette ligne au lieu de modifier celle qui existe déjà, vous vous retrouvez avec deux lignes bind pour le même port, et HAProxy ne s’en plaint pas. Il démarre, et il ouvre deux sockets d’écoute distincts sur le port 443 avec des paramètres TLS différents. Le socket sur lequel atterrit une connexion donnée n’est pas quelque chose que vous contrôlez, si bien que votre durcissement ne couvre à peu près que la moitié de votre trafic.

La vérification de configuration ne le détecte pas non plus, et sa propre documentation explique pourquoi : -c « effectue uniquement une vérification des fichiers de configuration et se termine avant de tenter le bind ». Un écouteur en double est une condition qui n’apparaît qu’au moment du bind, si bien qu’une simple vérification syntaxique ne la verra jamais.

Définissez plutôt des valeurs par défaut globales, afin que chaque ligne bind du fichier en hérite et qu’il n’y ait rien à dupliquer :

global
    ssl-default-bind-options ssl-min-ver TLSv1.2 prefer-client-ciphers
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Bon à savoir avant de copier ce bloc où que ce soit : ssl-min-ver a déjà pour valeur par défaut TLSv1.2, de l’aveu même de HAProxy. Le régler sur TLSv1.2 ne change donc rien et se contente de documenter l’intention, ce qui est bien, mais ce n’est pas l’amélioration de sécurité qu’on présente souvent. Les deux paramètres de suites de chiffrement, eux, font un vrai travail, et ils sont séparés à dessein : ssl-default-bind-ciphers s’applique à TLS 1.2 et en dessous, ssl-default-bind-ciphersuites s’applique à TLS 1.3. Ne définissez que le premier et vos suites TLS 1.3 resteront à leurs valeurs par défaut.

Le backend

Donnez à chaque serveur une adresse réelle. Cela compte plus qu’il n’y paraît :

backend web_servers
    mode http
    balance roundrobin
    option httpchk GET /
    server web1 10.0.0.11:80 check
    server web2 10.0.0.12:80 check

Une ligne server écrite comme server web1 :80 check, avec l’adresse omise, ne provoque pas d’erreur. HAProxy l’accepte et résout l’adresse manquante en 0.0.0.0, que son manuel traite comme une valeur spéciale signifiant que la connexion est renvoyée vers la même adresse IP à laquelle le client s’est connecté. Cette adresse est HAProxy lui-même, si bien que le backend pointe silencieusement vers le propre port 80 de HAProxy, c’est-à-dire le frontend que vous venez de configurer. Le trafic revient en boucle vers la redirection au lieu d’atteindre une quelconque application, et les vérifications de santé paraissent saines parce que quelque chose écoute effectivement. Si un répartiteur de charge répond à chaque requête HTTPS par une redirection vers lui-même, vérifiez d’abord les lignes server.

Comme HAProxy termine le TLS, les backends reçoivent du HTTP en clair sur le port 80 et n’ont besoin d’aucun certificat propre. Si la politique exige que ce tronçon soit lui aussi chiffré, ajoutez ssl verify required avec un fichier CA sur les lignes server, et pointez-les plutôt vers le port 443.

Transmettez le schéma d’origine au backend. Comme le backend reçoit désormais du HTTP en clair, une application qui génère des URL absolues, comme WordPress, Django et Rails le font toutes, les générera avec http://, ce qui se traduit par du contenu mixte ou par une boucle de redirection créée par l’application elle-même. Ajoutez une ligne au frontend :

http-request set-header X-Forwarded-Proto https if { ssl_fc }

et une au backend, qui transmet aussi la véritable adresse IP du client :

option forwardfor

La plupart des frameworks doivent ensuite être informés qu’il faut faire confiance à ces en-têtes ; cette partie se configure dans l’application, pas dans HAProxy.

Vérifier la configuration avant de l’appliquer

Ne redémarrez jamais un répartiteur de charge sur un fichier non vérifié. Validez d’abord :

sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg

Avec -V, il affiche Configuration file is valid en cas de succès et renvoie un statut de sortie zéro. Sans cette option, le succès est silencieux. Les avertissements éventuels sont signalés que le fichier soit valide ou non, lisez donc la sortie plutôt que de vous fier à l’absence de texte en rouge.

Recharger plutôt que redémarrer

sudo systemctl reload haproxy

La distinction est réelle sur un répartiteur de charge. Un rechargement démarre un nouveau processus et signale à l’ancien de « terminer ce qu’il est en train de faire puis de quitter », si bien que les requêtes déjà en cours se terminent normalement. Un redémarrage signale à l’ancien processus de « se terminer immédiatement sans finir ce qu’il était en train de faire », ce qui coupe les connexions actives, y compris les téléversements et les appels API de longue durée. N’utilisez le redémarrage que lorsqu’un rechargement ne peut pas prendre en compte le changement, par exemple après avoir modifié les paramètres de processus de la section globale.

Confirmez que le service est bien revenu et qu’il écoute sur les deux ports :

sudo systemctl status haproxy
sudo ss -tlnp | grep haproxy

C’est exactement un socket d’écoute par port que vous voulez ici. Deux sur le port 443 signifie que vous avez la ligne bind en double décrite plus haut.

Vérifier que le certificat est bien servi

Vérifiez ce que HAProxy présente réellement, y compris la chaîne, depuis le serveur lui-même :

openssl s_client -connect mydomain.com:443 -servername mydomain.com < /dev/null

Lisez la section Certificate chain en haut de la sortie. Votre certificat devrait apparaître à la profondeur 0 et l’intermédiaire à la profondeur 1. Si la profondeur 1 est absente, l’intermédiaire n’a jamais été intégré au fichier PEM, et le site fonctionnera dans certains navigateurs tout en échouant dans d’autres. Ignorez la ligne Verify return code pour évaluer cela : elle ne rapporte que le verdict de la chaîne, et elle peut se lire comme un succès dans des situations qui n’ont rien à voir avec ce que vous testez.

Confirmez ensuite depuis l’extérieur, là où le résultat reflète ce que reçoivent les vrais visiteurs. Notre SSL Checker indique le certificat, la chaîne et la date d’expiration.

Renouvellements et automatisation

Remplacer le fichier PEM constitue toute la procédure de renouvellement : reconstruisez-le à partir du nouveau certificat et de la même clé ou d’une nouvelle, puis rechargez. Rien dans la configuration HAProxy ne fait référence à la date d’expiration, donc aucune modification de configuration n’est nécessaire tant que le chemin du fichier reste le même.

Avec le raccourcissement des durées de vie des certificats, l’automatisation mérite d’être mise en place dès maintenant. HAProxy a acquis un client ACME intégré dans la version 3.2, configuré via une section acme. Pour le moment, considérez-le comme un aperçu plutôt que comme une infrastructure de production : il est encore marqué expérimental dans la 3.4 et nécessite expose-experimental-directives dans la section globale, il ne prend en charge que les types de défi http-01, dns-01 et dns-persist-01, et les certificats qu’il génère doivent être extraits du socket de statistiques pour atteindre le disque. Le type dns-persist-01, ajouté dans la 3.4, utilise un enregistrement TXT statique défini une seule fois et qui ne change jamais entre les renouvellements, si bien qu’il ne nécessite pas d’accès en écriture à l’API du fournisseur DNS à chaque renouvellement. L’alternative éprouvée consiste à faire tourner un client ACME externe et à faire reconstruire le fichier PEM et recharger HAProxy par son étape de déploiement, ce qui correspond au même schéma décrit dans notre guide ACME pour Apache et NGINX.

Questions fréquentes

Dans quel ordre le certificat, la chaîne et la clé doivent-ils figurer dans le fichier PEM ?

D’abord votre certificat, puis les intermédiaires éventuels, puis la clé privée. Le manuel de HAProxy décrit ce fichier comme construit en concaténant des fichiers PEM et précise que l’intermédiaire peut y être concaténé. Si vous préférez garder la clé séparée, omettez-la entièrement et enregistrez-la sous le même chemin avec .key ajouté, que HAProxy charge automatiquement.

Pourquoi mon site HTTPS se redirige-t-il vers lui-même en boucle ?

Généralement à cause d’une ligne server backend sans adresse, comme server web1 :80 check. HAProxy résout l’adresse vide en 0.0.0.0, et cette adresse signifie que la connexion est renvoyée vers la même adresse IP à laquelle le client s’est connecté, c’est-à-dire HAProxy lui-même. Le backend pointe donc vers le propre port 80 de HAProxy, qui est le frontend émettant la redirection HTTP vers HTTPS. Donnez à chaque ligne server une véritable adresse IP ou un nom d’hôte.

Puis-je avoir deux lignes bind pour le port 443 dans le même frontend ?

Vous le pouvez, et c’est bien le problème. HAProxy ne les fusionne pas et ne prévient pas, et haproxy -c réussit car il se termine avant de tenter le bind. Vous obtenez deux sockets d’écoute sur un même port, chacun avec ses propres options TLS, si bien qu’un réglage présent sur une seule des deux lignes ne s’applique qu’à une partie de votre trafic. Gardez une seule ligne bind par port et placez les paramètres TLS partagés dans ssl-default-bind-options.

Ajouter ssl-min-ver TLSv1.2 renforce-t-il quelque chose ?

Pas à lui seul. HAProxy documente déjà TLSv1.2 comme valeur par défaut de ssl-min-ver, si bien que le régler sur la même valeur ne fait qu’enregistrer votre intention sans changer le comportement. Le véritable durcissement provient des paramètres de suites de chiffrement, et n’oubliez pas que TLS 1.3 a besoin de ssl-default-bind-ciphersuites tandis que TLS 1.2 et en dessous utilisent ssl-default-bind-ciphers.

Mes serveurs backend ont-ils aussi besoin de certificats ?

Pas dans la configuration standard. HAProxy termine le TLS en périphérie et transmet du HTTP en clair, c’est pourquoi seul le répartiteur de charge détient le certificat. Ajoutez ssl verify required avec un fichier CA sur les lignes server uniquement si votre politique exige que le tronçon interne soit lui aussi chiffré.

Comment servir plusieurs domaines depuis une seule instance HAProxy ?

Pointez crt vers un répertoire plutôt que vers un fichier. HAProxy charge tous les certificats qu’il y trouve et choisit le bon pour chaque requête à l’aide du SNI, si bien qu’une seule ligne bind les couvre tous. Un certificat multi-domaines (SAN) est l’autre solution, et il convient bien à un ensemble de noms qui se renouvellent ensemble.

Quelle version de HAProxy dois-je utiliser ?

La branche 3.4, publiée en juin 2026, est l’actuelle version à support à long terme et elle est maintenue jusqu’au T2 2031. Les branches à numéro pair de HAProxy sont les branches LTS, avec environ cinq ans de maintenance, tandis que les branches à numéro impair comme la 3.3 bénéficient de 12 à 18 mois. Tout ce qui figure dans ce guide s’applique à la 3.0 et aux versions ultérieures ; seul le client ACME intégré nécessite la 3.2 ou une version plus récente.

Si le certificat est installé mais que les navigateurs continuent de se plaindre, nos guides sur les erreurs SSL courantes couvrent les causes habituelles, le plus souvent une chaîne incomplète ou un nom que le certificat ne liste pas.

Economisez 10% sur les certificats SSL en commandant aujourd’hui!

Émission rapide, cryptage puissant, confiance de 99,99 % du navigateur, assistance dédiée et garantie de remboursement de 25 jours. Code de coupon: SAVE10

Image détaillée d'un dragon en vol
Rédigé par

Rédacteur de contenu expérimenté spécialisé dans les certificats SSL. Transformer des sujets complexes liés à la cybersécurité en un contenu clair et attrayant. Contribuer à l'amélioration de la sécurité numérique par des récits percutants.

Avatar of Sergiu Rosca
Technical Review by Sergiu Rosca

Sergiu Rosca is the core web developer behind SSL Dragon. He manages the technical infrastructure, platform performance, and backend integrations that keep the site running smoothly and securely. At SSL Dragon, Sergiu shares practical insights on web development, site optimization, and technical troubleshooting.

All SSL Dragon installation guides are tested on live server environments and undergo a strict peer-review process to ensure your infrastructure remains secure. Read our full Editorial Policy.