HAProxy 3.2 : déploiement systemd, configuration frontend/backend, ACL

Tutoriel complet HAProxy 3.2 : installation, réglages OS, unité systemd avec reload sans coupure, exemples frontend/backend, ACL et rate limiting pour PrestaShop.

Écrans affichant HAProxy 3.2 avec graphiques et texte technique.

Table des matières :

  1. Pré-requis, périmètre et topologie cible (e-commerce / PrestaShop)
  2. Installation de HAProxy 3.2 et réglages OS qui évitent les surprises
  3. Déploiement systemd : unité, override, et reload sans coupure (vraiment)
  4. Socle de configuration : global / defaults, timeouts, TLS et headers proxy
  5. Frontend / backend : HTTP→HTTPS, pool applicatif, checks et affinité
  6. ACL HAProxy : définition, routage Host/Path, protection et rate limiting
  7. Observabilité, debugging et runbook de prod (config testable, reloads sûrs)

Pré-requis, périmètre et topologie cible (e-commerce / PrestaShop)

HAProxy 3.2 est un reverse-proxy L4/L7 pertinent dès que vous avez besoin de terminaison TLS propre, de routage HTTP fin (ACL), et de rechargements sans coupure (reloads). Le cas le plus courant en e-commerce : HAProxy en frontal (443/80) qui distribue vers un pool d’upstreams (Nginx/Apache + PHP-FPM), éventuellement avec Varnish intercalé pour le cache. Si vous cherchez du cache applicatif ou des ESI, HAProxy n’est pas le bon outil : c’est le rôle de Varnish (cf. l’article interne sur la config ESI : https://www.expertise-prestashop.fr/2026/05/22/varnish-cache-configuration-esi-pour-optimiser-le-cache-par-fragments/).

Côté prérequis OS, l’article part du principe que vous êtes sur une distro moderne supportant HAProxy 3.x et systemd (Debian 12/Ubuntu 24.04 typiquement), avec accès root, et que vous savez gérer TLS (certificats, chaîne, renouvellement). Côté applicatif, l’exemple de backend est “PrestaShop derrière Nginx”, mais la config HAProxy est identique si vous poussez vers Apache, Caddy ou directement vers un service Symfony. Pour le contexte PHP/PrestaShop, gardez en tête la compatibilité PHP et les patterns de prod (voir https://www.expertise-prestashop.fr/2026/03/24/prestashop-9-1-compatibilite-php-8-1-8-5-cli-et-nouveautes-developpeurs/).

Deux points de design qui font la différence en prod : (1) les timeouts et le keep-alive (sinon vous explosez le TTFB et les connexions backend sous charge), (2) la cohérence des headers X-Forwarded-* (sinon redirections en boucle, URLs en http, IP client perdue, logs inutilisables). Si votre objectif est la perf mesurable (TTFB < 200 ms), HAProxy doit être configuré comme une brique de latence minimale, pas comme un “fourre-tout” (référence interne : https://www.expertise-prestashop.fr/2026/06/03/ttfb-prestashop-reduire-le-time-to-first-byte-sous-200-ms/).

Dans une topologie réaliste “boutique + backoffice + endpoints techniques”, vous retrouvez généralement :

  • Entrées publiques : :80 (redir / challenges ACME) et :443 (TLS + HTTP/2).
  • Backends applicatifs : pool Nginx/Apache (souvent en réseau privé).
  • Endpoints non-publics : /metrics, page stats HAProxy, éventuellement un vhost admin dédié.
  • Composants optionnels : CDN en amont, WAF dédié, Varnish, ou un second HAProxy pour faire du north-south vs east-west.

Mini-scénario typique (soldes / campagne TV) : la charge ne vient pas uniquement du trafic “humain”. Les bots de pricing, les crawlers SEO et les scans opportunistes font aussi monter le taux de requêtes. D’où l’intérêt de séparer clairement :

  • ce qui doit toujours répondre vite (healthcheck, assets, pages produit),
  • ce qui doit être protégé (backoffice, login),
  • ce qui doit rester invisible (métriques, stats).

Installation de HAProxy 3.2 et réglages OS qui évitent les surprises

Sur Debian/Ubuntu, privilégiez un paquet maintenu (distro ou repo officiel/tiers) plutôt que du build “à la main”, sauf contrainte spécifique (OpenSSL/BoringSSL, QUIC, patch interne). Le piège classique du build from source : vous perdez l’intégration systemd/rsyslog par défaut et vous réinventez la roue (et ses erreurs). Pour valider la version et le build :

haproxy -vv

Ce -vv est non négociable : vous vérifiez la version (3.2.x), les options compilées (OpenSSL, threads, QUIC si pertinent), et vous évitez de déployer une config qui “passe en staging” mais casse en prod faute de feature.

Astuce opérationnelle : sur Debian/Ubuntu, gardez aussi un œil à la provenance du paquet, surtout si vous jonglez entre backports, PPA ou dépôts “vendor” :

apt-cache policy haproxy

Côté OS, HAProxy est souvent limité par des paramètres “invisibles” : nombre de fichiers ouverts, backlog TCP, ephemeral ports, et buffers. En e-commerce (pics type soldes), vous voulez explicitement ajuster :

  • LimitNOFILE (systemd) ou ulimit -n côté process
  • net.core.somaxconn, net.ipv4.ip_local_port_range, net.ipv4.tcp_tw_reuse (selon politique)

Exemple (à adapter, surtout pour tcp_tw_reuse selon votre kernel/politique réseau) :

cat >/etc/sysctl.d/99-haproxy.conf <<'EOF'
net.core.somaxconn=65535
net.ipv4.ip_local_port_range=10240 65535
EOF
sysctl --system

Deux précisions qui évitent des “mystères” :

  • somaxconn n’aide que si l’application écoute avec un backlog cohérent. Côté HAProxy, c’est surtout pertinent quand vous avez de gros pics de SYN/accept et que vous voulez éviter des refus transitoires.
  • La plage de ports éphémères impacte les sorties vers les backends (connexions serveur). Si vous scalez à plusieurs dizaines de milliers de connexions actives, des ports trop “serrés” peuvent déclencher des erreurs difficiles à corréler.

Enfin, la journalisation : soit vous logguez vers syslog (/dev/log) avec rsyslog/journald, soit vous logguez vers stdout et vous laissez systemd récupérer. En 2026, le choix “stdout + journal” est souvent plus simple à opérer (filtrage via journalctl, intégration agents). Dans tous les cas, dimensionnez votre rétention et votre pipeline (si vous centralisez via ELK, vous pouvez recouper avec une logique type Logstash : https://www.expertise-prestashop.fr/2026/06/05/logstash-plugins-input-filter-output-pour-elasticsearch-et-kafka/).

Point conformité (souvent oublié) : les logs reverse-proxy contiennent fréquemment IP, User-Agent, parfois des URL avec paramètres. En environnement UE/France, traitez-les comme des données potentiellement personnelles (politique de rétention, accès, anonymisation si nécessaire), surtout si vous activez des captures de headers.

« HAProxy is a free, very fast and reliable solution offering high availability, load balancing, and proxying for TCP and HTTP-based applications. » — HAProxy Technologies, page projet : https://www.haproxy.org/

Déploiement systemd : unité, override, et reload sans coupure (vraiment)

L’intégration systemd ne sert pas juste à “démarrer un service”. Elle sert à rendre le comportement opérable : limites de ressources, redémarrage contrôlé, notification de readiness, et rechargements propres. Rappel factuel :

« systemd is a system and service manager for Linux operating systems. » — documentation systemd : https://www.freedesktop.org/software/systemd/man/systemd.html

Sur HAProxy 3.2, vous voulez impérativement le mode master-worker et un process au premier plan pour que systemd puisse gérer correctement l’état. Le binaire supporte un mode adapté à systemd (notification), couramment lancé avec -Ws (master-worker + systemd). Le résultat attendu : systemctl reload haproxy qui recharge la conf sans drop massif de connexions.

Exemple d’override (drop-in) propre, sans casser l’unité fournie par votre paquet. Créez /etc/systemd/system/haproxy.service.d/override.conf :

[Service]
# Monter la limite de FD pour absorber pics de connexions
LimitNOFILE=200000

# Laisser HAProxy au premier plan, master-worker, et fournir un PID
ExecStart=
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid

# Reload contrôlé : (1) valider la conf (2) déclencher le reload
ExecReload=
ExecReload=/usr/sbin/haproxy -c -f /etc/haproxy/haproxy.cfg
ExecReload=/bin/kill -USR2 $MAINPID

RuntimeDirectory=haproxy
RuntimeDirectoryMode=0755

Trois remarques non optionnelles : (1) -c doit échouer avant de reloader, sinon vous faites tomber le proxy sur une erreur de syntaxe, (2) USR2 déclenche un reload “seamless” en master-worker (préservez les sockets), (3) le RuntimeDirectory évite les permissions approximatives dans /run. Ensuite :

systemctl daemon-reload
systemctl restart haproxy
systemctl status haproxy

Bon réflexe de prod : avant un changement, validez aussi que systemd recharge bien votre override et que le service n’a pas été “shadowed” par une autre unité :

systemctl cat haproxy
systemd-analyze verify /etc/systemd/system/haproxy.service.d/override.conf

Enfin, côté exploitation, fixez une règle simple : pas de reload si la conf n’est pas validée, et pas de déploiement si le reload n’est pas testé en préprod. C’est exactement le type de détail qui évite une panne “bête” lors d’une fenêtre de trafic critique.

Socle de configuration : global / defaults, timeouts, TLS et headers proxy

Dans HAProxy, la section global fixe le comportement du process (threads, sockets runtime, TLS par défaut), defaults fixe le comportement HTTP/TCP de vos proxies. Le piège le plus courant : des timeouts trop faibles (erreurs 504 sous charge) ou trop hauts (connexions zombies, saturation). Pour une boutique, commencez avec des timeouts explicites et versionnés (vous les ajusterez après mesure).

Exemple minimaliste mais exploitable /etc/haproxy/haproxy.cfg (HAProxy 3.2) :

global
  # Logs vers stdout : systemd/journald récupère tout
  log stdout format raw local0

  master-worker
  nbthread 4

  # Socket runtime (admin) : utile pour debug / opérations
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners

  ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
  ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
  tune.ssl.default-dh-param 2048

  # Evite les workers éternels lors de reloads en boucle
  hard-stop-after 30s

defaults
  mode http
  log global
  option httplog
  option dontlognull
  option http-keep-alive

  timeout connect 5s
  timeout client  30s
  timeout server  30s
  timeout http-request 10s
  timeout http-keep-alive 15s

  # Réutilisation de connexions backend (réduit la charge sur Nginx/Apache)
  http-reuse safe

Pour raisonner “tech + produit”, voici une grille de lecture utile :

Paramètre Trop bas => Trop haut => Indication pour e-commerce
timeout http-request 408/erreurs sur clients lents connexions qui traînent protège surtout des clients “qui n’envoient jamais la requête”
timeout connect bascule backend trop agressive attente inutile sur backends HS ajuster selon latence réseau interne
timeout server 504 sur pages lentes/DB threads/connexions occupés à corréler avec les p95/p99 côté app
timeout http-keep-alive plus de handshakes/connexions slots occupés utile si beaucoup de petites requêtes (assets, API)

Sur TLS, gardez un principe simple : la terminaison TLS doit être robuste mais pas ésotérique. Si vous avez besoin d’un profil “strict” documenté, alignez-vous sur les recommandations Mozilla (référence : https://ssl-config.mozilla.org/). Évitez aussi de “tuner” à l’aveugle : mesurez l’impact sur CPU (handshake) et sur les clients (compat). En e-commerce, la compatibilité navigateur reste un sujet, mais TLS 1.2+ est généralement un minimum opérationnel.

Deux points concrets qui rendent la gestion certificats plus sereine :

  • Si vous stockez plusieurs certificats (SNI), préférez un répertoire (comme dans l’exemple) ou une crt-list (quand vous voulez maîtriser explicitement quels noms sont servis). Pensez aussi au format “fullchain + key”.
  • En cas de renouvellement automatique (ex. Let’s Encrypt), prévoyez un reload HAProxy après renouvellement (pas besoin de restart). C’est typiquement une ligne dans un hook de renouvellement, ou une tâche orchestrée.

Enfin, sur les headers : HAProxy doit injecter ce que votre app (PrestaShop/Symfony) attend pour reconstruire l’URL canonique, détecter HTTPS, et journaliser l’IP réelle. En frontal, vous poserez typiquement X-Forwarded-Proto, X-Forwarded-For, et parfois X-Forwarded-Port. Si derrière vous avez Nginx, assurez-vous qu’il relaie correctement ces headers vers PHP-FPM, sinon vous aurez des incohérences SEO (http vs https) et des bugs de redirection. Pour la roadmap SEO/tech, voir : https://www.expertise-prestashop.fr/2026/04/20/seo-prestashop-roadmap-3-mois-audit-contenu-performance-et-popularite/.

Mini-symptôme très parlant côté boutique : si vous voyez des URLs générées en http:// dans les emails, dans les canonical, ou des redirections 302 en boucle, ce n’est pas “un bug PrestaShop” par défaut : c’est souvent une chaîne de proxy qui ne remonte pas correctement le schéma HTTPS.

Frontend / backend : HTTP→HTTPS, pool applicatif, checks et affinité

Un découpage propre : un frontend pour 80 (redir), un frontend pour 443 (TLS + routage), un ou plusieurs backend (pool). Exemple :

frontend fe_http
  bind :80
  http-request redirect scheme https code 301

frontend fe_https
  bind :443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1

  # Headers proxy
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-For %[src]

  default_backend be_prestashop

backend be_prestashop
  balance roundrobin
  option httpchk GET /healthz
  http-check expect status 200

  server web1 10.0.0.11:80 check
  server web2 10.0.0.12:80 check

Dans la vraie vie, la redirection 80→443 mérite souvent une exception : le challenge HTTP-01 (ACME) si vous renouvelez des certificats via /.well-known/acme-challenge/. Exemple minimal (si votre outil ACME répond localement sur un port interne, ou si un serveur dédié répond au challenge) :

frontend fe_http
  bind :80
  acl acme_challenge path_beg /.well-known/acme-challenge/
  use_backend be_acme if acme_challenge
  http-request redirect scheme https code 301

backend be_acme
  server acme 127.0.0.1:8080 check

Le endpoint /healthz doit être dédié (léger, pas authentifié, pas de dépendance DB critique) et retourner 200 rapidement. Ne faites pas pointer le check sur / : vous allez confondre “site lent” et “node mort”, et HAProxy va évincer des serveurs pour de mauvaises raisons. Pour une logique de monitoring/runbook orientée pics (soldes), vous pouvez vous aligner sur les pratiques décrites ici : https://www.expertise-prestashop.fr/2026/06/18/prestashop-performance-monitoring-tests-de-charge-et-runbooks-soldes/.

Astuce utile quand votre backend sert plusieurs vhosts : envoyez un Host explicite dans le healthcheck pour tester le bon virtual host (sinon vous risquez un 301/404 qui ressemble à un “node mort”) :

backend be_prestashop
  option httpchk
  http-check send meth GET uri /healthz ver HTTP/1.1 hdr Host shop.example.com
  http-check expect status 200

Sur l’affinité (stickiness), ne partez pas du principe que PrestaShop en a besoin. Si vos sessions sont en Redis/DB partagée et que vous n’avez pas de state local, vous pouvez rester en round-robin (souvent préférable). Si vous avez du state local ou des uploads temporaires non partagés, vous devrez soit corriger l’architecture (recommandé), soit activer une affinité. Exemple par cookie inséré côté HAProxy (pratique, mais attention aux caches/proxies intermédiaires) :

backend be_prestashop
  balance roundrobin
  cookie SRV insert indirect nocache
  server web1 10.0.0.11:80 check cookie w1
  server web2 10.0.0.12:80 check cookie w2

Bon compromis “anti-effet de bord” : si vous activez la stickiness, surveillez en particulier :

  • la répartition réelle (un mauvais paramétrage peut envoyer trop de monde sur un seul nœud),
  • la cohérence avec votre cache (Varnish/CDN) si vous en avez un,
  • le taux d’erreurs applicatives après bascule (perte de panier, session, etc.).

ACL HAProxy : définition, routage Host/Path, protection et rate limiting

Une ACL (Access Control List) dans HAProxy est une condition booléenne basée sur des “fetches” (host, path, headers, IP, SNI, etc.) et des comparateurs. C’est l’outil central pour faire du routage déterministe et du filtrage à faible coût CPU. La règle d’or : vous écrivez des ACL lisibles, testables, et vous limitez les effets de bord (ordre d’évaluation, règles trop larges, regex coûteuses).

Routage par host/path (multi-boutiques, backoffice séparé, endpoints techniques) :

frontend fe_https
  bind :443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1

  acl host_shop  hdr(host) -i shop.example.com
  acl host_admin hdr(host) -i admin.example.com
  acl path_admin path_beg /admin
  acl path_metrics path -i /metrics

  use_backend be_admin      if host_admin || (host_shop path_admin)
  use_backend be_metrics    if path_metrics
  default_backend be_prestashop

backend be_admin
  server admin1 10.0.0.21:80 check

backend be_metrics
  # exporter Prometheus intégré (voir section observabilité)
  http-request use-service prometheus-exporter

Protection “chirurgicale” : sur /admin, ne faites pas confiance à l’obscurité. Whiteliste IP (VPN/bastion), puis ajoutez une seconde barrière si nécessaire. Exemple simple :

frontend fe_https
  acl is_admin_path path_beg /admin
  acl from_office   src 203.0.113.10 203.0.113.11

  http-request deny status 403 if is_admin_path !from_office

Complément utile en production : coupez tôt le bruit des scans automatisés (WordPress, .git, etc.). Ce n’est pas un “WAF”, mais c’est un gain immédiat en logs et en charge applicative, surtout lors de campagnes où le site est plus exposé :

frontend fe_https
  acl bad_paths path_beg -i /.git /wp-admin /wp-login.php
  http-request deny status 404 if bad_paths

Rate limiting (anti-scan / anti-bruteforce) avec stick-table : c’est efficace, mais vous devez calibrer. Un mauvais seuil peut tuer votre conversion (faux positifs sur NAT mobiles/entreprises). Exemple basique : 50 req/10s par IP, renvoi 429 :

frontend fe_https
  stick-table type ip size 200k expire 10m store http_req_rate(10s)
  http-request track-sc0 src

  acl abuse sc_http_req_rate(0) gt 50
  http-request deny status 429 if abuse

Une approche plus “e-commerce friendly” consiste à appliquer des seuils différents selon le chemin : par exemple plus strict sur /login ou /admin que sur le catalogue. Vous pouvez simplement dupliquer la logique avec une seconde table (ou conditionner le deny à une ACL de chemin), en testant soigneusement sur votre trafic réel.

Pour aller plus loin sur les ACL, les fetches et les tables, la doc officielle HAProxy est une référence pratique (syntaxe + exemples) : https://docs.haproxy.org/

Pour la posture sécurité globale (WAF, SIEM, journalisation), HAProxy n’est qu’un maillon. Ne le confondez pas avec un WAF complet : il filtre, mais n’analyse pas “profondément” l’attaque applicative comme un ModSecurity/Coraza dédié. Pour cadrer les protections cohérentes côté PrestaShop : https://www.expertise-prestashop.fr/2026/05/29/securite-prestashop-proteger-api-backoffice-waf-et-journalisation-siem/ et https://www.expertise-prestashop.fr/2026/04/20/securite-prestashop-2026-risques-majeurs-et-protections-professionnelles/.

Observabilité, debugging et runbook de prod (config testable, reloads sûrs)

La base : valider la config avant tout reload, et pouvoir diagnostiquer rapidement (latence, erreurs backend, saturation). En pipeline CI/CD, exécutez systématiquement :

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

Puis utilisez un reload systemd (celui défini plus haut) :

systemctl reload haproxy
journalctl -u haproxy -f

Pour l’observabilité, trois surfaces utiles : (1) logs HTTP (codes, timers, backend/server), (2) stats HAProxy (sessions, queues, health), (3) runtime API via socket. La socket (/run/haproxy/admin.sock) permet de sortir du “tout redémarrer” :

echo "show info" | socat - UNIX-CONNECT:/run/haproxy/admin.sock
echo "show stat" | socat - UNIX-CONNECT:/run/haproxy/admin.sock | head

Lecture rapide “incident” (utile en période de pics) :

  • si vous voyez des queues qui montent (qcur, qmax dans show stat), vos backends ne consomment plus assez vite (CPU, DB, locks, pool PHP-FPM).
  • si les 5xx augmentent côté backend mais pas côté frontend, c’est souvent applicatif (exceptions, timeouts upstream, saturation).
  • si le temps de réponse grimpe mais que la queue reste basse, cherchez plutôt la latence (DB, réseau, cache).

Pour l’exposition Prometheus, HAProxy fournit un service prometheus-exporter activable via http-request use-service prometheus-exporter. Vous le servez idéalement sur un vhost/chemin dédié, protégé (IP allowlist) et hors du trafic public. Exemple (complément du frontend précédent) :

frontend fe_https
  acl from_monitoring src 10.0.0.0/24
  acl path_metrics path -i /metrics
  http-request deny if path_metrics !from_monitoring
  use_backend be_metrics if path_metrics

Si vous voulez une surface de diagnostic “humaine” en plus de Prometheus, vous pouvez aussi activer une page stats HAProxy (à réserver au réseau interne/VPN). L’intérêt est d’avoir, en quelques secondes, l’état des serveurs (UP/DOWN), les sessions actives et les erreurs sans parser des logs.

Enfin, gardez un runbook court, exécutable, et réaliste (pas un roman). Le minimum : (a) commandes de validation + reload, (b) checks de santé backend, (c) rollback (recharger l’ancienne conf), (d) métriques à surveiller (5xx, queues, ttfb, saturation CPU). Pour la méthodologie de tests de charge et les runbooks “jours de pics”, vous avez déjà une base interne solide : https://www.expertise-prestashop.fr/2026/06/18/prestashop-performance-monitoring-tests-de-charge-et-runbooks-soldes/ ; pour les métriques Web (CWV), voir aussi https://www.expertise-prestashop.fr/2026/04/16/core-web-vitals-actions-concretes-pour-ameliorer-lcp-inp-et-cls/.

Checklist runbook (format “copier-coller” qui tient en prod) :

  • Avant déploiement : haproxy -c -f /etc/haproxy/haproxy.cfg
  • Reload : systemctl reload haproxy puis journalctl -u haproxy -n 200 --no-pager
  • Santé backends : vérifier /healthz depuis HAProxy ou depuis un hôte du même réseau
  • En cas de 5xx : regarder show stat (queues + serveurs DOWN) puis isoler : proxy vs app vs DB
  • Rollback : remettre le dernier haproxy.cfg connu OK, revalider, reloader
  • Post-incident : corréler avec vos métriques TTFB et vos traces applicatives (voir aussi la démarche perf côté boutique : https://www.expertise-prestashop.fr/2026/06/03/ttfb-prestashop-reduire-le-time-to-first-byte-sous-200-ms/)

À lire aussi