1. Les blocs de configuration
Le fichier haproxy.cfg est structuré en plusieurs sections (Global, Defaults, Frontend, Backend, Listen, Program) qui définissent le comportement global et le flux du trafic.
Section Global
La section global définit des paramètres au niveau du processus système (sécurité, performance, logs). Elle s'applique à l'ensemble de l'instance HAProxy.
global
log /dev/log local0
maxconn 4096
user haproxy
group haproxy
daemon
Section Defaults
La section defaults permet d'éviter les répétitions. Les paramètres définis ici (mode, timeouts, logs) sont hérités par toutes les sections frontend et backend qui suivent.
defaults
log global
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
Section Frontend
Le frontend définit comment HAProxy reçoit les requêtes. On y précise l'adresse IP et le port d'écoute (bind), ainsi que les règles de routage (ACL) vers les backends.
frontend http-in
bind *:80
acl is_static path_beg /static
use_backend static_servers if is_static
default_backend app_serversL'importance du default_backend : Cette directive définit le backend par défaut vers lequel HAProxy envoie les requêtes qui ne correspondent à aucune règle d'ACL (use_backend). Il est fortement recommandé d'en définir un systématiquement pour éviter que HAProxy ne rejette des requêtes avec une erreur 503 si aucune condition de routage n'est satisfaite.
Section Backend
Le backend définit le pool de serveurs de destination. La syntaxe commence par le mot-clé backend suivi d'un nom unique. Pour déclarer plusieurs backends (par exemple pour séparer le trafic API du trafic Web), il suffit de définir plusieurs blocs avec des noms distincts.
backend app_servers
balance roundrobin
server web1 10.0.0.1:80 check
backend api_servers
balance leastconn
server api1 10.0.0.10:80 check
Section Listen
La section listen est un raccourci qui combine les fonctionnalités d'un frontend et d'un backend dans un seul bloc. C'est idéal pour les services simples comme l'exposition des statistiques ou le proxying TCP pur.
Note : Bien que pratique, ce rôle combiné n'est pas idéal pour les applications complexes composées de multiples domaines web et pools de serveurs. Dans ces cas, fusionner les fonctions peut complexifier inutilement la configuration. Nous recommandons alors de définir des sections frontend et backend séparées.
listen stats
bind *:8404
stats enable
stats uri /monitor
stats refresh 5s
Section Program
La section program permet à HAProxy de lancer et de surveiller des processus externes (disponible depuis la v2.2).
Note de dépréciation : La fonctionnalité program est dépréciée depuis HAProxy 3.1 et sera supprimée en version 3.3. D'ici là, son comportement change lors des rechargements : le processus maître démarre le programme, mais c'est un processus travailleur (worker) qui l'exécute. Il est désormais recommandé d'utiliser des gestionnaires de processus dédiés comme Systemd, SysVinit, Supervisord ou s6-overlays.
program my-agent
command /usr/local/bin/agent-script.sh
user haproxy
group haproxy
2. Simplifier avec les inclusions
Comment organiser une configuration complexe en plusieurs fichiers.
Utilisation de dossiers de configuration
Plutôt que d'avoir un fichier unique de plusieurs milliers de lignes, HAProxy permet de charger un répertoire entier. Cela est particulièrement utile dans les environnements automatisés (Ansible, Puppet) où chaque application peut avoir son propre fichier de configuration.
Lors du lancement du service, on utilise l'argument -f pointant vers un dossier. HAProxy concatène les fichiers trouvés par ordre alphabétique.
haproxy -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/
Exemple d'organisation en production
Dans une production avec de nombreux services, on adopte souvent une nomenclature numérique pour contrôler l'ordre de chargement :
/etc/haproxy/
├── haproxy.cfg # Global & Defaults
└── conf.d/
├── 10-frontend-http.cfg
├── 11-frontend-https.cfg
├── 20-backend-ecommerce.cfg
├── 21-backend-blog.cfg
└── 99-stats.cfgCette structure permet d'ajouter ou supprimer une application simplement en gérant un fichier dans conf.d/, facilitant ainsi l'automatisation via CI/CD.
3. Mise à jour et Rechargement à chaud
Modifier la configuration sans interrompre le trafic.
Zéro Down-time Reload
HAProxy est conçu pour la haute disponibilité. Lorsque vous modifiez la configuration, vous pouvez recharger le service sans perdre de connexions actives. Le nouveau processus prend le relais sur les nouveaux sockets tandis que l'ancien termine de traiter les requêtes en cours.
# Vérifier la syntaxe avant de recharger
haproxy -c -f /etc/haproxy/haproxy.cfg
# Rechargement via systemd
systemctl reload haproxy
Rechargement sous Docker (SIGHUP)
Dans un environnement Docker, utiliser docker restart provoque une coupure nette car il tue le processus. Pour effectuer un rechargement 'hitless' (sans coupure) après avoir modifié votre fichier de configuration, envoyez le signal SIGHUP au conteneur. Le processus maître d'HAProxy créera un nouveau processus avec la nouvelle configuration tout en laissant l'ancien terminer les requêtes en cours.
# Recharger la configuration sans redémarrer le conteneur
docker kill -s HUP my-running-haproxy
La Runtime API
Pour des modifications ultra-dynamiques (comme changer le poids d'un backend ou passer un serveur en maintenance) sans même recharger le fichier, HAProxy propose une Runtime API accessible via une socket Unix. Des outils comme socat ou l'utilitaire haproxy-cli permettent d'interagir avec cette API.
# Exemple : désactiver un serveur via la socket
echo "disable server app_servers/web1" | socat stdio /var/run/haproxy.stat
# Exemple : ajouter un nouveau serveur à chaud avec haproxy-cli
haproxy-cli exec "add server app_servers/web3 10.0.0.3:80 check"4. Sécurité : DoS, Filtrage IP et WAF
HAProxy est souvent la première ligne de défense de votre infrastructure. Il permet de filtrer le trafic et d'analyser sa dangerosité avant qu'il n'atteigne vos serveurs applicatifs.
Protection contre les attaques DoS
Grâce aux stick-tables, HAProxy peut suivre le comportement des IPs en temps réel pour bloquer les abus (trop de connexions simultanées).
frontend http-in
bind *:80
# Table de suivi : 100k entrées, expire après 30s d'inactivité
stick-table type ip size 100k expire 30s store conn_cur
# On suit l'IP source
tcp-request connection track-sc0 src
# On rejette si l'IP dépasse 15 connexions simultanées
tcp-request connection reject if { sc0_conn_cur gt 15 }
Sécurité IP : Whitelisting et Blacklisting
Le filtrage IP permet de restreindre l'accès à des ressources sensibles ou de bloquer des attaquants connus.
- Whitelisting (Liste blanche) : On bloque tout sauf les IPs autorisées (stratégie Default Deny).
- Blacklisting (Liste noire) : On autorise tout sauf les IPs malveillantes.
# Exemple de Whitelisting pour les stats
acl network_allowed src 127.0.0.1 172.20.0.5
http-request deny if !network_allowed
# Exemple de Blacklisting via un fichier externe
acl bad_guys src -f /etc/haproxy/blacklist.lst
http-request deny if bad_guys
Web Application Firewall (WAF)
Le WAF inspecte le contenu des requêtes (headers, body, paramètres) pour bloquer les attaques de type Injection SQL ou XSS (OWASP Top 10). HAProxy peut intégrer un WAF nativement ou déléguer l'analyse via le mécanisme SPOE (Stream Processing Offload Engine) à un moteur comme ModSecurity.
frontend http-in
# On délègue l'analyse à l'agent ModSecurity via SPOE
filter spoe engine modsecurity config /etc/haproxy/modsec.conf
# On bloque la requête (403) si l'agent identifie une menace
http-request deny deny_status 403 if { var(txn.modsec.code) -m int gt 0 }Le fichier modsec.conf : Attention, ce fichier n'est pas celui qui contient vos règles de sécurité (WAF). C'est la configuration du SPOE agent. Il définit comment HAProxy communique avec le service externe : quels messages envoyer (headers, IP, etc.), les timeouts de réponse, et quel backend utiliser pour joindre l'agent ModSecurity.
5. Les ACL (Access Control Lists)
Les ACL sont le cœur de l'intelligence de HAProxy. Elles permettent de tester des conditions (URL, headers, IP) pour prendre des décisions de routage.
Syntaxe et Routage
Une ACL se définit par un nom, une méthode de test (fetch) et une valeur.
frontend http-in
# Teste si le chemin commence par /api
acl is_api path_beg /api
# Teste si le header Host contient 'admin'
acl is_admin hdr_dom(host) admin.mondomaine.com
# Actions basées sur les ACLs
use_backend api-servers if is_api
http-request deny if is_admin !network_allowed
6. Observabilité et Supervision
HAProxy offre une visibilité native sur l'état de santé du trafic et des serveurs.
Dashboard de Statistiques
L'interface web intégrée permet de visualiser l'état des backends et le débit en temps réel.
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 5s
stats auth admin:password # Optionnel : authentification
Exposition Prometheus
HAProxy peut exposer ses métriques nativement pour être collectées par un serveur Prometheus.
frontend stats_and_metrics
bind *:8404
# On expose les métriques sur l'URI /metrics
http-request use-service prometheus-exporter if { path /metrics }
Support OpenTelemetry (OTel)
Depuis la version 3.4, HAProxy peut envoyer des traces directement vers un collecteur OpenTelemetry pour un tracing distribué complet.
global
otel-exporter my-collector
endpoint otel-collector:4317
frontend http-in
# Envoi de la trace au collecteur
http-request otel-send-trace7. resolvers (DNS dynamique)
La directive resolvers permet à HAProxy de résoudre dynamiquement les noms DNS et de suivre leurs changements (scaling, Kubernetes, Docker, service discovery).
Structure de base
La section resolvers définit un serveur DNS utilisé par HAProxy pour résoudre les noms d'hôtes dynamiques.
resolvers dns
nameserver dns1 127.0.0.11:53
resolve_retries 3
timeout resolve 1s
timeout retry 1s
hold valid 10s
Utilisation avec un backend
Les resolvers permettent à HAProxy de résoudre dynamiquement des noms DNS et de les combiner avec server-template pour gérer automatiquement le scaling.
Pourquoi server-template ? Contrairement à une déclaration statique, server-template génère automatiquement plusieurs instances backend (web-1, web-2, web-3) sans configuration manuelle, indispensable en Docker/Kubernetes.
resolvers docker_dns
nameserver docker 127.0.0.11:53
hold valid 5s
backend app
server-template app 1-5 app.local:80 check resolvers docker_dns resolve-prefer ipv4
Docker / Service Discovery
Dans Docker, le DNS interne (127.0.0.11) permet de résoudre dynamiquement les conteneurs créés par scaling.
Pourquoi server-template ? Docker ne garantit ni IP fixe ni nom stable. server-template permet à HAProxy de suivre automatiquement les conteneurs sans modifier la configuration.
resolvers docker
nameserver docker 127.0.0.11:53
hold valid 10s
backend app
server-template web 1-10 web.local:80 check resolvers docker resolve-prefer ipv4
Kubernetes / Microservices
Dans Kubernetes, les pods changent dynamiquement selon le scaling du cluster.
Pourquoi server-template ? Les endpoints évoluent en permanence. server-template permet d’adapter automatiquement HAProxy sans reload ni configuration manuelle.
resolvers kube_dns
nameserver kube 10.96.0.10:53
hold valid 10s
backend api
server-template api 1-20 api.default.svc.cluster.local:80 check resolvers kube_dns resolve-prefer ipv4
Comportement de cache DNS
Les directives hold permettent de contrôler la durée de mise en cache des réponses DNS.
- hold valid : durée de validité d'une résolution réussie
- hold nx : durée pour les réponses NXDOMAIN
- hold refused : durée pour les refus DNS
resolvers dns
nameserver dns1 8.8.8.8:53
hold valid 30s
hold nx 5s
hold refused 5s
Conclusion
La puissance par la modularité.
Une structure robuste
Maîtriser l'anatomie de la configuration HAProxy est la première étape pour construire des infrastructures résilientes. La séparation nette entre l'écoute (frontend) et le traitement (backend) offre une flexibilité que peu d'autres solutions égalent.