HAProxy en pratique : load balancing et haute disponibilité sur Ubuntu
1. Qu'est-ce que HAProxy ?
HAProxy (High Availability Proxy) est un load balancer et reverse proxy open source haute performance. Il est utilisé dans la majorité des grandes infrastructures web pour répartir le trafic entre plusieurs serveurs et garantir la disponibilité des services.
HAProxy vs Nginx
| Fonctionnalité | HAProxy | Nginx |
|---|---|---|
| Load balancing | Spécialisé, très avancé | Basique |
| Reverse proxy | Oui | Oui (principale fonction) |
| Serveur de fichiers statiques | Non | Oui |
| Health checks | Très avancés | Basiques |
| Dashboard de stats | Intégré | Non (module externe) |
| Performance | Extrême (millions de connexions) | Très bonne |
Règle simple : Nginx pour servir du contenu, HAProxy pour distribuer le trafic.
Architecture type en production
Internet
↓
HAProxy (point d'entrée unique)
↓ ↓ ↓
Serveur 1 Serveur 2 Serveur 3
2. Concepts clés
Frontend
Point d'entrée du trafic. HAProxy écoute sur un port et attend les connexions entrantes.
Backend
Groupe de serveurs qui vont répondre aux requêtes. HAProxy choisit quel serveur utiliser selon l'algorithme de load balancing configuré.
Health Check
Vérification régulière de l'état de chaque serveur backend. Si un serveur ne répond plus, HAProxy l'exclut automatiquement de la rotation et y renvoie le trafic dès qu'il revient.
Load Balancing
Répartition du trafic entre plusieurs serveurs selon un algorithme défini.
3. Architecture du Lab
Infrastructure mise en place
┌─────────────────────────────────────────────────────┐
│ VMware Workstation │
│ │
│ ┌──────────────────┐ │
│ │ haproxy-lb │ │
│ │ 192.168.145.134 │ ← Point d'entrée unique │
│ │ HAProxy 2.8 │ │
│ └────────┬─────────┘ │
│ │ Round Robin │
│ ┌─────┴──────┐ │
│ ↓ ↓ │
│ ┌──────────┐ ┌──────────┐ │
│ │backend- │ │backend- │ │
│ │web │ │web2 │ │
│ │.135:8080 │ │.136:8080 │ │
│ │Nginx │ │Nginx │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────┘
4. Installation
sudo apt update
sudo apt install haproxy -y
sudo systemctl status haproxy
Fichiers importants
| Fichier | Rôle |
|---|---|
/etc/haproxy/haproxy.cfg | Fichier de configuration principal |
/var/log/haproxy.log | Logs HAProxy |
/run/haproxy/haproxy.pid | PID du processus |
5. Configuration complète commentée
global
log /dev/log local0
# Envoie les logs vers syslog
# local0 = facilité syslog utilisée par HAProxy
maxconn 2000
# Nombre maximum de connexions simultanées
daemon
# HAProxy tourne en arrière-plan comme un daemon système
defaults
log global
# Hérite de la configuration de logs définie dans "global"
mode http
# Mode HTTP : analyse et comprend le protocole HTTP (layer 7)
# mode tcp : passe le trafic sans l'analyser (layer 4, plus rapide)
option httplog
# Active les logs détaillés HTTP
timeout connect 5s
# Délai maximum pour établir la connexion avec un backend
timeout client 30s
# Délai maximum d'inactivité côté client
timeout server 30s
# Délai maximum d'inactivité côté serveur backend
frontend web_frontend
bind *:80
# Écoute sur toutes les interfaces sur le port 80
default_backend web_backend
# Envoie tout le trafic vers le groupe "web_backend"
backend web_backend
balance roundrobin
# Algorithme de répartition : chaque serveur à son tour
server backend1 192.168.145.135:8080 check
# nom : backend1 | ip:port | check = health check activé
server backend2 192.168.145.136:8080 check
listen stats
bind *:8404
# Dashboard accessible sur le port 8404
stats enable
stats uri /stats
# URL : http://IP:8404/stats
stats refresh 10s
# Rafraîchissement automatique toutes les 10 secondes
6. Dashboard de monitoring
Le dashboard HAProxy accessible sur http://192.168.145.134:8404/stats affiche en temps réel l'état de tous les serveurs.

Colonnes importantes
| Colonne | Signification |
|---|---|
| Status | État du serveur (UP/DOWN) |
| LastChk | Résultat du dernier health check |
| Sessions Total | Nombre total de connexions traitées |
| Bytes In/Out | Volume de données transférées |
| Dwntme | Temps total passé en état DOWN |
7. Load Balancing Round Robin en action
La commande suivante envoie 6 requêtes successives à HAProxy et montre la répartition entre les deux backends :
for i in {1..6}; do curl http://192.168.145.134; echo; done

Le résultat montre que les requêtes alternent parfaitement entre backend-web et backend-web2 - c'est le Round Robin en action.
8. Health Check - Détection automatique de panne
Quand un backend tombe, HAProxy le détecte en quelques secondes et redirige tout le trafic vers les serveurs disponibles.
Simulation de panne
# Sur backend-web : désactiver le service
sudo rm /etc/nginx/sites-enabled/backend-lab
sudo systemctl reload nginx

Ce qu'on observe
- backend1 passe en rouge avec le statut DOWN
- backend2 continue en vert avec le statut UP
- HAProxy redirige automatiquement tout le trafic vers backend2
- Aucune interruption de service pour l'utilisateur
Réintégration automatique
Quand le serveur revient :
# Sur backend-web : réactiver le service
sudo ln -s /etc/nginx/sites-available/backend-lab /etc/nginx/sites-enabled/
sudo systemctl reload nginx
HAProxy détecte que backend1 est de nouveau disponible et le réintègre dans la rotation sans intervention manuelle.
9. Algorithmes de load balancing
Round Robin (défaut)
balance roundrobin
Distribue les requêtes à tour de rôle. Idéal pour : serveurs avec des capacités identiques.
Least Connections
balance leastconn
Envoie la requête au serveur qui a le moins de connexions actives. Idéal pour : requêtes de durée variable (sessions longues).
Source (IP Hash)
balance source
Le même client est toujours envoyé vers le même serveur. Idéal pour : applications avec sessions sans mécanisme de session partagée.
Weighted Round Robin
server backend1 192.168.145.135:8080 check weight 3
server backend2 192.168.145.136:8080 check weight 1
backend1 reçoit 3x plus de trafic que backend2. Idéal pour : serveurs avec des capacités différentes.
10. Health Check avancé
# Health check TCP (par défaut)
server backend1 192.168.145.135:8080 check
# Health check HTTP
option httpchk GET /health
server backend1 192.168.145.135:8080 check
# Paramètres avancés
server backend1 192.168.145.135:8080 check inter 2s fall 3 rise 2
# inter 2s : vérification toutes les 2 secondes
# fall 3 : 3 échecs consécutifs → serveur DOWN
# rise 2 : 2 succès consécutifs → serveur UP
États possibles
| Couleur | État | Signification |
|---|---|---|
| Vert | UP | Serveur opérationnel |
| Rouge | DOWN | Serveur hors service |
| Jaune | going down | Serveur en train de tomber |
| Orange | going up | Serveur en train de revenir |
11. Serveur Backup
Un serveur backup ne reçoit du trafic que si tous les serveurs actifs sont down.
backend web_backend
balance roundrobin
server backend1 192.168.145.135:8080 check
server backend2 192.168.145.136:8080 check
server backup1 192.168.145.137:8080 check backup
12. ACL - Routage conditionnel
Les ACL (Access Control Lists) permettent de router le trafic selon des règles précises : URL, domaine, headers, IP du client...
Principe
Requête arrive sur HAProxy
↓
HAProxy évalue les ACL
↓
/api/* → api_backend (backend1)
/web/* → web_backend (backend2)
autre → api_backend (défaut)
Configuration utilisée dans le lab
frontend web_frontend
bind *:80
# Définition des ACL
acl is_api path_beg /api/
# path_beg = "path begins with" (l'URL commence par)
acl is_web path_beg /web/
# Routage selon les ACL
use_backend api_backend if is_api
use_backend web_backend if is_web
default_backend api_backend
# Si aucune ACL ne correspond → api_backend par défaut
backend api_backend
balance roundrobin
server backend1 192.168.145.135:8080 check
backend web_backend
balance roundrobin
server backend2 192.168.145.136:8080 check
Test des ACL
# Doit aller vers backend1 (api_backend)
curl http://192.168.145.134/api/test
# Doit aller vers backend2 (web_backend)
curl http://192.168.145.134/web/test

Résultat observé
/api/test → Backend Web (backend1) ← api_backend
/web/test → Backend Web 2 (backend2) ← web_backend
Autres types d'ACL
# Router selon le domaine
acl is_api hdr(host) -i api.monsite.com
acl is_blog hdr(host) -i blog.monsite.com
# Router selon un header HTTP
acl is_mobile hdr(User-Agent) -i -m sub Mobile
# Router selon l'IP source
acl is_internal src 192.168.0.0/16
# Router selon la méthode HTTP
acl is_post method POST
13. Rate Limiting - Protection contre les abus
Le rate limiting permet de limiter le nombre de requêtes par IP sur une période donnée. C'est une protection essentielle contre les attaques DDoS et le brute force.
Configuration
frontend web_frontend
bind *:80
# Créer une table pour compter les requêtes par IP
stick-table type ip size 100k expire 30s store http_req_rate(10s)
# type ip : indexé par adresse IP
# size 100k : jusqu'à 100 000 IPs suivies simultanément
# expire 30s : entrée supprimée après 30s d'inactivité
# http_req_rate(10s) : compteur de requêtes sur 10 secondes
# Suivre l'IP du client
http-request track-sc0 src
# track-sc0 : utilise le compteur 0 (sticky counter 0)
# src : indexé par IP source du client
# Bloquer si plus de 10 requêtes en 10 secondes
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 10 }
# deny_status 429 : retourne HTTP 429 Too Many Requests
# sc_http_req_rate(0) gt 10 : si le compteur dépasse 10
acl is_api path_beg /api/
acl is_web path_beg /web/
use_backend api_backend if is_api
use_backend web_backend if is_web
default_backend api_backend
Test du rate limiting
for i in {1..15}; do curl -s -o /dev/null -w "%{http_code}\n" http://192.168.145.134/api/test; done

Résultat observé
200 ← requête 1
200 ← requête 2
...
200 ← requête 10
429 ← requête 11 (bloquée)
429 ← requête 12 (bloquée)
429 ← requête 13 (bloquée)
429 ← requête 14 (bloquée)
429 ← requête 15 (bloquée)
Après 10 requêtes en 10 secondes depuis la même IP, HAProxy retourne automatiquement 429 Too Many Requests sans même contacter les backends.
Pourquoi c'est important
En production, le rate limiting protège contre :
- Les attaques par force brute sur les endpoints d'authentification
- Les attaques DDoS par flood de requêtes
- Le scraping abusif
- Les bots malveillants
14. SSL/TLS - Terminaison HTTPS
La terminaison SSL dans HAProxy signifie que HAProxy gère tout le chiffrement HTTPS côté client et communique en HTTP simple avec les backends en interne.
Client → HTTPS → HAProxy (déchiffre SSL) → HTTP → Backend
Avantages
- Les backends n'ont pas besoin de certificat SSL
- Gestion centralisée des certificats
- Moins de charge CPU sur les backends
- Configuration SSL en un seul endroit
Générer un certificat auto-signé (lab)
sudo mkdir -p /etc/haproxy/certs
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/haproxy/certs/haproxy.key \
-out /etc/haproxy/certs/haproxy.crt \
-subj "/C=FR/ST=IDF/L=Paris/O=TJEH/CN=haproxy-lab.local"
HAProxy a besoin d'un fichier unique combinant certificat et clé :
sudo cat /etc/haproxy/certs/haproxy.crt /etc/haproxy/certs/haproxy.key \
| sudo tee /etc/haproxy/certs/haproxy.pem
sudo chmod 600 /etc/haproxy/certs/haproxy.pem
Configuration HAProxy avec SSL
frontend web_frontend_http
bind *:80
# Redirection automatique HTTP → HTTPS
http-request redirect scheme https unless { ssl_fc }
# ssl_fc = "SSL/TLS front connection"
# unless = sauf si la connexion est déjà en HTTPS
frontend web_frontend_https
bind *:443 ssl crt /etc/haproxy/certs/haproxy.pem
# ssl = active SSL/TLS
# crt = chemin vers le fichier .pem (cert + clé)
# Rate limiting
stick-table type ip size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 10 }
# ACL
acl is_api path_beg /api/
acl is_web path_beg /web/
use_backend api_backend if is_api
use_backend web_backend if is_web
default_backend api_backend
Vérification du certificat
# Vérifier que le port 443 écoute
sudo ss -tlnp | grep :443
# Inspecter le certificat
echo | openssl s_client -connect 192.168.145.134:443 2>/dev/null \
| openssl x509 -noout -dates
Résultat observé dans le lab :
notBefore=May 17 14:46:36 2026 GMT
notAfter=May 17 14:46:36 2027 GMT
Protocole : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Clé RSA : 2048 bits
Test de la redirection HTTP → HTTPS
# Doit retourner 302 Found (redirection vers HTTPS)
curl -v http://192.168.145.134/api/test 2>&1 | grep -E "Location|HTTP/"
# Test HTTPS (-k pour ignorer l'avertissement du certificat auto-signé)
curl -k https://192.168.145.134/api/test
En production avec Let's Encrypt
En production on remplace le certificat auto-signé par un certificat Let's Encrypt gratuit et reconnu par tous les navigateurs :
# Installer Certbot
sudo apt install certbot -y
# Générer le certificat
sudo certbot certonly --standalone -d mondomaine.com
# Combiner pour HAProxy
sudo cat /etc/letsencrypt/live/mondomaine.com/fullchain.pem \
/etc/letsencrypt/live/mondomaine.com/privkey.pem \
| sudo tee /etc/haproxy/certs/mondomaine.pem
# Renouvellement automatique (cron)
echo "0 0 * * * certbot renew --quiet && systemctl reload haproxy" \
| sudo tee -a /etc/crontab
15. Sécuriser le Dashboard
En production, le dashboard ne doit jamais être accessible sans authentification.
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:motdepasse_fort
stats hide-version
stats show-node
16. Commandes utiles
# Vérifier la syntaxe de la config
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
# Recharger sans interruption de service
sudo systemctl reload haproxy
# Redémarrer
sudo systemctl restart haproxy
# Logs en temps réel
sudo tail -f /var/log/haproxy.log
# Sauvegarder la config
sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
17. Cas d'usage en production
Haute disponibilité web
Internet → HAProxy → [Nginx 1, Nginx 2, Nginx 3]
Si un serveur tombe, les autres continuent - aucune interruption de service.
Séparation API / Frontend
Internet → HAProxy
/api/* → Backend FastAPI [API 1, API 2]
/* → Frontend Next.js [Web 1, Web 2]
Déploiement sans interruption (Blue/Green)
1. Déployer la nouvelle version sur backend2
2. Retirer backend1 de la rotation
3. Tester backend2 en production
4. Remettre backend1 avec la nouvelle version
5. Résultat : zéro downtime