⚖️ HAProxy – Le Guide Ultime
Deep Dive : Load Balancing (L4/L7), Haute Disponibilité, ACLs, Health Checks & Sticky Sessions.
1. C'est quoi HAProxy ?
High Availability Proxy. Reverse Proxy L4 (TCP) / L7 (HTTP) pour Load Balancing.
Load Balancer L4/L72. Architecture
Client -> HAProxy (Port 80) -> Pool de Backends (App1, App2...).
Architecture Proxy3. Fichier Config (Core)
haproxy.cfg. Sections : global, defaults, frontend, backend.
4. Section frontend
Le "listener" public. bind *:80, mode http/tcp, default_backend.
5. Section backend
Le "pool" de serveurs. server s1 ..., server s2 .... balance.
6. ⚖️ Algorithmes (Balance)
roundrobin, leastconn, source (IP Hash), uri (URL Hash).
7. Health Checks (Santé)
La "Haute Dispo". check, inter, fall, rise. Retrait/ajout auto du pool.
8. Sticky Sessions (Persistance)
Gérer l'état (login). cookie SERVERID insert. Stick tables (L4).
9. ACL (Logique de Routage)
Le "cerveau". acl (règle), use_backend if, http-request deny if.
10. 📊 Stats Page
Le "plugin" dashboard. listen stats, stats uri /haproxy, stats auth.
11. Terminaison SSL/TLS
"Offloading". bind *:443 ssl crt. Client -> (HTTPS) -> HAProxy -> (HTTP) -> Backend.
12. Addons & Outils (HA)
SPOF & keepalived (VRRP). hatop. Liens officiels.
HAProxy (High Availability Proxy) est un reverse proxy et load balancer (répartiteur de charge) open-source, gratuit, et ultra-performant. Il est réputé pour sa vitesse, son efficacité (faible conso CPU/RAM) et sa fiabilité.
Important : HAProxy n'est *pas* un serveur web (il ne peut pas lire de fichiers sur le disque comme Nginx ou Apache). Il est *spécialisé* dans le routage réseau.
L4 vs L7 (La "Killer Feature")
HAProxy excelle dans les deux modes de "load balancing" :
| Mode | Niveau OSI | Description | Cas d'usage |
|---|---|---|---|
mode tcp (L4) | Couche 4 (Transport) | Rapide & "Bête". Ne comprend pas le HTTP. Il transfère les paquets TCP. | Bases de données (PostgreSQL, MySQL), SMTP, SSH. |
mode http (L7) | Couche 7 (Application) | Intelligent & "Lent". Comprend le HTTP. Peut lire les URLs, les headers, les cookies. | APIs REST, sites web (routage par path, sticky sessions). |
Les 2 Objectifs de HAProxy
- Load Balancing (Répartition de Charge) : Distribuer le trafic (ex: 1 million de visiteurs) sur plusieurs serveurs backend (ex: 10 serveurs web) pour qu'aucun ne tombe.
- High Availability (Haute Disponibilité) : Détecter automatiquement si un serveur backend est "mort" (Health Check) et arrêter de lui envoyer du trafic, sans interruption pour l'utilisateur.
Varnish est un "Reverse Proxy", ce qui signifie qu'il se place *entre* l'utilisateur et votre serveur d'application ("backend" ou "origin").
Diagramme de Flux (Load Balancing)
(Internet)
|
| (Requête: GET /) (IP Publique)
▼
+----------------------+
| HAProxy (Serveur 1) | (Écoute sur Port 80)
| (Le "Répartiteur") |
+----------------------+
|
| 1. HAProxy reçoit la requête.
| 2. Il consulte son algorithme (ex: roundrobin)
| 3. Il choisit un backend "vivant" (health check OK).
|
+------- (50% du trafic) --------+
| |
▼ ▼
+----------------------+ +----------------------+
| Backend 1 (Serveur 2)| | Backend 2 (Serveur 3)|
| (Apache/Nginx/Node.js) | (Apache/Nginx/Node.js)
| (IP: 10.0.0.1:8080) | | (IP: 10.0.0.2:8080) |
+----------------------+ +----------------------+
Le cœur de HAProxy est son unique fichier de configuration : /etc/haproxy/haproxy.cfg.
Il est divisé en 4 (ou 5) sections principales :
| Section | Description |
|---|---|
global | Paramètres du *processus* HAProxy (logs, user/group, maxconn). |
defaults | Paramètres par défaut *hérités* par les sections frontend et backend (ex: mode, timeout). |
frontend | Définit la "façade" (le "listener") qui reçoit le trafic client (IP, port, règles ACL). |
backend | Définit le "pool" de serveurs applicatifs vers lesquels router le trafic. |
listen | (Optionnel) Une section qui combine un frontend et un backend en un seul bloc. (Souvent utilisé pour la page de Stats). |
Exemple (haproxy.cfg)
# --- NIVEAU PROCESSUS ---
global
log /dev/log local0
user haproxy
group haproxy
maxconn 4000
# --- NIVEAU HÉRITAGE ---
defaults
log global
mode http # (Mode par défaut: L7)
option httplog
timeout connect 5s
timeout client 50s
timeout server 50s
# --- NIVEAU CLIENT ---
frontend http_in
bind *:80
# Logique de routage (ACLs)
acl is_api path_beg /api
use_backend api_pool if is_api
# Backend par défaut
default_backend web_pool
# --- NIVEAU SERVEUR ---
backend web_pool
balance roundrobin
server web1 10.0.0.1:8080 check
server web2 10.0.0.2:8080 check
backend api_pool
balance leastconn
server api1 10.0.0.3:3000 check
server api2 10.0.0.4:3000 check
La section frontend (ou listen) définit "comment" HAProxy accepte les connexions entrantes.
Directives Clés (frontend)
| Directive | Description | Exemple |
|---|---|---|
bind | Définit le "socket" (IP + Port) sur lequel écouter. | bind *:80 (Port 80, toutes IPs)bind 1.2.3.4:443 ssl crt ... (SSL) |
mode | Définit le niveau de travail (Couche 4 ou 7). | mode http (L7) ou mode tcp (L4). |
default_backend | Le nom du "pool" backend à utiliser si aucune règle acl ne matche. | default_backend web_pool |
acl ... | Définit une règle de test (voir 2.3). | acl is_blog path_beg /blog |
use_backend ... if | La logique de routage. | use_backend blog_pool if is_blog |
Exemple (Routage L7 par Hostname)
frontend http_frontend
bind *:80
mode http
# 1. Définir les ACLs basées sur le "Host" (domaine)
acl host_blog hdr(Host) -i blog.monsite.com
acl host_api hdr(Host) -i api.monsite.com
# 2. Appliquer la logique de routage
use_backend blog_servers if host_blog
use_backend api_servers if host_api
# 3. Fallback
default_backend default_web_servers
La section backend définit le "pool" de serveurs réels (vos applications) qui feront le travail.
Directives Clés (backend)
| Directive | Description | Exemple |
|---|---|---|
mode | Doit *matcher* le mode du frontend. | mode http ou mode tcp. |
balance | L'algorithme de répartition de charge (voir 1.6). | balance roundrobin (défaut). |
server | Le plus important. Définit un serveur backend. | server srv1 10.0.0.1:8080 check |
cookie | Active les "sticky sessions" (voir 2.2). | cookie SERVERID insert |
La directive server (Détaillée)
server [nom] [ip:port] [options]
backend web_pool
balance roundrobin
# srv1: Serveur 1
# 10.0.0.1:8080 : L'IP/Port de l'application (Apache, Tomcat...)
# check : Active le Health Check (voir 2.1)
# weight 10 : (Optionnel) Reçoit 10x plus de trafic
server srv1 10.0.0.1:8080 check weight 10
# srv2: Serveur 2
# weight 1 : (Défaut) Reçoit 1x le trafic
server srv2 10.0.0.2:8080 check weight 1
# srv3: Serveur de backup
# backup : N'est utilisé QUE si 'srv1' ET 'srv2' sont DOWN.
server srv3_backup 10.0.0.3:8080 check backup
balance)La directive balance (dans le backend) dit à HAProxy *comment* choisir le prochain serveur.
| Algorithme | Description | Cas d'usage |
|---|---|---|
roundrobin | Tourniquet (Défaut). A -> B -> C -> A -> B... (Prend en compte les weight). | Le plus simple, bon pour les requêtes courtes et rapides (APIs). |
leastconn | Le moins connecté. Envoie la requête au serveur ayant le *moins* de connexions actives. | Le meilleur pour les sessions longues. (Connexions BDD (L4), RDP, WebSockets). |
source | IP Source (Hash). "Hashe" l'IP du client et l'assigne à un serveur. hash-type consistent (recommandé) évite de re-hacher tout si un serveur tombe. | "Sticky session" L4. Garantit que le client 1.2.3.4 va *toujours* sur le serveur A. (Inconvénient si A tombe). |
uri | Hash de l'URI. "Hashe" l'URL. Garantit que /images/1.jpg va *toujours* sur le serveur A. | Très bon pour le cache (permet aux caches backend de mieux fonctionner). |
C'est la partie "HA" (High Availability). HAProxy *surveille* en permanence ses backends.
La directive check
Le mot-clé check sur une ligne server active le health check.
backend web_pool
# 'check' : Active le check
# 'inter 2000' : (Intervalle) Vérifie toutes les 2000 ms (2s)
# 'fall 3' : Marque le serveur DOWN après 3 échecs consécutifs
# 'rise 2' : Remet le serveur UP après 2 succès consécutifs
server srv1 10.0.0.1:8080 check inter 2000 fall 3 rise 2
L4 (TCP) vs L7 (HTTP) Check
| Mode | Méthode | Description |
|---|---|---|
mode tcp | Connexion TCP (Défaut) | HAProxy essaie juste d'ouvrir un socket TCP sur 10.0.0.1:8080. Si le port répond, c'est "UP". Inconvénient : Le port peut répondre, mais l'app (Apache) peut être plantée (Erreur 500). |
mode http | option httpchk | Bien meilleur. HAProxy va *vraiment* faire une requête HTTP (OPTIONS / par défaut) et vérifier le code de statut (attend 2xx ou 3xx). |
Exemple (HTTP Check)
backend api_pool
mode http
# 1. Définit le "health check"
# (Fait un GET /health au lieu de OPTIONS /)
option httpchk GET /health
# 2. Attend un '200 OK'
http-check expect status 200
server api1 10.0.0.1:3000 check
Le Problème (État "Stateful") :
1. Client 1 se connecte, l'algo roundrobin l'envoie sur Serveur A. Il se logue (sa session est stockée sur A).
2. Client 1 rafraîchit la page. L'algo roundrobin l'envoie sur Serveur B.
3. Serveur B ne connaît pas sa session. Le client est déconnecté.
La Solution : "Sticky Sessions" (Session Collante). On force le client à *toujours* parler au même serveur.
Méthode 1 : balance source (IP Hash)
Facile, mais pose problème si plusieurs utilisateurs sont derrière le même NAT (ex: une entreprise). (Voir 1.6).
Méthode 2 : cookie (La meilleure)
HAProxy va *insérer* un cookie chez le client.
backend web_pool
balance roundrobin
# 1. Active le mode "cookie"
# "SRV_ID" est le nom du cookie que HAProxy va créer.
# "insert" : HAProxy va l'insérer lui-même.
cookie SRV_ID insert nocache
# 2. Lie le nom du cookie au nom du serveur
server srv1 10.0.0.1:8080 check cookie S1
server srv2 10.0.0.2:8080 check cookie S2
# --- Flux ---
# 1. Client visite (1ère fois).
# 2. HAProxy choisit 'srv1'.
# 3. HAProxy renvoie la réponse ET un 'Set-Cookie: SRV_ID=S1'.
# 4. Client revient. Il envoie le cookie 'SRV_ID=S1'.
# 5. HAProxy voit le cookie 'S1' et le route *directement* vers 'srv1'.
Les ACLs sont le "cerveau" de HAProxy. C'est un système de règles (if) qui permet de prendre des décisions de routage complexes.
Syntaxe : acl [nom_de_la_regle] [critère] [valeur]
Critères (Fetches) Courants
| Critère | Description |
|---|---|
path_beg | Le chemin de l'URL commence par... (/blog) |
path_end | Le chemin de l'URL finit par... (.jpg) |
hdr(Host) | Le header "Host" (domaine). |
src | L'IP source du client. |
method | Le verbe HTTP (POST). |
Exemple (Routage Avancé)
frontend http_in
bind *:80
mode http
# 1. Définir les ACLs (variables booléennes)
acl is_api path_beg /api
acl is_blog path_beg /blog
acl is_image path_end .jpg .png .gif
acl ip_blacklist src -f /etc/haproxy/blacklist.txt
# 2. Logique d'action (http-request)
# 2a. Sécurité (Bloquer en premier)
http-request deny if ip_blacklist
# 2b. Routage
use_backend api_servers if is_api
use_backend blog_servers if is_blog
use_backend image_servers if is_image
# 2c. Fallback
default_backend default_servers
HAProxy inclut un "plugin" (dashboard web) de statistiques vital pour le monitoring et le débuggage. On le configure via une section listen (une section qui est à la fois frontend et backend).
Configuration (haproxy.cfg)
Ajoutez ce bloc à la fin de votre fichier de configuration :
# --- Stats Page ---
listen stats
# 1. Le port d'écoute (un port non-standard)
bind *:8404
# 2. L'URL d'accès
stats uri /haproxy_stats
# 3. (Optionnel, mais RECOMMANDÉ) Sécurité
stats auth admin:UnMotDePasseTresSolide
# 4. (Optionnel) Permet de rafraîchir
stats refresh 10s
Accédez ensuite à http://votre-ip:8404/haproxy_stats (avec le login/pass).
Ce que l'on y voit :
- Statut des Backends : (Couleur) Vert (UP), Rouge (DOWN).
- Sessions : Le nombre de connexions actuelles, en attente (Queue), max.
- Hit Rate : (Si Varnish est derrière) Le taux de cache.
- Erreurs : Le nombre d'erreurs (
5xx) par serveur. - Admin : Permet de *désactiver* (
DRAIN) un serveur manuellement avant une mise à jour, sans couper les sessions en cours.
La Terminaison SSL (Offloading) est la pratique où le Reverse Proxy (HAProxy) gère le "lourd" travail de chiffrement/déchiffrement (HTTPS), et parle ensuite en HTTP (non-chiffré) aux serveurs backend sur le réseau privé.
Flux (Terminaison)
Client --- (HTTPS) ---> HAProxy (Port 443) --- (HTTP) ---> Backend (Port 8080)
Avantages
- Centralisation : Les certificats SSL sont gérés à *un seul* endroit (le LB), pas sur les 10 serveurs web.
- Performance : Les serveurs web (Apache, etc.) n'ont plus à dépenser du CPU pour chiffrer.
- Simplicité : Le réseau interne (privé) reste en HTTP simple.
Configuration (bind)
Vous avez besoin d'un fichier .pem qui contient votre *certificat* ET votre *clé privée* (dans cet ordre).
# (Combinez votre clé et votre certificat)
$ cat /etc/letsencrypt/live/monsite.com/fullchain.pem /etc/letsencrypt/live/monsite.com/privkey.pem > /etc/haproxy/certs/monsite.pem
# --- haproxy.cfg ---
frontend http_https_frontend
# 1. Écoute sur le port 80 (et redirige vers HTTPS)
bind *:80
http-request redirect scheme https unless { ssl_fc }
# 2. Écoute sur le port 443 (HTTPS)
# 'ssl' : Active le mode SSL
# 'crt' : Pointe vers le certificat
bind *:443 ssl crt /etc/haproxy/certs/monsite.pem
# 3. (Important) Ajouter ce header pour que le backend (PHP/Django)
# sache que la connexion *était* sécurisée.
http-request set-header X-Forwarded-Proto https
default_backend web_pool
backend web_pool
# (Le backend écoute en HTTP simple)
server srv1 10.0.0.1:8080 check
Le Problème : Le SPOF (Single Point of Failure)
Nous avons 10 serveurs web (c'est "HA"), mais 1 seul HAProxy. Si le serveur HAProxy tombe, *tout* le site est DOWN.
La Solution (Addon) : keepalived (VRRP)
La solution est d'avoir *deux* serveurs HAProxy (un "Master", un "Backup") qui partagent une IP Virtuelle (VIP).
keepalived (un "plugin" Linux) gère ce "failover" via le protocole VRRP :
- Les deux serveurs (HAProxy 1 et HAProxy 2) sont lancés.
keepalivedassigne l'IP Publique (VIP) à HAProxy 1 (Master).- HAProxy 1 envoie un "heartbeat" (un "ping") toutes les secondes à HAProxy 2.
- Si HAProxy 1 tombe (panne) :
- HAProxy 2 *arrête* de recevoir le heartbeat.
keepalived(sur HAProxy 2) s'auto-promeut "Master" et *vole* l'IP Publique (VIP).- Le trafic bascule (failover) sur HAProxy 2. (Temps de coupure : < 1 seconde).
Autres Outils & Addons
| Outil | Description |
|---|---|
peers (Directive) | Une fonctionnalité native de HAProxy (dans global) pour *synchroniser* les "stick tables" (sessions) entre plusieurs HAProxy (en mode Actif/Actif). |
hatop | Un outil (pip install hatop) qui fournit un top (monitoring CLI) pour HAProxy, plus léger que la page de stats web. |
Nginx | Le "concurrent". Nginx est un *serveur web* qui fait aussi du *reverse proxy* (mais HAProxy est souvent considéré comme un meilleur *load balancer* pur). |
