URL: https://linuxfr.org/news/haproxy-1-5 Title: HAProxy 1.5 Authors: Joris Dedieu Davy Defaud, BAud, Nils Ratusznik, Benoît Sibaud, palm123, Nÿco, jcr83, azerttyu, vaxvms et NeoX Date: 2014年06月24日T16:41:56+02:00 License: CC By-SA Tags: haproxy, répartiteur, répartition, ssl, http et https Score: 66 Après quatre ans et trois mois, et pas moins de 26 versions de développement, la version réputée stable de HAProxy devient la 1.5. Même si HAProxy est avant tout un [[répartiteur de charge]] HTTP et TCP, les possibilités offertes par la version 1.5 en font le véritable couteau suisse du Web à haute charge. ![HAProxy](http://www.haproxy.org/img/logo-med.png) Il est utilisé, entre autres, par de [nombreux sites d’audience mondiale](http://www.haproxy.org/they-use-it.html), tels que Twitter, Instagram, GitHub, Reddit... Cette version apporte de nombreuses nouveautés, dont la très attendue prise en charge de l’[_offloading SSL_](http://en.wikipedia.org/wiki/SSL_acceleration). La version 1.5.0 a été rapidement suivie de quelques versions correctives. Nous en sommes à la 1.5.3, disponible depuis le 25 juillet dernier. ---- [Site officiel](http://www.haproxy.org/) [Changements](http://www.haproxy.org/download/1.5/src/CHANGELOG) [Dépot Git](http://git.haproxy.org/?p=haproxy-1.5.git) [Guide de configuration](http://cbonte.github.io/haproxy-dconv/configuration-1.5.html) ---- Listes des nouveautés =========== Inspection du contenu ----------- HAProxy 1.5 sait désormais capturer n’importe quelle partie d’une requête ou d’une réponse, y compris le contenu (_payload_) et les arguments passés dans l’URL (`url_param`). Cette fonctionnalité est essentielle car elle est à la base de beaucoup d’autres nouveautés. Pour l’administrateur système, le bénéfice est énorme : il peut désormais intervenir à n’importe quel moment de la transaction. Prise en charge du chiffrement (SSL) ----------- Jusqu’à présent, pour utiliser du chiffrement TLS avec HAProxy, il fallait soit utiliser le mode TCP, soit utiliser une version modifiée de [STunnel](https://www.stunnel.org/index.html). Désormais, HAProxy prend en charge le chiffrement SSL côté client comme côté serveur. ``` listen https_proxy bind :443 ssl crt /etc/haproxy/site.pem mode http server web1 10.0.0.1:443 ssl verify check server web2 10.0.0.2:443 ssl verify check ``` Il gère de nombreuses extensions au protocole TLS, telles que [SNI](http://fr.wikipedia.org/wiki/Server_Name_Indication), [NPN/ALPN](http://en.wikipedia.org/wiki/Next_Protocol_Negotiation) et [[OCSP]], la validation des certificats côté serveur, les certificats clients. ``` bind 192.168.10.1:443 ssl crt ./server.pem ca-file ./ca.crt verify required ``` Gestion étendue de l’IPv6 et des sockets UNIX ----------- Il est désormais possible d’utiliser indifféremment l’IPv4, l’IPv6 ou encore les _sockets_ UNIX, côté client comme côté serveur. ``` listen mysql_proxy bind /var/tmp/mysql.sock user mysql mode 666 mode tcp option mysql-check user haproxy post-41 server mysql 192.168.10.100:3306 check maxconn 200 server mysql_slave fe80:482:cafe::a200:e8ff:fe65:a:3306 check backup ``` HTTP keep‐alive de bout en bout ----------- Le _keep‐alive_ consiste à faire passer successivement plusieurs requêtes HTTP dans la même requête TCP. En général, dans une architecture Web un peu complète, on dispose de plusieurs services ayant des rôles particuliers. Par exemple, un service d’authentification, un service pour les contenus dynamiques, un autre pour les ressources statiques, etc. HAProxy doit alors inspecter chaque requête pour déterminer vers quel service l’envoyer. Jusqu’à présent, le _keep‐alive_ de bout en bout n’autorisait que l’inspection de la première requête. Et l’administrateur passait des heures à se demander pourquoi telle requête n’arrivait pas au bon endroit. C’est pourquoi l’option ```http-server-close```, permettant du _keep‐alive_ côté client uniquement, était souvent utilisée. Ce problème est désormais résolu. Outre l’_overhead_ réseau, le _keep‐alive_ côté serveur est important car certains serveurs Web n’utilisent pas de _chunk_ si celui‐ci est désactivé (ce problème est toutefois géré par l’option ```http-pretend-keepalive```). Compression des réponses HTTP ----------- Il est désormais possible d’utiliser HAProxy pour la compression des réponses HTTP. Les algorithmes [_gzip_](http://fr.wikipedia.org/wiki/Gzip) et [_deflate_](http://fr.wikipedia.org/wiki/Deflate) sont pris en charge. Elle peut être activée globalement ou localement. ``` compression gzip compression type text/html text/plain ``` HAProxy gère toute une série de cas pour lesquels la compression n’est pas pertinente, notamment les réponses déjà compressées. Toutefois, il est possible, via l’option ```compression offload```, de demander aux serveurs de ne jamais compresser. Dans ce cas, l’entête `Accept-Encoding` est réécrit à la volée. Amélioration des ACL ----------- Une conséquence directe de l’amélioration des possibilités de capture est qu’il est désormais possible de créer des listes de contrôle d’accès (ACL) sur l’ensemble des données capturables. ``` acl hello payload(0,6) -m bin 48656c6c6f0a ``` Il est également possible d’utiliser des variables : ``` http-request redirect code 301 location www.%[hdr(host)]%[req.uri] \ unless { hdr_beg(host) -i www } ``` Les maps ----------- On pouvait déjà passer à HAProxy un fichier contenant une série de valeurs (par exemple une liste d’IP à autoriser). Il est désormais possible d’utiliser des fichiers clés‐valeurs avec les mots clés ```map_*```. Par exemple, pour faire de la géolocalisation, il fallait jusqu’à présent écrire une série d’ACL : ``` acl src A1 -f A1.subnets acl src A2 -f A2.subnets acl src AD -f AD.subnets acl src AE -f AE.subnets acl src AF -f AF.subnets acl src AG -f AG.subnets acl src AI -f AI.subnets acl src AL -f AL.subnets acl src AM -f AM.subnets acl src AN -f AN.subnets ``` ACL pour lesquelles chaque fichier contenait l’ensemble des sous‐réseaux d’un pays. Désormais, il est possible de faire un seul fichier sous la forme _range pays_ : ``` 223.228.0.0/14 IN 223.232.0.0/13 IN 223.240.0.0/13 CN 223.248.0.0/14 CN 223.252.0.0/17 AU 223.252.128.0/19 CN 223.252.160.0/24 CN 223.252.161.0/26 CN 223.252.161.64/26 HK 223.252.161.128/25 CN 223.252.162.0/23 CN 223.252.164.0/22 CN 223.252.168.0/21 CN 223.252.176.0/20 CN 223.252.192.0/18 CN ``` Puis, il suffit d’écrire : ``` http-request set-header X-Country %[src,map_ip(geoip.lst)] ``` Compteurs d’activité et tables ----------- Il est désormais possible d’utiliser des tables pour comptabiliser l’activité d’un client pour des besoins aussi divers que de se souvenir d’une décision de routage ou bannir les indélicats. Par exemple, pour éviter qu’un serveur se fasse bombarder de requêtes toujours identiques (_brute force_, _spam_) : ```bash # Si on a une requête POST, on stocke dans la table un hash créé à partir de l'IP source et de l'url stick-table type binary len 20 size 5m expire 1h store http_req_rate(10s) tcp-request content track-sc1 base32+src if METH_POST # Si on a un ratio supérieur à 10 requêtes en 10 secondes alors on bannit le client acl bruteforce_detection sc1_http_req_rate gt 10 http-request deny if bruteforce_detection ``` Ces tables peuvent être contrôlées et vidées par le _socket_ de contrôle : ```bash echo show table |nc -U /tmp/haproxy.sock # table: monserveur, type: binary, size:5242880, used:468 echo show table monserveur |nc -U /tmp/haproxy.sock |tail 0x8019d9f4c: key=FD0D68C950F7E432000000000000000000000000 use=0 exp=2956851 http_req_rate(10000)=0 0x8017f8e0c: key=FD19C86D50F7E432000000000000000000000000 use=0 exp=2206531 http_req_rate(10000)=0 0x8019d970c: key=FE3651B30209AF8C000000000000000000000000 use=0 exp=820386 http_req_rate(10000)=0 0x801bcbccc: key=FE3651B356D4F7D1000000000000000000000000 use=0 exp=2985182 http_req_rate(10000)=0 0x8017fed4c: key=FE3651B35A08E3FA000000000000000000000000 use=0 exp=1701016 http_req_rate(10000)=0 0x801be15cc: key=FE3651B36DDCDC20000000000000000000000000 use=0 exp=363622 http_req_rate(10000)=0 0x801bfba8c: key=FE3651B3973CC657000000000000000000000000 use=0 exp=1302278 http_req_rate(10000)=0 0x8017f8ecc: key=FEE742DC8D6942B3000000000000000000000000 use=0 exp=693453 http_req_rate(10000)=0 0x801bdff4c: key=FEE742DC9200499B000000000000000000000000 use=0 exp=3415931 http_req_rate(10000)=0 echo clear table monserveur |nc -U /tmp/haproxy.sock echo show table |nc -U /tmp/haproxy.sock sock # table: monserveur, type: binary, size:5242880, used:1 ``` Vérification de la santé des serveurs améliorée ----------- Pour prendre des décisions de routage des requêtes, il est important de savoir quels serveurs sont en bonne santé. Outre les _checks_ HTTP, largement paramétrables, HAProxy dispose en natif de tests de vie pour les protocoles `mysql`, `pgsql`, `redis`, `ssl` et `smtp`. Il est toutefois désormais possible d’écrire des tests de vie personnalisés. Voici un exemple utilisant [`php-fpm`]( http://blog.haproxy.com/2014/06/06/binary-health-check-with-haproxy-1-5-php-fpmfastcgi-probe-example/) : ```bash option tcp-check # FCGI_BEGIN_REQUEST tcp-check send-binary 01 # version tcp-check send-binary 01 # FCGI_BEGIN_REQUEST tcp-check send-binary 0001 # request id tcp-check send-binary 0008 # content length tcp-check send-binary 00 # padding length tcp-check send-binary 00 # tcp-check send-binary 0001 # FCGI responder tcp-check send-binary 0000 # flags tcp-check send-binary 0000 # tcp-check send-binary 0000 # # FCGI_PARAMS tcp-check send-binary 01 # version tcp-check send-binary 04 # FCGI_PARAMS tcp-check send-binary 0001 # request id tcp-check send-binary 0045 # content length tcp-check send-binary 03 # padding length: padding for content % 8 = 0 tcp-check send-binary 00 # tcp-check send-binary 0e03524551554553545f4d4554484f44474554 # REQUEST_METHOD = GET tcp-check send-binary 0b055343524950545f4e414d452f70696e67 # SCRIPT_NAME = /ping tcp-check send-binary 0f055343524950545f46494c454e414d452f70696e67 # SCRIPT_FILENAME = /ping tcp-check send-binary 040455534552524F4F54 # USER = ROOT tcp-check send-binary 000000 # padding # FCGI_PARAMS tcp-check send-binary 01 # version tcp-check send-binary 04 # FCGI_PARAMS tcp-check send-binary 0001 # request id tcp-check send-binary 0000 # content length tcp-check send-binary 00 # padding length: padding for content % 8 = 0 tcp-check send-binary 00 # tcp-check expect binary 706f6e67 # pong ``` Par ailleurs, les vérifications peuvent être déléguées à un agent externe. Cela permet de configurer dynamiquement le poids du serveur dans le _pool_. L’agent doit retourner soit une valeur entre 0 % et 100 % représentant le poids relatif au poids initialement donné au serveur, soit un mot clé _ready_ (prêt), _drain_ (n’accepte plus de nouvelles connexions mais traite celles en cours), _maint_ (passe en maintenance), _down_, _up_... Pour mettre cela en place, il faut utiliser le mot clé _agent-check_. Typiquement, cela peut être un script lancé par `inetd`. Par exemple, pour adapter le poids du serveur en fonction de la charge : ```bash #!/bin/sh SYSCTL="/sbin/sysctl -n" NCPU=$(${SYSCTL} hw.ncpu) LOAD=$(${SYSCTL} vm.loadavg | awk '{print 2ドル}') LOAD=${LOAD%.*} if [ ${LOAD} -ge ${NCPU} ]; then PERCENT="100" else PERCENT=$((${LOAD}*100/${NCPU})) fi echo "$PERCENT%" ``` On paramètre ensuite `inetd.conf` de la façon suivante : ``` dec-notes stream tcp nowait nobody /usr/local/bin/agent-check ``` Enfin, la configuration pour HAProxy est : ``` server server1 192.168.64.50:3389 weight 100 check agent-check agent-port 3333 ``` Version 2 du proxy protocol ----------- Le [_proxy protocol_](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) est un protocole simple qui permet à l’adresse IP d’un client d’être conservée lorsqu’une requête passe de serveurs en serveurs. Si en HTTP, l’en‐tête `X-Forwarded-For` est largement utilisée à cette fin, il fallait un mécanisme plus universel, utilisable notamment en mode TCP. Initialement, ce protocole a été conçu pour utiliser HAProxy conjointement avec STunnel. Il est désormais pris en charge par Elastic Load Balancing, ExaProxy, Exim, Gunicorn, HAProxy, NGINX, Postfix, stud et stunnel. La version 2 modifie profondément la nature du protocole, puisqu’on passe d’une version humainement lisible à une version binaire. Par exemple, avec Postfix, il faudra dans HAProxy utiliser la configuration ci‐après : ``` mode tcp option smtpchk server postfix 127.0.0.1:10024 send-proxy check ``` Une configuration Postfix (`master.cf`) sera aussi nécessaire : ``` postscreen_upstream_proxy_protocol = haproxy ``` Prise en charge de systemd ----------- HAProxy ne peut pas recharger sa configuration. Pour le redémarrer, on doit tuer l’ancien processus et en lancer un nouveau. Toutefois, afin de ne pas fermer les sessions brutalement, il existe l’option `-st` qui permet au nouveau processus de remplacer l’ancien proprement. Ce comportement ne convenant pas à _systemd_, qui ne sait pas remplacer un processus par un autre, l’option `-Ds` et le démon ```haproxy-systemd-wrapper``` permettent désormais de fonctionner avec ce système d’initialisation. Nouveau cycle de développement =========== Willy Tarreau explique dans un [long courriel](http://marc.info/?l=haproxy&m=140630935820775&w=1) ses plans pour les prochaines versions de HAProxy, ainsi que les leçons à tirer de la version 1.5, dont le développement a été particulièrement long. Selon lui, il faut arrêter de promettre telle ou telle fonctionnalité pour telle version, et fonctionner en périodes, à la mode Linux. Ainsi le développement de la version 1.6 s’arrêtera en mars 2015, pour une sortie en mai ou juin de la même année. Il indique toutefois les directions qu’il souhaite prendre : - multi‐processus : meilleure synchronisation des états et des vérifications. Vue l’arrivée de ces _monstres de latence_ que sont SSL et la compression, une architecture gérant la concurrence serait sans doute bénéfique. Il est toutefois exclu d’ajouter des _mutex_ partout dans le code. - reconfiguration à chaud : dans les environnements dynamiques, on est souvent contraint de relancer HAProxy. Même si de nombreuses possibilités sont désormais offertes par le _socket_ de contrôle, il serait intéressant d’aller plus loin dans ce sens. - DNS : actuellement HAProxy ne résout les noms d’hôte qu’au démarrage. Il serait intéressant, en particulier pour les utilisateurs de EC2, que cela puisse être fait dynamiquement. - cache d’objets en mémoire : il ne s’agit pas de concurrencer Varnish, mais d’implémenter un petit cache afin de réduire le trafic entre HAProxy et les serveurs d’origine des objets. Plutôt un cache avec un ratio de _hits_ de 50 % sans maintenance, qu’un cache efficace à 90 % mais demandant beaucoup d’attention. - amélioration de la réutilisation des connexions : dans certains cas, il est particulièrement intéressant de conserver les connexions réseau en vie, même si cela ouvre de nouvelles problématiques comme la supervision des connexions. - HTTP/2 : Willy Tarreau étant particulièrement investi dans le groupe de travail _http-bis_ qui spécifie entre autres HTTP/2, c’est donc sans surprise qu’il place l’implémentation de cette nouvelle version du protocole en tête de ses priorités. Exemple d’utilisation =========== Imaginons un site Web servi par un parc de serveurs sur lesquels nous voulons mettre en place de l’équilibrage de charge (_load balancing_) et de la tolérance de panne. Une bonne idée est alors de créer un _cluster_ de HAProxy actif/actif avec au moins deux machines en utilisant le _round‐robin_ DNS et un mécanisme de _failover_ tel que CARP ou _keepalived_. Nous allons commencer par une configuration basique à laquelle nous ajouterons peu à peu des fonctionnalités. ## Paramètres globaux On commence par définir quelques généralités comme les journaux (_logs_), le maximum de connexions, le comportement du démon. ``` global log /var/run/log local0 notice maxconn 4096 uid 99 gid 99 daemon chroot /var/empty ``` ## Paramètres par défaut On ajoute ensuite, une section par défaut qui contiendra l’ensemble des paramètres qui, s’ils ne sont pas surchargés, s’appliqueront à nos _proxys_/mandataires. ```bash defaults # par défaut on logue avec ce qui est défini # dans la section globale log global # on peut définir très finement les différents timeout # le temps qu'une connexion client peut rester idle timeout client 40s # le temps entre une réponse et le début de la requête # suivante dans une connexion keepalive timeout http-keep-alive 30s # Le temps entre le début d'une requête et la fin des entêtes timeout http-request 10s # Workaround pour certains navigateurs # bogués avec le timeout http-request errorfile 408 /dev/null # Le temps durant lequel on attend une réponse du serveur timeout server 60s # Le temps qu'une connexion peut rester en attente # d'un slot disponible # timeout queue 1500 # le temps que met un client a établir une connexion tcp timeout connect 5s # Combien de fois on réessaye de se connecter à un serveur retries 3 # On redistribue les sessions en cas d'échec de # connexion avec un serveur option redispatch # Par défaut on fait du http mode http # Par défaut le mot check signifie check http option httpchk # On ajoute l'entête X-Forwarded-Forr option forwardfor # On utilise l'algorithme roundrobin balance roundrobin # On logue des sessions http option httplog # On ne logue pas les connexions sur lesquelles # il ne se passe rien option dontlognull # Aucun proxy ne pourra avoir plus de 2048 connexions ouvertes # Soit la moitié des connexions acceptables maxconn 2048 ``` ## Le proxy/mandataire On déclare ensuite notre proxy de la façon la plus simple possible, on ajoutera les fioritures après : ```bash listen http_proxy bind :80 server web1 192.168.42.11:80 server web2 192.168.42.12:80 server web3 192.168.42.13:80 ``` Il est nommé _http_proxy_, écoute sur le port 80. Il équilibre les connexions suivant l’algorithme _round‐robin_ vers trois serveurs nommés _web1_, _web2_ et _web3_. D’autres algorithmes de répartition sont bien évidement disponibles : - **_static-rr_** est une variante de _round‐robin_ sans limitation du nombre de serveurs (4 095 pour _round‐robin_), mais sans prise en compte du poids ; - **_leastconn_**, adapté aux sessions longues (LDAP, TSE...), c’est le serveur qui a le moins de connexions actives (pondéré par son poids) qui est choisi ; - **_first_**, le premier serveur est utilisé jusqu’à `maxconn`, puis on passe au suivant, ce qui est idéal pour pouvoir éteindre des serveurs aux heures creuses ; - d’autres algorithmes basés sur un _hash_ de l’IP, l’URL, un paramètre de la requête, un en‐tête HTTP, ou le _cookie_ RDP. Le paramètre ```balance``` défini dans la section globale, pourrait être surchargé ici. Savoir ce qu’il se passe ----------- Il y a plusieurs défauts sur notre configuration : - les _logs_ ne fonctionnent pas car HAProxy étant « chrooté », il ne peut pas accéder au _socket_ UNIX ; - si un serveur Web tombe, HAProxy n’est pas au courant et nous non plus. Concernant les _logs_, il suffit de modifier la section globale : ```bash log localhost local0 notice ``` Il faudra ensuite configurer son serveur de _log_ préféré pour pouvoir récupérer les _logs_ en UDP sur l’interface _loopback_. Pour vérifier l’état de santé des serveurs il suffit d’ajouter le mot clé _check_ à la fin de la déclaration des serveurs : ```bash server web1 192.168.42.11:80 check ``` Dans ce cas, HAProxy lancera une requête ```OPTIONS /``` sur le serveur toutes les 2 secondes. On peut chercher à faire plus fin, comme, par exemple, une requête vers une URL applicative se connectant à une base de données. En bref, ne pas vérifier simplement l’état de santé du serveur mais également celui de l’application. Dans ce cas, il faut compléter l’option `httpchk` : ```bash listen http_proxy bind :80 option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com http-check expect string pong server web1 192.168.42.11:80 check inter 30s server web2 192.168.42.12:80 check inter 30s server web3 192.168.42.13:80 check inter 30s ``` Du coup, on va aller chercher sur chaque serveur l’URL `/ping` de l’hôte _www.example.com_ toutes les 30 secondes et l’on attendra que le serveur nous réponde avec une page contenant le mot « pong ». Nos serveurs sont donc bien surveillés par HAProxy, mais pour notre part — exception faite des _logs_ — nous sommes aveugles. Pour remédier à cela, nous allons activer le _socket_ de contrôle ainsi que l’interface d’administration. La première s’active dans la section globale : ```bash stats socket /tmp/haproxy_prod_admin.sock user root group nagios mode 660 level admin ``` On peut ensuite l’utiliser avec un programme comme `socat` par exemple. Elle est également utilisée par des utilitaires comme [HAtop](http://feurix.org/projects/hatop) ou [l’excellente sonde Nagios de Polymorf](https://github.com/polymorf/check_haproxy/blob/master/check_haproxy.pl) : ``` socat /tmp/haproxy.sock readline prompt> help Unknown command. Please enter one of the following commands only : clear counters : clear max statistics counters (add 'all' for all counters) clear table : remove an entry from a table help : this message prompt : toggle interactive mode with prompt quit : disconnect show info : report information about the running process show stat : report counters for each proxy and server show errors : report last request and response errors for each proxy show sess [id] : report the list of current sessions or dump this session show table [id]: report table usage stats or dump this table's contents get weight : report a server's current weight set weight : change a server's weight set table [id] : update or create a table entry's data set timeout : change a timeout setting set maxconn : change a maxconn setting set rate-limit : change a rate limiting value disable : put a server or frontend in maintenance mode enable : re-enable a server or frontend which is in maintenance mode shutdown : kill a session or a frontend (eg:to release listening ports) ``` Quant à la seconde, elle s’active soit dans un _proxy_ à part, soit dans un _proxy_ existant. Celle‐ci donne l’état actuel des _proxies_, ainsi qu’un certain nombre de statistiques. ```bash listen http_proxy bind :80 option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com http-check expect string pong server web1 192.168.42.11:80 check inter 30s server web2 192.168.42.12:80 check inter 30s server web3 192.168.42.13:80 check inter 30s stats enable stats uri /admin?stats stats realm Haproxy\ Statistics stats auth admin:s3cR3T ``` ![Stats HAProxy](http://rmdir.fr/haproxy.png) ## Routage plus complexe Pour l’instant notre schéma de fonctionnement est très simple. S’il doit se complexifier, il deviendra utile de séparer les blocs ```listen``` en ```frontend``` et ```backend```. Cela nous donne : ```bash frontend http_proxy bind :80 stats enable stats uri /haproxy stats realm Haproxy\ Statistics stats auth admin:s3cR3T default_backend web_servers backend web_servers option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com http-check expect string pong server web1 192.168.42.11:80 check inter 30s server web2 192.168.42.12:80 check inter 30s server web3 192.168.42.13:80 check inter 30s ``` Ainsi, si nous souhaitons offrir la possibilité d’utiliser le site en version HTTPS, il nous suffit d’ajouter un second frontal : ```bash frontend https_proxy bind :443 ssl crt /etc/certificates/website.pem reqadd X-Forwarded-proto:\ https default_backend web_servers ``` Si derrière on utilise Apache, ajoutons dans sa configuration la ligne suivante : ```apache SetEnvIfNoCase X-Forwarded-Proto HTTPS HTTPS=on ``` Cela permettra à nos utilisateurs de retrouver les bonnes variables d’environnement (en PHP par exemple : ```$_SERVER["HTTPS"]```). Si l’on veut reconnaître un utilisateur authentifié grâce au _cookie_ MYSSO, il est alors facile de le rediriger systématiquement vers la version chiffrée du site : ```bash frontend http_proxy bind :80 stats enable stats uri /haproxy stats realm Haproxy\ Statistics stats auth admin:s3cR3T acl is_logged cook MYSSO -m found redirect scheme https if is_logged default_backend web_servers ``` Bien évidemment, on peut souhaiter qu’ils s’identifient sur une page chiffrée, voire sur des serveurs séparés : ```bash frontend http_proxy bind :80 stats enable stats uri /haproxy stats realm Haproxy\ Statistics stats auth admin:s3cR3T acl is_logged cook MYSSO -m found acl to_login url_beg /login redirect scheme https if is_logged or to_login default_backend web_servers ``` À noter que pour former la condition, le ```or``` doit être spécifié alors qu’un ```and``` aurait été implicite. Enfin, nous voulons que l’accès aux statistiques et au backoffice du site soit sécurisé par une vérification du certificat client. Nous allons commencer par créer un _back‐end_ particulier donnant accès au serveur de _back office_. Il contiendra en plus l’accès aux statistiques que nous supprimons du coup du _front‐end_ public : ```bash backend very_secure stats enable stats uri /haproxy stats realm Haproxy\ Statistics stats auth admin:s3cR3T server admin 192.168.9.42:80 ``` Le _front‐end_ public devient : ```bash frontend http_proxy bind :80 acl is_logged cook MYSSO -m found acl to_login url_beg /login redirect scheme https if is_logged or to_login default_backend web_servers ``` Sur la partie HTTPS, nous allons donc vérifier la présence d’un certificat client et, s’il est présent et valable, donner l’accès au _back office_ et aux statistiques HAProxy. Pour cela, il faut fournir à HAProxy l’autorité de certification (`ca-file`) et éventuellement une liste de révocation (`crl-file`) : ```bash frontend https_proxy bind :443 ssl crt /etc/certificates/website.pem ca-file /etc/certificates/website.ca verify optional crl-file /etc/certificates/website.crl reqadd X-Forwarded-proto:\ https acl client_ok ssl_fc_has_crt acl want_admin if url_beg /admin acl want_admin if url_beg /haproxy use_backend very_secure if want_admin and client_ok default_backend web_servers ``` La négociation SSL échouera si le certificat présenté est invalide ou révoqué, mais pas s’il est absent (mot‐clé `optional`). ## Coller au serveur et gérer les pannes Pour diverses raisons, on peut vouloir que le client ne change pas de serveur durant la durée de sa session. La plus mauvaise de ces raisons est que les sessions applicatives ne sont pas partagées, la meilleure étant que cela permet d’effectuer des trucs sympathiques, comme des mises à jour applicatives sans interruption de service ou encore de faciliter le débogage. La façon la plus simple de faire est d’insérer un _cookie_. Si celui‐ci est présent, HAProxy essayera d’utiliser le serveur visé : ```bash backend web_servers option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com http-check expect string pong cookie SRV insert server web1 192.168.42.11:80 check inter 30s cookie web1 server web2 192.168.42.12:80 check inter 30s cookie web2 server web3 192.168.42.13:80 check inter 30s cookie web3 ``` Ainsi, pour savoir sur quel serveur vous êtes, il suffit de regarder la valeur du _cookie_ SRV. C’est aussi le moment d’introduire la notion de poids. On peut en effet moduler l’importance de chaque serveur au sein du répartiteur de charge (_load‐balancer_) : ```bash backend web_servers option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com http-check expect string pong cookie SRV insert server web1 192.168.42.11:80 check inter 30s cookie web1 weight 10 server web2 192.168.42.12:80 check inter 30s cookie web2 weight 10 server web3 192.168.42.13:80 check inter 30s cookie web3 weight 20 ``` Le poids peut être piloté par le _socket_ de contrôle. Par exemple, pour passer le poids du serveur _web2_ à zéro : ```bash echo "set weight web_servers/web2 0" | nc -U /tmp/haproxy_prod_admin.sock ``` Un poids de 0 ne signifie pas que le serveur est tombé, mais qu’il n’accepte plus de nouvelle session (laissant ainsi finir tranquillement celles en cours). On peut également spécifier un serveur de secours (_backup_) : ```bash backend web_servers option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com option allbackup http-check expect string pong cookie SRV insert server web1 192.168.42.11:80 check inter 30s cookie web1 weight 10 server web2 192.168.42.12:80 check inter 30s cookie web2 weight 10 server web3 192.168.42.13:80 check inter 30s cookie web3 weight 20 server maintenance1 192.168.42.21:80 backup check inter 30s server maintenance2 192.168.42.22:80 backup check inter 30s ``` L’option `allbackup` spécifie que lorsque tous les serveurs sont tombés, tous les serveurs de secours (et pas seulement le premier disponible) doivent être utilisés. Bien sûr, le _backup_ est utile pour servir les pages de maintenance, mais également pour se replier en cas de problème logiciel. Ainsi, par exemple, si nous souhaitons utiliser Varnish pour servir les fichiers statiques, nous pouvons faire quelque chose comme : ```bash acl url_static url_reg -i ^\/(.*)\.(js|jpg|JPG|jpeg|gif|png|ico|txt|css|pdf)(\?.*)? use_backend varnish if url_static ``` dans les _front‐ends_, puis : ```bash backend varnish option httpchk GET /ping HTTP/1.1\r\nHost:\ www.example.com option allbackup http-check expect string pong server varnish 127.0.0.1:8080 check inter 30s server web1 192.168.42.11:80 check inter 30s backup server web2 192.168.42.12:80 check inter 30s backup server web3 192.168.42.13:80 check inter 30s backup ``` Ainsi, en cas d’indisponibilité du serveur Varnish, les fichiers sont servis par les serveurs principaux. ## Et ainsi de suite Lorsqu’on en prend l’habitude, HAProxy devient vite un outil indispensable. Il offre une telle souplesse, que ce soit en mode TCP ou HTTP, qu’il est difficile de rencontrer des situations pour lesquelles on ne puisse pas imaginer de solutions l’utilisant. D’autant plus qu’il excelle en termes de performance. Autrement dit : c’est bon, mangez‐en !

AltStyle によって変換されたページ (->オリジナル) /