Chapitre 915 minIntermédiaire
Reverse proxy et répartition de charge : HAProxy sur pfSense
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- distinguer un proxy d'un reverse proxy et un reverse proxy d'un répartiteur ;
- expliquer frontend, backend, ACL, terminaison TLS et contrôle de santé ;
- publier un site avec HAProxy et ACME sur pfSense ;
- configurer un reverse proxy Nginx ou HAProxy sous Debian.
4 exercices corrigés1 schéma
Un reverse proxy (proxy inverse) est un serveur placé devant un ou plusieurs serveurs web : il reçoit les requêtes des clients à leur place, les transmet au bon serveur, puis renvoie la réponse. Quand il répartit les requêtes entre plusieurs serveurs identiques, en vérifiant qu'ils sont en état de répondre, on l'appelle répartiteur de charge (load balancer). Ce chapitre explique à quoi sert un reverse proxy, ses notions (frontend, backend, terminaison TLS, contrôles de santé), sa mise en place avec le paquet HAProxy de pfSense pour publier le site de suivi de Sorbier, et l'équivalent avec Nginx. Les règles et la DMZ qui l'entourent sont dans le cours pfSense : DMZ et proxy inverse HAProxy.
Proxy ou reverse proxy ?
| Proxy (direct, forward proxy) | Reverse proxy | |
|---|---|---|
| Placé | Devant les clients | Devant les serveurs |
| Il agit pour le compte de | L'utilisateur qui navigue | Le site qui est publié |
| Il sert à | Filtrer et journaliser la navigation des salariés, mettre en cache | Publier plusieurs sites sur une adresse, centraliser TLS, protéger et répartir |
| Le client sait-il qu'il existe ? | Souvent oui (proxy configuré dans le navigateur, ou transparent) | Non : pour le client, le reverse proxy est le site |
| Exemples | Squid, proxy d'un pare-feu nouvelle génération | HAProxy, Nginx, Apache (mod_proxy), Traefik |
Le proxy de filtrage de la navigation est traité dans Cybersécurité des infrastructures ; ce chapitre ne parle que du reverse proxy.
Ce qu'un reverse proxy apporte
Jusqu'ici, Sorbier publiait son site de suivi par une simple redirection de port (NAT) : le pare-feu envoyait tout le TCP 443 reçu sur 203.0.113.17 vers srv-web (192.168.10.225). Ça marche pour un site. Les limites arrivent vite :
- Une seule adresse publique, un seul site par port. Avec du NAT, tout le TCP 443 va vers une seule machine. Un reverse proxy lit le nom demandé (en-tête
Host, ou SNI en TLS) et envoiesuivi.sorbier.examplevers un serveur,portail.sorbier.examplevers un autre, sur la même adresse et le même port. - Les certificats sont éparpillés. Le reverse proxy fait la terminaison TLS (SSL offloading) : il détient les certificats publics et les renouvelle (ACME) à un seul endroit.
- Les serveurs sont exposés. Le client ne parle jamais directement à
srv-web; le reverse proxy peut rejeter les requêtes mal formées, limiter le débit, ajouter les en-têtes de sécurité, et, avec un module de pare-feu applicatif (WAF), bloquer des attaques web connues. - Une panne de serveur est une panne du site. Avec deux serveurs derrière lui, le reverse proxy répartit les requêtes et retire automatiquement celui qui ne répond plus.
Le vocabulaire de HAProxy
Les mêmes notions existent dans tous les reverse proxys, sous des noms proches.
| Notion | Définition | Chez Sorbier |
|---|---|---|
| Frontend | Ce que voient les clients : une adresse, un port, éventuellement un certificat | 203.0.113.17:443, certificat Let's Encrypt de suivi.sorbier.example |
| Backend | Un groupe de serveurs qui rendent le même service, et la façon de répartir entre eux | bk-suivi : srv-web (et srv-web2 plus tard) |
| ACL | Une condition testée sur la requête | « le Host est suivi.sorbier.example » |
| Action | Ce qu'on fait si la condition est vraie | « utiliser le backend bk-suivi » |
| Contrôle de santé (health check) | Une requête envoyée régulièrement à chaque serveur pour vérifier qu'il répond | GET / toutes les 2 secondes, code 2xx ou 3xx attendu |
| Terminaison TLS (SSL offloading) | Le proxy déchiffre TLS et parle au serveur en HTTP | Le cas de Sorbier |
| Passage TLS (SSL passthrough) | Le proxy transmet le flux chiffré sans le déchiffrer, d'après le SNI | Quand le serveur doit garder lui-même son certificat |
| Rechiffrement | Le proxy déchiffre, inspecte, puis rechiffre vers le serveur | Quand le réseau entre le proxy et le serveur n'est pas de confiance |
Les algorithmes de répartition
| Algorithme (nom HAProxy) | Fonctionnement | Quand le choisir |
|---|---|---|
Tourniquet (roundrobin) | Chacun son tour, éventuellement selon un poids | Serveurs identiques, requêtes courtes : le défaut |
Moins de connexions (leastconn) | Le serveur qui a le moins de connexions en cours | Connexions longues (bases de données, bureaux à distance, WebSocket) |
Adresse source (source) | Un hachage de l'adresse du client : un client va toujours sur le même serveur | Application qui garde la session en mémoire, sans cookie possible |
| Affinité par cookie | Le proxy pose un cookie qui renvoie le client vers le même serveur | Application à session locale, cas le plus courant |
Avec des poids, un serveur de poids 3 reçoit trois fois plus de requêtes qu'un serveur de poids 1 : sur 100 requêtes, 75 et 25. La redondance complète d'un service (répartition, basculement, cluster) est traitée dans le cours Haute disponibilité.
Publier le site de suivi avec HAProxy sur pfSense
HAProxy est un paquet de pfSense. Le paquet acme obtient et renouvelle les certificats Let's Encrypt. Les étapes, avec les noms des menus de pfSense CE 2.8 :
1. Installer les paquets. System > Package Manager > Available Packages : installe acme, puis haproxy.
2. Libérer le port 443. L'interface d'administration de pfSense (webConfigurator) écoute par défaut sur le 443 de toutes les interfaces : HAProxy ne pourrait pas s'y installer. Dans System > Advanced > Admin Access, change le TCP port (par exemple 8443). L'interface d'administration ne doit, de toute façon, jamais être joignable depuis le WAN : les règles du pare-feu la réservent au VLAN d'administration.
3. Obtenir le certificat. Dans Services > Acme Certificates : onglet Account Keys, crée une clé de compte pour l'ACME Server « Let's Encrypt Production ACME v2 » et enregistre-la ; onglet Certificates, crée le certificat de suivi.sorbier.example avec une méthode de validation (défi DNS chez l'hébergeur de la zone, ou défi HTTP), puis Issue. Dans General Settings, active la tâche planifiée (Cron Entry) qui renouvelle les certificats.
4. Créer le backend. Services > HAProxy, onglet Backend, Add :
| Champ | Valeur |
|---|---|
| Name | bk-suivi |
| Server list | Mode active, Name srv-web, Address 192.168.10.225, Port 80, Encrypt (SSL) décoché |
| Loadbalancing Options | Round robin |
| Health checking > Health check method | HTTP |
5. Créer le frontend. Onglet Frontend, Add :
| Champ | Valeur |
|---|---|
| Name et Status | ft-public, Active |
| External address | Listen address WAN address (IPv4), Port 443, SSL Offloading coché |
| Type | http / https (offloading) |
| Access Control lists | Name acl-suivi, Expression Host matches:, Value suivi.sorbier.example |
| Actions | Action Use Backend, Condition acl names acl-suivi, backend bk-suivi |
| Default Backend | Aucun : une requête pour un autre nom est refusée |
| Use forwardfor option | Coché : ajoute l'en-tête X-Forwarded-For |
| SSL Offloading > Certificate | Le certificat Let's Encrypt de l'étape 3 |
6. Activer HAProxy. Onglet Settings : coche Enable HAProxy, règle Maximum connections, puis Save et Apply Changes.
7. Adapter les règles du pare-feu. Supprime l'ancienne redirection de port 443 vers srv-web (Firewall > NAT). Dans Firewall > Rules > WAN, autorise TCP 443 à destination de WAN address (le pare-feu lui-même, où écoute HAProxy). Aucune règle n'est nécessaire sur la DMZ : les règles de pfSense filtrent le trafic qui entre par une interface, et le trafic émis par le pare-feu lui-même (HAProxy vers srv-web) est autorisé par défaut ; vérifie seulement que le pare-feu local de srv-web accepte TCP 80 depuis 192.168.10.238. Pour la redirection HTTP vers HTTPS, ajoute un second frontend sur le port 80 dont l'action redirige vers https, ou laisse srv-web renvoyer un 301.
L'adresse du vrai client
Derrière un reverse proxy, srv-web voit toutes les connexions venir du pare-feu (192.168.10.238), pas des clients. Ses journaux, ses statistiques et ses éventuelles protections par adresse deviennent inutiles. L'en-tête X-Forwarded-For, ajouté par le proxy (case Use forwardfor option), contient l'adresse du vrai client. Il faut dire au serveur web de la croire, mais seulement quand la requête vient du proxy :
# Sur srv-web, dans le bloc http ou server de Nginx
set_real_ip_from 192.168.10.238;
real_ip_header X-Forwarded-For;
La même chose avec Nginx ou HAProxy sous Debian
Sans pfSense, le reverse proxy est un serveur Debian dans la DMZ. Avec Nginx :
upstream suivi {
server 192.168.10.225:80 max_fails=3 fail_timeout=30s;
server 192.168.10.227:80 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl;
http2 on;
server_name suivi.sorbier.example;
ssl_certificate /etc/letsencrypt/live/suivi.sorbier.example/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/suivi.sorbier.example/privkey.pem;
location / {
proxy_pass http://suivi;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
Nginx libre ne fait que des contrôles de santé passifs : il retire un serveur après 3 échecs (max_fails) sur des requêtes réelles, pendant 30 secondes (fail_timeout). Les contrôles actifs, qui interrogent les serveurs en permanence, sont réservés à sa version commerciale. HAProxy (version 3.0 dans Debian 13) les fait en standard :
# /etc/haproxy/haproxy.cfg (extrait)
frontend ft-public
bind :80
bind :443 ssl crt /etc/haproxy/certs/
mode http
option forwardfor
http-request redirect scheme https unless { ssl_fc }
acl acl-suivi hdr(host) -i suivi.sorbier.example
use_backend bk-suivi if acl-suivi
backend bk-suivi
mode http
balance roundrobin
option httpchk GET /
server srv-web 192.168.10.225:80 check inter 2s fall 3 rise 2
server srv-web2 192.168.10.227:80 check inter 2s fall 3 rise 2
check inter 2s fall 3 rise 2 : un contrôle toutes les 2 secondes, un serveur déclaré hors service après 3 échecs consécutifs, et de retour après 2 succès. Vérifie la configuration avec haproxy -c -f /etc/haproxy/haproxy.cfg avant systemctl reload haproxy. La répartition de charge avec HAProxy et keepalived est déroulée pas à pas dans le cours Haute disponibilité.
Exercices
Exercice 1 sur 4 NAT ou reverse proxy ? Réussi À revoir
Sorbier veut publier sur sa seule adresse publique 203.0.113.17 : le site de suivi (srv-web, .225), un portail client sur un futur serveur srv-portail, et l'accès SSH de son prestataire à srv-web, sur un port non standard.
- Pourquoi une redirection de port (NAT) ne suffit-elle pas pour les deux sites ?
- Quel service publies-tu par HAProxy, lequel par une redirection de port ?
- Comment HAProxy sait-il vers quel serveur envoyer une requête HTTPS ?
Voir la réponseMasquer la réponse de l'exercice 1
- Une redirection de port envoie tout le TCP 443 de l'adresse publique vers une seule machine : impossible de servir deux sites différents sur le même port avec du NAT seul.
- Les deux sites web passent par HAProxy, qui les distingue par leur nom. L'accès SSH n'est pas du HTTP : une redirection de port dédiée (par exemple TCP 2222 vers
.225:22), limitée à l'adresse publique du prestataire, ou mieux un VPN. - Il déchiffre TLS avec le bon certificat (choisi grâce au SNI), puis lit l'en-tête
Hostde la requête et applique ses ACL («Hostestsuivi.sorbier.example» → backendbk-suivi).
Tu avais trouvé ?
Exercice 2 sur 4 Le site répond 503 Réussi À revoir
Après une mise à jour de srv-web, le site de suivi répond 503 Service Unavailable à tous les clients. Depuis srv-web lui-même, curl -I http://127.0.0.1/ renvoie HTTP/1.1 302 Found vers /connexion. Le contrôle de santé de HAProxy est configuré avec la méthode HTTP, et le statut attendu « 200 ».
- Pourquoi HAProxy répond-il 503 ?
- Propose deux corrections.
Voir la réponseMasquer la réponse de l'exercice 2
- Le contrôle de santé reçoit un 302 au lieu du 200 attendu : HAProxy déclare
srv-webhors service (DOWN). Le backend n'a plus aucun serveur disponible, d'où le 503. Le site fonctionne, c'est le contrôle qui est mal réglé après le changement de l'application. - Faire porter le contrôle sur une page qui répond 200 sans authentification (une page de santé dédiée,
/sante), ou accepter les codes 2xx et 3xx. Dans l'onglet Stats, vérifier ensuite que le serveur repasse en vert (UP).
Tu avais trouvé ?
Exercice 3 sur 4 Les poids Réussi À revoir
Le backend contient srv-web (poids 2) et srv-web2 (poids 1), en tourniquet.
- Sur 900 requêtes, combien chaque serveur en reçoit-il ?
srv-web2tombe. Que deviennent les requêtes ? Et les utilisateurs qui avaient une session sursrv-web2, si l'application garde les sessions en mémoire ?- Quel réglage évite de perdre les sessions lors d'une maintenance planifiée de
srv-web2?
Voir la réponseMasquer la réponse de l'exercice 3
- Poids total 3 :
srv-webreçoit 2/3, soit 600 requêtes ;srv-web21/3, soit 300. - Après l'échec des contrôles de santé, HAProxy envoie tout à
srv-web. Les utilisateurs desrv-web2perdent leur session (ils sont déconnectés) : la session était dans la mémoire du serveur tombé. La vraie parade est de stocker les sessions hors des serveurs web (base de données, cache partagé). - Passer
srv-web2en mode drain (ou maintenance) dans HAProxy avant l'intervention : il ne reçoit plus de nouveaux clients, et les sessions en cours se terminent normalement. Avec une affinité par cookie, les clients restent sur leur serveur tant qu'il est disponible.
Tu avais trouvé ?
Exercice 4 sur 4 Les journaux de srv-web Réussi À revoir
Depuis la mise en place de HAProxy, le journal d'accès de srv-web ne contient plus qu'une seule adresse cliente : 192.168.10.238.
- Pourquoi ?
- Que configures-tu sur le pare-feu et sur
srv-webpour retrouver les vraies adresses ? - Quel risque y a-t-il à accepter l'en-tête
X-Forwarded-Forde n'importe quelle source ?
Voir la réponseMasquer la réponse de l'exercice 4
- C'est HAProxy, sur le pare-feu, qui ouvre les connexions vers
srv-web, depuis son adresse dans la DMZ :srv-webne voit plus les clients. - Sur HAProxy, cocher Use forwardfor option dans le frontend. Sur
srv-web(Nginx),set_real_ip_from 192.168.10.238;etreal_ip_header X-Forwarded-For;, puis recharger Nginx. - N'importe quel client pourrait usurper une adresse en écrivant lui-même l'en-tête, et fausser les journaux ou contourner une restriction par adresse. On ne l'accepte que s'il vient du proxy.
Tu avais trouvé ?