| |
| H A - P r o x y |
| --------------- |
| version 1.1.27 |
| willy tarreau |
| 2003/10/27 |
| |
| ================ |
| | Introduction | |
| ================ |
| |
| HA-Proxy est un relais TCP/HTTP offrant des facilités d'intégration en |
| environnement hautement disponible. En effet, il est capable de : |
| - effectuer un aiguillage statique défini par des cookies ; |
| - effectuer une répartition de charge avec création de cookies pour assurer la |
| persistence de session ; |
| - fournir une visibilité externe de son état de santé ; |
| - s'arrêter en douceur sans perte brutale de service ; |
| - modifier/ajouter/supprimer des entêtes dans la requête et la réponse ; |
| - interdire des requêtes qui vérifient certaines conditions ; |
| - utiliser des serveurs de secours lorsque les serveurs principaux sont hors |
| d'usage. |
| |
| Il requiert peu de ressources, et son architecture événementielle mono-processus |
| lui permet facilement de gérer plusieurs milliers de connexions simultanées sur |
| plusieurs relais sans effondrer le système. |
| |
| |
| =========================== |
| | Paramètres de lancement | |
| =========================== |
| |
| Les options de lancement sont peu nombreuses : |
| |
| -f <fichier de configuration> |
| -n <nombre maximal total de connexions simultanées> |
| -N <nombre maximal de connexions simultanées par proxy> |
| -d active le mode debug |
| -D passe en daemon |
| -p <fichier> indique au processus père qu'il doit écrire les PIDs de ses |
| fils dans ce fichier en mode démon. |
| -s affiche les statistiques (si option compilée) |
| -l ajoute des informations aux statistiques |
| |
| Le nombre maximal de connexion simultanées par proxy est le paramètre par défaut |
| pour les proxies pour lesquels ce paramètre n'est pas précisé dans le fichier de |
| configuration. Il s'agit du paramètre 'maxconn' dans les sections 'listen'. |
| |
| Le nombre maximal total de connexions simultanées limite le nombre de connexions |
| TCP utilisables à un instant donné par le processus, tous proxies confondus. Ce |
| paramètre remplace le paramètre 'maxconn' de la section 'global'. |
| |
| Le mode debug correspond à l'option 'debug' de la section 'global'. Dans ce |
| mode, toutes les connexions, déconnexions, et tous les échanges d'entêtes HTTP |
| sont affichés. |
| |
| Les statistiques ne sont disponibles que si le programme a été compilé avec |
| l'option "STATTIME". Il s'agit principalement de données brutes n'ayant |
| d'utilité que lors de benchmarks par exemple. |
| |
| |
| ============================ |
| | Fichier de configuration | |
| ============================ |
| |
| Structure |
| ========= |
| |
| L'analyseur du fichier de configuration ignore des lignes vides, les espaces, |
| les tabulations, et tout ce qui est compris entre le symbole '#' (s'il n'est pas |
| précédé d'un '\'), et la fin de la ligne, ce qui constitue un commentaire. |
| |
| Le fichier de configuration est découpé en sections répérées par des mots clés |
| tels que : |
| |
| - 'global' |
| - 'listen' |
| - 'defaults' |
| |
| Tous les paramètres font référence à la section définie par le dernier mot clé |
| reconnu. |
| |
| |
| 1) Paramètres globaux |
| ===================== |
| |
| Il s'agit des paramètres agissant sur le processus, ou bien sur l'ensemble des |
| proxies. Ils sont tous spécifiés dans la section 'global'. Les paramètres |
| supportés sont : |
| |
| - log <adresse> <catégorie> [niveau_max] |
| - maxconn <nombre> |
| - uid <identifiant> |
| - gid <identifiant> |
| - chroot <répertoire> |
| - nbproc <nombre> |
| - daemon |
| - debug |
| - quiet |
| - pidfile <fichier> |
| |
| 1.1) Journalisation des événements |
| ---------------------------------- |
| La plupart des événements sont journalisés : démarrages, arrêts, disparition et |
| apparition de serveurs, connexions, erreurs. Tous les messages sont envoyés en |
| syslog vers un ou deux serveurs. La syntaxe est la suivante : |
| |
| log <adresse_ip> <catégorie> [niveau_max] |
| |
| Les connexions sont envoyées en niveau "info". Les démarrages de service et de |
| serveurs seront envoyés en "notice", les signaux d'arrêts en "warning" et les |
| arrêts définitifs de services et de serveurs en "alert". Ceci est valable aussi |
| bien pour les proxies que pour les serveurs testés par les proxies. Le paramètre |
| optionnel <niveau_max> définit le niveau maximal de traces émises parmi les 8 |
| valeurs suivantes : |
| emerg, alert, crit, err, warning, notice, info, debug |
| |
| Par compatibilité avec les versions 1.1.16 et antérieures, la valeur par défaut |
| est "debug" si l'option n'est pas précisée. |
| |
| Les catégories possibles sont : |
| kern, user, mail, daemon, auth, syslog, lpr, news, |
| uucp, cron, auth2, ftp, ntp, audit, alert, cron2, |
| local0, local1, local2, local3, local4, local5, local6, local7 |
| |
| Conformément à la RFC3164, les messages émis sont limités à 1024 caractères. |
| |
| Exemple : |
| --------- |
| global |
| log 192.168.2.200 local3 |
| log 127.0.0.1 local4 notice |
| |
| 1.2) limitation du nombre de connexions |
| --------------------------------------- |
| Il est possible et conseillé de limiter le nombre global de connexions par |
| processus. Les connexions sont comprises au sens 'acceptation de connexion', |
| donc il faut s'attendre en règle général à avoir un peu plus du double de |
| sessions TCP que le maximum de connexions fixé. C'est important pour fixer le |
| paramètre 'ulimit -n' avant de lancer le proxy. Pour comptabiliser le nombre |
| de sockets nécessaires, il faut prendre en compte ces paramètres : |
| - 1 socket par connexion entrante |
| - 1 socket par connexion sortante |
| - 1 socket par couple adresse/port d'écoute par proxy |
| - 1 socket pour chaque serveur en cours de health-check |
| - 1 socket pour les logs (tous serveurs confondus) |
| |
| Dans le cas où chaque proxy n'écoute que sur un couple adresse/port, positionner |
| la limite du nombre de descripteurs de fichiers (ulimit -n) à |
| (2 * maxconn + nbproxy + nbserveurs + 1). Dans une future version, haproxy sera |
| capable de positionner lui-même cette limite. |
| |
| 1.3) Diminution des privilèges |
| ------------------------------ |
| Afin de réduire les risques d'attaques dans le cas où une faille non identifiée |
| serait exploitée, il est possible de diminuer les privilèges du processus, et |
| de l'isoler dans un répertoire sans risque. |
| |
| Dans la section 'global', le paramètre 'uid' permet de spécifier un identifiant |
| numérique d'utilisateur. La valeur 0, correspondant normalement au super- |
| utilisateur, possède ici une signification particulière car elle indique que |
| l'on ne souhaite pas changer cet identifiant et conserver la valeur courante. |
| C'est la valeur par défaut. De la même manière, le paramètre 'gid' correspond à |
| un identifiant de groupe, et utilise par défaut la valeur 0 pour ne rien |
| changer. Il est particulièrement déconseillé d'utiliser des comptes génériques |
| tels que 'nobody' car cette pratique revient à utiliser 'root' si d'autres |
| processus utilisent les mêmes identifiants. |
| |
| Le paramètre 'chroot' autorise à changer la racine du processus une fois le |
| programme lancé, de sorte que ni le processus, ni l'un de ses descendants ne |
| puissent remonter de nouveau à la racine. Ce type de cloisonnement (chroot) est |
| généralement contournable sur certains OS (Linux, Solaris) pour peu que |
| l'attaquant possède des droits 'root' et soit en mesure d'utiliser ou de créer |
| un répertoire. Aussi, il est important d'utiliser un répertoire spécifique au |
| service pour cet usage, et de ne pas mutualiser un même répertoire pour |
| plusieurs services de nature différente. Pour rendre l'isolement plus robuste, |
| il est conseillé d'utiliser un répertoire vide, sans aucun droit, et de changer |
| l'uid du processus de sorte qu'il ne puisse rien faire dans ledit répertoire. |
| |
| Remarque: dans le cas où une telle faille serait mise en évidence, il est fort |
| probable que les premières tentatives de son exploitation provoquent un arrêt du |
| programme, à cause d'un signal de type 'Segmentation Fault', 'Bus Error' ou |
| encore 'Illegal Instruction'. Même s'il est vrai que faire tourner le serveur en |
| environnement limité réduit les risques d'intrusion, il est parfois bien utile |
| dans ces circonstances de connaître les conditions d'apparition du problème, via |
| l'obtention d'un fichier 'core'. La plupart des systèmes, pour des raisons de |
| sécurité, désactivent la génération du fichier 'core' après un changement |
| d'identifiant pour le processus. Il faudra donc soit lancer le processus à |
| partir d'un compte utilisateur aux droits réduits (mais ne pouvant pas effectuer |
| le chroot), ou bien le faire en root sans réduction des droits (uid 0). Dans ce |
| cas, le fichier se trouvera soit dans le répertoire de lancement, soit dans le |
| répertoire spécifié après l'option 'chroot'. Ne pas oublier la commande suivante |
| pour autoriser la génération du fichier avant de lancer le programme : |
| |
| # ulimit -c unlimited |
| |
| Exemple : |
| --------- |
| |
| global |
| uid 30000 |
| gid 30000 |
| chroot /var/chroot/haproxy |
| |
| 1.4) Modes de fonctionnement |
| ---------------------------- |
| Le service peut fonctionner dans plusieurs modes : |
| - avant- / arrière-plan |
| - silencieux / normal / debug |
| |
| Le mode par défaut est normal, avant-plan, c'est à dire que le programme ne rend |
| pas la main une fois lancé. Il ne faut surtout pas le lancer comme ceci dans un |
| script de démarrage du système, sinon le système ne finirait pas son |
| initialisation. Il faut le mettre en arrière-plan, de sorte qu'il rende la main |
| au processus appelant. C'est ce que fait l'option 'daemon' de la section |
| 'global', et qui est l'équivalent du paramètre '-D' de la ligne de commande. |
| |
| Par ailleurs, certains messages d'alerte sont toujours envoyés sur la sortie |
| standard, même en mode 'daemon'. Pour ne plus les voir ailleurs que dans les |
| logs, il suffit de passer en mode silencieux par l'ajout de l'option 'quiet'. |
| Cette option n'a pas d'équivalent en ligne de commande. |
| |
| Enfin, le mode 'debug' permet de diagnostiquer les origines de certains |
| problèmes en affichant les connexions, déconnexions et échanges d'en-têtes HTTP |
| entre les clients et les serveurs. Ce mode est incompatible avec les options |
| 'daemon' et 'quiet' pour des raisons de bon sens. |
| |
| 1.5) Accroissement de la capacité de traitement |
| ----------------------------------------------- |
| Sur des machines multi-processeurs, il peut sembler gâché de n'utiliser qu'un |
| processeur pour effectuer les tâches de relayage, même si les charges |
| nécessaires à saturer un processeur actuel sont bien au-delà des ordres de |
| grandeur couramment rencontrés. Cependant, pour des besoins particuliers, le |
| programme sait démarrer plusieurs processus se répartissant la charge de |
| travail. Ce nombre de processus est spécifié par le paramètre 'nbproc' de la |
| section 'global'. Sa valeur par défaut est naturellement 1. Ceci ne fonctionne |
| qu'en mode 'daemon'. |
| |
| Exemple : |
| --------- |
| |
| global |
| daemon |
| quiet |
| nbproc 2 |
| |
| 1.6) Simplification de la gestion des processus |
| ----------------------------------------------- |
| Haproxy supporte dorénavant la notion de fichiers de pid (-> pidfiles). Si le |
| paramètre '-p' de ligne de commande, ou l'option globale 'pidfile' sont suivis |
| d'un nom de fichier, alors ce fichier sera supprimé puis recréé et contiendra |
| le numéro de PID des processus fils, à raison d'un par ligne (valable |
| uniquement en mode démon). Ce fichier n'est PAS relatif au cloisonnement chroot |
| afin de rester compatible avec un répertoire protégé en lecture seule. Il |
| appartiendra à l'utilisateur ayant lancé le processus, et disposera des droits |
| 0644. |
| |
| Exemple : |
| --------- |
| |
| global |
| daemon |
| quiet |
| nbproc 2 |
| pidfile /var/run/haproxy-private.pid |
| |
| # pour stopper seulement ces processus parmi d'autres : |
| # kill $(</var/run/haproxy-private.pid) |
| |
| |
| 2) Définition d'un service en écoute |
| ==================================== |
| |
| Les sections de service débutent par le mot clé "listen" : |
| |
| listen <nom_instance> [ <adresse_IP>:<plage_ports>[,...] ] |
| |
| - <nom_instance> est le nom de l'instance décrite. Ce nom sera envoyé dans les |
| logs, donc il est souhaitable d'utiliser un nom relatif au service relayé. Aucun |
| test n'est effectué concernant l'unicité de ce nom, qui n'est pas obligatoire, |
| mais fortement recommandée. |
| |
| - <adresse_IP> est l'adresse IP sur laquelle le relais attend ses connexions. |
| L'absence d'adresse ainsi que l'adresse 0.0.0.0 signifient que les connexions |
| pourront s'effectuer sur toutes les adresses de la machine. |
| |
| - <plage_ports> correspond soit à un port, soit à une plage de ports sur |
| lesquels le relais acceptera des connexions pour l'adresse IP spécifiée. |
| Cette plage peut être : |
| - soit un port numérique (ex: '80') |
| - soit une plage constituée de deux valeurs séparées par un tiret |
| (ex: '2000-2100') représentant les extrémités incluses dans la |
| plage. |
| Il faut faire attention à l'usage des plages, car chaque combinaison |
| <adresse_IP>:<port> consomme une socket, donc un descripteur de fichier. |
| Le couple <adresse_IP>:<port> doit être unique pour toutes les instances |
| d'une même machine. L'attachement à un port inférieur à 1024 nécessite un |
| niveau de privilège particulier lors du lancement du programme (indépendamment |
| du paramètre 'uid' de la section 'global'). |
| |
| - le couple <adresse_IP>:<plage_ports> peut être répété indéfiniment pour |
| demander au relais d'écouter également sur d'autres adresses et/ou d'autres |
| plages de ports. Pour cela, il suffit de séparer les couples par une virgule. |
| |
| Exemples : |
| --------- |
| listen http_proxy :80 |
| listen x11_proxy 127.0.0.1:6000-6009 |
| listen smtp_proxy 127.0.0.1:25,127.0.0.1:587 |
| listen ldap_proxy :389,:663 |
| |
| Si toutes les adresses ne tiennent pas sur une ligne, il est possible d'en |
| rajouter à l'aide du mot clé 'bind'. Dans ce cas, il n'est même pas nécessaire |
| de spécifier la première adresse sur la ligne listen, ce qui facilite parfois |
| l'écriture de configurations : |
| |
| bind [ <adresse_IP>:<plage_ports>[,...] ] |
| |
| Exemples : |
| ---------- |
| listen http_proxy |
| bind :80,:443 |
| bind 10.0.0.1:10080,10.0.0.1:10443 |
| |
| 2.1) Inhibition d'un service |
| ---------------------------- |
| Un service peut être désactivé pour des besoins de maintenance, sans avoir à |
| commenter toute une partie du fichier. Il suffit de positionner le mot clé |
| "disabled" dans sa section : |
| |
| listen smtp_proxy 0.0.0.0:25 |
| disabled |
| |
| Remarque: le mot clé 'enabled' permet de réactiver un service préalablement |
| désactivé par le mot clé 'disabled', par exemple à cause d'une |
| configuration par défaut. |
| |
| 2.2) Mode de fonctionnement |
| --------------------------- |
| Un service peut fonctionner dans trois modes différents : |
| - TCP |
| - HTTP |
| - supervision |
| |
| Mode TCP |
| -------- |
| Dans ce mode, le service relaye, dès leur établissement, les connexions TCP vers |
| un ou plusieurs serveurs. Aucun traitement n'est effectué sur le flux. Il s'agit |
| simplement d'une association source<adresse:port> -> destination<adresse:port>. |
| Pour l'utiliser, préciser le mode TCP sous la déclaration du relais. |
| |
| Exemple : |
| --------- |
| listen smtp_proxy 0.0.0.0:25 |
| mode tcp |
| |
| Mode HTTP |
| --------- |
| Dans ce mode, le service relaye les connexions TCP vers un ou plusieurs |
| serveurs, une fois qu'il dispose d'assez d'informations pour en prendre la |
| décision. Les entêtes HTTP sont analysés pour y trouver un éventuel cookie, et |
| certains d'entre-eux peuvent être modifiés par le biais d'expressions |
| régulières. Pour activer ce mode, préciser le mode HTTP sous la déclaration du |
| relais. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| |
| Mode supervision |
| ---------------- |
| Il s'agit d'un mode offrant à un composant externe une visibilité de l'état de |
| santé du service. Il se contente de retourner "OK" à tout client se connectant |
| sur son port. Il peut être utilisé avec des répartiteurs de charge évolués pour |
| déterminer quels sont les services utilisables. Si l'option 'httpchk' est |
| activée, alors la réponse changera en 'HTTP/1.0 200 OK' pour satisfaire les |
| attentes de composants sachant tester en HTTP. Pour activer ce mode, préciser |
| le mode HEALTH sous la déclaration du relais. |
| |
| Exemple : |
| --------- |
| # réponse simple : 'OK' |
| listen health_check 0.0.0.0:60000 |
| mode health |
| |
| # réponse HTTP : 'HTTP/1.0 200 OK' |
| listen http_health_check 0.0.0.0:60001 |
| mode health |
| option httpchk |
| |
| |
| 2.3) Limitation du nombre de connexions simultanées |
| --------------------------------------------------- |
| Le paramètre "maxconn" permet de fixer la limite acceptable en nombre de |
| connexions simultanées par proxy. Chaque proxy qui atteint cette valeur cesse |
| d'écouter jusqu'à libération d'une connexion. Voir plus loin concernant les |
| limitations liées au système. |
| |
| Exemple : |
| --------- |
| listen tiny_server 0.0.0.0:80 |
| maxconn 10 |
| |
| |
| 2.4) Arrêt en douceur |
| --------------------- |
| Il est possible d'arrêter les services en douceur en envoyant un signal SIG_USR1 |
| au processus relais. Tous les services seront alors mis en phase d'arrêt, mais |
| pourront continuer d'accepter des connexions pendant un temps défini par le |
| paramètre 'grace' (en millisecondes). Cela permet par exemple, de faire savoir |
| rapidement à un répartiteur de charge qu'il ne doit plus utiliser un relais, |
| tout en continuant d'assurer le service le temps qu'il s'en rende compte. |
| Remarque : les connexions actives ne sont jamais cassées. Dans le pire des cas, |
| il faudra attendre en plus leur expiration avant l'arrêt total du processus. La |
| valeur par défaut est 0 (pas de grâce, arrêt immédiat de l'écoute). |
| |
| Exemple : |
| --------- |
| # arrêter en douceur par 'killall -USR1 haproxy' |
| # le service tournera encore 10 secondes après la demande d'arrêt |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| grace 10000 |
| |
| # ce port n'est testé que par un répartiteur de charge. |
| listen health_check 0.0.0.0:60000 |
| mode health |
| grace 0 |
| |
| |
| 2.5) Temps d'expiration des connexions |
| -------------------------------------- |
| Il est possible de paramétrer certaines durées d'expiration au niveau des |
| connexions TCP. Trois temps indépendants sont configurables et acceptent des |
| valeurs en millisecondes. Si l'une de ces trois temporisations est dépassée, la |
| session est terminée à chaque extrémité. |
| |
| - temps d'attente d'une donnée de la part du client, ou de la |
| possibilité de lui envoyer des données : "clitimeout" : |
| |
| # time-out client à 2mn30. |
| clitimeout 150000 |
| |
| - temps d'attente d'une donnée de la part du serveur, ou de la |
| possibilité de lui envoyer des données : "srvtimeout" : |
| |
| # time-out serveur à 30s. |
| srvtimeout 30000 |
| |
| - temps d'attente de l'établissement d'une connexion vers un serveur |
| "contimeout" : |
| |
| # on abandonne si la connexion n'est pas établie après 4 secondes |
| contimeout 4000 |
| |
| Remarques : |
| ----------- |
| - "contimeout" et "srvtimeout" n'ont pas d'utilité dans le cas du serveur de |
| type "health". |
| - sous de fortes charges, ou sur un réseau saturé ou défectueux, il est |
| possible de perdre des paquets. Du fait que la première retransmission TCP |
| n'ait lieu qu'au bout de 3 secoudes, fixer un timeout de connexion inférieur |
| à 3 secondes ne permet pas de se rattraper sur la perte de paquets car la |
| session aura été abandonnée avant la première retransmission. Une valeur de |
| 4 secondes réduira considérablement le nombre d'échecs de connexion. |
| |
| 2.6) Tentatives de reconnexion |
| ------------------------------ |
| Lors d'un échec de connexion vers un serveur, il est possible de |
| retenter (potentiellement vers un autre serveur, en cas de répartition |
| de charge). Le nombre de nouvelles tentatives infructueuses avant |
| abandon est fourni par le paramètre "retries". |
| |
| Exemple : |
| --------- |
| # on essaie encore trois fois maxi |
| retries 3 |
| |
| |
| 2.7) Adresse du serveur |
| ----------------------- |
| Le serveur vers lequel sont redirigées les nouvelles connexions est défini par |
| le paramètre "dispatch" sous la forme <adresse_ip>:<port>. Il correspond à un |
| serveur d'assignation de cookie dans le cas où le service consiste à assurer |
| uniquement une persistence HTTP, ou bien simplement au serveur destination dans |
| le cas de relayage TCP simple. Cet ancien mode ne permet pas de tester l'état |
| du serveur distant, et il est maintenant recommandé d'utiliser de préférence |
| le mode 'balance'. |
| |
| Exemple : |
| --------- |
| # on envoie toutes les nouvelles connexions ici |
| dispatch 192.168.1.2:80 |
| |
| Remarque : |
| ---------- |
| Ce paramètre n'a pas d'utilité pour un serveur en mode 'health', ni en mode |
| 'balance'. |
| |
| |
| 2.8) Adresse de sortie |
| ---------------------- |
| Il est possible de forcer l'adresse utilisée pour établir les connexions vers |
| les serveurs à l'aide du paramètre "source". Il est même possible de forcer le |
| port, bien que cette fonctionnalité se limite à des usages très spécifiques. |
| C'est particulièrement utile en cas d'adressage multiple, et plus généralement |
| pour permettre aux serveurs de trouver le chemin de retour dans des contextes de |
| routage difficiles. Si l'adresse est '0.0.0.0' ou '*' ou vide, elle sera choisie |
| librement par le systeme. Si le port est '0' ou vide, il sera choisi librement |
| par le système. Il est à noter que depuis la version 1.1.18, les tests de bon |
| fonctionnement des serveurs seront aussi effectués à partir de la source |
| spécifiée par ce paramètre. |
| |
| Exemples : |
| ---------- |
| listen http_proxy *:80 |
| # toutes les connexions prennent l'adresse 192.168.1.200 |
| source 192.168.1.200:0 |
| |
| listen rlogin_proxy *:513 |
| # utiliser l'adresse 192.168.1.200 et le port réservé 900 |
| source 192.168.1.200:900 |
| |
| |
| 2.9) Définition du nom du cookie |
| -------------------------------- |
| En mode HTTP, il est possible de rechercher la valeur d'un cookie pour savoir |
| vers quel serveur aiguiller la requête utilisateur. Le nom du cookie est donné |
| par le paramètre "cookie". |
| |
| Exemple : |
| --------- |
| listen http_proxy :80 |
| mode http |
| cookie SERVERID |
| |
| On peut modifier l'utilisation du cookie pour la rendre plus intelligente |
| vis-à-vis des applications relayées. Il est possible, notamment de supprimer ou |
| réécrire un cookie retourné par un serveur accédé en direct, et d'insérer un |
| cookie dans une réponse HTTP adressée à un serveur sélectionné en répartition |
| de charge, et même de signaler aux proxies amont de ne pas cacher le cookie |
| inséré. |
| |
| Exemples : |
| ---------- |
| |
| Pour ne conserver le cookie qu'en accès indirect, donc à travers le |
| dispatcheur, et supprimer toutes ses éventuelles occurences lors des accès |
| directs : |
| |
| cookie SERVERID indirect |
| |
| Pour remplacer la valeur d'un cookie existant par celle attribuée à un serveur, |
| lors d'un accès direct : |
| |
| cookie SERVERID rewrite |
| |
| Pour créer un cookie comportant la valeur attribuée à un serveur lors d'un accès |
| en répartition de charge interne. Dans ce cas, il est souhaitable que tous les |
| serveurs aient un cookie renseigné. Un serveur non assigné d'un cookie |
| retournera un cookie vide (cookie de suppression) : |
| |
| cookie SERVERID insert |
| |
| Pour insérer un cookie, en s'assurant qu'un cache en amont ne le stockera pas, |
| ajouter le mot clé 'nocache' après 'insert' : |
| |
| cookie SERVERID insert nocache |
| |
| Pour insérer un cookie seulement suite aux requêtes de type POST, ajouter le mot |
| clé 'postonly' après 'insert' : |
| |
| cookie SERVERID insert postonly |
| |
| |
| Remarques : |
| ----------- |
| - Il est possible de combiner 'insert' avec 'indirect' ou 'rewrite' pour s'adapter |
| à des applications générant déjà le cookie, avec un contenu invalide. Il suffit |
| pour cela de les spécifier sur la même ligne. |
| |
| - dans le cas où 'insert' et 'indirect' sont spécifiés, le cookie n'est jamais |
| transmis au serveur vu qu'il n'en a pas connaissance et ne pourrait pas le |
| comprendre. |
| |
| - il est particulièrement recommandé d'utiliser 'nocache' en mode insertion si |
| des caches peuvent se trouver entre les clients et l'instance du proxy. Dans |
| le cas contraire, un cache HTTP 1.0 pourrait cacher la réponse, incluant le |
| cookie de persistence inséré, donc provoquer des changements de serveurs pour |
| des clients partageant le même cache. |
| |
| - lorsque l'application est bien connue, et que les parties nécessitant de la |
| persistence sont systématiquement accédées par un formulaire en mode POST, |
| il est plus efficace encore de combiner le mot clé "postonly" avec "insert" |
| et "indirect", car la page d'accueil reste cachable, et c'est l'application |
| qui gère le 'cache-control'. |
| |
| 2.10) Assignation d'un serveur à une valeur de cookie |
| ---------------------------------------------------- |
| En mode HTTP, il est possible d'associer des valeurs de cookie à des serveurs |
| par le paramètre 'server'. La syntaxe est : |
| |
| server <identifiant> <adresse_ip>:<port> cookie <valeur> |
| |
| - <identifiant> est un nom quelconque de serveur utilisé pour l'identifier dans la |
| configuration et les logs. |
| - <adresse_ip>:<port> est le couple adresse-port sur lequel le serveur écoute. |
| - <valeur> est la valeur à reconnaître ou positionner dans le cookie. |
| |
| Exemple : le cookie SERVERID peut contenir server01 ou server02 |
| --------- |
| listen http_proxy :80 |
| mode http |
| cookie SERVERID |
| dispatch 192.168.1.100:80 |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| |
| Attention : la syntaxe a changé depuis la version 1.0. |
| ----------- |
| |
| 3) Répartiteur de charge autonome |
| ================================= |
| |
| Le relais peut effectuer lui-même la répartition de charge entre les différents |
| serveurs définis pour un service donné, en mode TCP comme en mode HTTP. Pour |
| cela, on précise le mot clé 'balance' dans la définition du service, |
| éventuellement suivi du nom d'un algorithme de répartition. En version 1.1.9, |
| seul 'roundrobin' est géré, et c'est aussi la valeur implicite par défaut. Il |
| est évident qu'en cas d'utilisation du répartiteur interne, il ne faudra pas |
| spécifier d'adresse de dispatch, et qu'il faudra au moins un serveur. |
| |
| Exemple : même que précédemment en répartition interne |
| --------- |
| |
| listen http_proxy :80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| |
| Depuis la version 1.1.22, il est possible de déterminer automatiquement le port |
| du serveur vers lequel sera envoyée la connexion, en fonction du port d'écoute |
| sur lequel le client s'est connecté. En effet, il y a 4 possibilités pour le |
| champ <port> de l'adresse serveur : |
| |
| - non spécifié ou nul : |
| la connexion sera envoyée au serveur sur le même port que celui sur |
| lequel le relais a reçu la connexion. |
| |
| - valeur numérique (seul cas supporté pour les versions antérieures) : |
| le serveur recevra la connexion sur le port désigné. |
| |
| - valeur numérique précédée d'un signe '+' : |
| la connexion sera envoyée au serveur sur le même port que celui sur |
| lequel le relais a reçu la connexion, auquel on ajoute la valeur désignée. |
| |
| - valeur numérique précédée d'un signe '-' : |
| la connexion sera envoyée au serveur sur le même port que celui sur |
| lequel le relais a reçu la connexion, duquel on soustrait la valeur |
| désignée. |
| |
| Exemples : |
| ---------- |
| |
| # même que précédemment |
| |
| listen http_proxy :80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| server web1 192.168.1.1 cookie server01 |
| server web2 192.168.1.2 cookie server02 |
| |
| # relayage simultané des ports 80 et 81 et 8080-8089 |
| |
| listen http_proxy :80,:81,:8080-8089 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| server web1 192.168.1.1 cookie server01 |
| server web2 192.168.1.2 cookie server02 |
| |
| # relayage TCP des ports 25, 389 et 663 vers les ports 1025, 1389 et 1663 |
| |
| listen http_proxy :25,:389,:663 |
| mode tcp |
| balance roundrobin |
| server srv1 192.168.1.1:+1000 |
| server srv2 192.168.1.2:+1000 |
| |
| |
| 3.1) Surveillance des serveurs |
| ------------------------------ |
| Il est possible de tester l'état des serveurs par établissement de connexion TCP |
| ou par envoi d'une requête HTTP. Un serveur hors d'usage ne sera pas utilisé |
| dans le processus de répartition de charge interne. Pour activer la surveillance, |
| ajouter le mot clé 'check' à la fin de la déclaration du serveur. Il est |
| possible de spécifier l'intervalle (en millisecondes) séparant deux tests du |
| serveur par le paramètre "inter", le nombre d'échecs acceptés par le paramètre |
| "fall", et le nombre de succès avant reprise par le paramètre "rise". Les |
| paramètres non précisés prennent les valeurs suivantes par défaut : |
| - inter : 2000 |
| - rise : 2 |
| - fall : 3 |
| - port : port de connexion du serveur |
| |
| Le mode par défaut consiste à établir des connexions TCP uniquement. Dans |
| certains cas de pannes, des serveurs peuvent continuer à accepter les connexions |
| sans les traiter. Depuis la version 1.1.16, haproxy est en mesure d'envoyer des |
| requêtes HTTP courtes et très peu coûteuses. Les versions 1.1.16 et 1.1.17 |
| utilisent "OPTIONS / HTTP/1.0". Dans les versions 1.1.18 à 1.1.20, les requêtes |
| ont été changées en "OPTIONS * HTTP/1.0" pour des raisons de contrôle d'accès aux |
| ressources. Cependant, cette requête documentée dans la RFC2068 n'est pas |
| comprise par tous les serveurs. Donc à partir de la version 1.1.21, la requête |
| par défaut est revenue à "OPTIONS / HTTP/1.0", mais il est possible de |
| paramétrer la partie URI. Les requêtes OPTIONS présentent l'avantage d'être |
| facilement extractibles des logs, et de ne pas induire d'accès aux fichiers côté |
| serveur. Seules les réponses 2xx et 3xx sont considérées valides, les autres (y |
| compris non-réponses) aboutissent à un échec. Le temps maximal imparti pour une |
| réponse est égal à l'intervalle entre deux tests (paramètre "inter"). Pour |
| activer ce mode, spécifier l'option "httpchk", éventuellement suivie d'une |
| méthode et d'une URI. L'option "httpchk" accepte donc 4 formes : |
| - option httpchk -> OPTIONS / HTTP/1.0 |
| - option httpchk URI -> OPTIONS <URI> HTTP/1.0 |
| - option httpchk METH URI -> <METH> <URI> HTTP/1.0 |
| - option httpchk METH URI VER -> <METH> <URI> <VER> |
| Voir les exemples ci-après. |
| |
| Depuis la version 1.1.17, il est possible de définir des serveurs de secours, |
| utilisés uniquement lorsqu'aucun des autres serveurs ne fonctionne. Pour cela, |
| ajouter le mot clé "backup" sur la ligne de définition du serveur. Un serveur |
| de secours n'est appelé que lorsque tous les serveurs normaux, ainsi que tous |
| les serveurs de secours qui le précèdent sont hors d'usage. Il n'y a donc pas |
| de répartition de charge entre des serveurs de secours. Ce type de serveurs |
| peut servir à retourner des pages d'indisponibilité de service. Dans ce cas, |
| il est préférable de ne pas affecter de cookie, afin que les clients qui le |
| rencontrent n'y soient pas affectés définitivement. Le fait de ne pas mettre |
| de cookie envoie un cookie vide, ce qui a pour effet de supprimer un éventuel |
| cookie affecté précédemment. |
| |
| Depuis la version 1.1.22, il est possible d'envoyer les tests de fonctionnement |
| vers un port différent de celui de service. C'est nécessaire principalement |
| pour les configurations où le serveur n'a pas de port prédéfini, par exemple |
| lorsqu'il est déduit du port d'acceptation de la connexion. Pour cela, utiliser |
| le paramètre 'port' suivi du numéro de port devant répondre aux requêtes. |
| |
| Enfin, depuis la version 1.1.17, il est possible de visualiser rapidement l'état |
| courant de tous les serveurs. Pour cela, il suffit d'envoyer un signal SIGHUP au |
| processus proxy. L'état de tous les serveurs de tous les proxies est envoyé dans |
| les logs en niveau "notice", ainsi que sur la sortie d'erreurs si elle est |
| active. C'est une bonne raison pour avoir au moins un serveur de logs local en |
| niveau notice. |
| |
| Exemples : |
| ---------- |
| # conf du paragraphe 3) avec surveillance TCP |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 |
| |
| # même que précédemment avec surveillance HTTP par 'OPTIONS / HTTP/1.0' |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| option httpchk |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 |
| |
| # même que précédemment avec surveillance HTTP par 'OPTIONS /index.html HTTP/1.0' |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| option httpchk /index.html |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 |
| |
| # idem avec surveillance HTTP par 'HEAD /index.jsp? HTTP/1.1\r\nHost: www' |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| option httpchk HEAD /index.jsp? HTTP/1.1\r\nHost:\ www |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check inter 500 rise 1 fall 2 |
| |
| # Insertion automatique de cookie dans la réponse du serveur, et suppression |
| # automatique dans la requête, tout en indiquant aux caches de ne pas garder |
| # ce cookie. |
| listen web_appl 0.0.0.0:80 |
| mode http |
| cookie SERVERID insert nocache indirect |
| balance roundrobin |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check |
| |
| # idem avec serveur applicatif de secours sur autre site, et serveur de pages d'erreurs |
| listen web_appl 0.0.0.0:80 |
| mode http |
| cookie SERVERID insert nocache indirect |
| balance roundrobin |
| server web1 192.168.1.1:80 cookie server01 check |
| server web2 192.168.1.2:80 cookie server02 check |
| server web-backup 192.168.2.1:80 cookie server03 check backup |
| server web-excuse 192.168.3.1:80 check backup |
| |
| # relayage SMTP+TLS avec test du serveur et serveur de backup |
| |
| listen http_proxy :25,:587 |
| mode tcp |
| balance roundrobin |
| server srv1 192.168.1.1 check port 25 inter 30000 rise 1 fall 2 |
| server srv2 192.168.1.2 backup |
| |
| |
| 3.2) Reconnexion vers un répartiteur en cas d'échec direct |
| ---------------------------------------------------------- |
| En mode HTTP, si un serveur défini par un cookie ne répond plus, les clients |
| seront définitivement aiguillés dessus à cause de leur cookie, et de ce fait, |
| définitivement privés de service. La spécification du paramètre 'redispatch' |
| autorise dans ce cas à renvoyer les connexions échouées vers le répartiteur |
| (externe ou interne) afin d'assigner un nouveau serveur à ces clients. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| dispatch 192.168.1.100:80 |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| redispatch # renvoyer vers dispatch si refus de connexion. |
| |
| Par défaut (et dans les versions 1.1.16 et antérieures), le paramètre redispatch |
| ne s'applique qu'aux échecs de connexion au serveur. Depuis la version 1.1.17, |
| il s'applique aussi aux connexions destinées à des serveurs identifiés comme |
| hors d'usage par la surveillance. Si l'on souhaite malgré tout qu'un client |
| disposant d'un cookie correspondant à un serveur défectueux tente de s'y |
| connecter, il faut préciser l'option "persist" : |
| |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| option persist |
| cookie SERVERID |
| dispatch 192.168.1.100:80 |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| redispatch # renvoyer vers dispatch si serveur HS. |
| |
| |
| 4) Fonctionnalités additionnelles |
| ================================= |
| |
| D'autres fonctionnalités d'usage moins courant sont disponibles. Il s'agit |
| principalement du mode transparent, de la journalisation des connexions, et de |
| la réécriture des entêtes. |
| |
| 4.1) Fonctionnement en mode transparent |
| --------------------------------------- |
| En mode HTTP, le mot clé 'transparent' permet d'intercepter des sessions routées |
| à travers la machine hébergeant le proxy. Dans ce mode, on ne précise pas |
| l'adresse de répartition 'dispatch', car celle-ci est tirée de l'adresse |
| destination de la session détournée. Le système doit permettre de rediriger les |
| paquets vers un processus local. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:65000 |
| mode http |
| transparent |
| cookie SERVERID |
| server server01 192.168.1.1:80 |
| server server02 192.168.1.2:80 |
| |
| # iptables -t nat -A PREROUTING -i eth0 -p tcp -d 192.168.1.100 \ |
| --dport 80 -j REDIRECT --to-ports 65000 |
| |
| Remarque : |
| ---------- |
| Si le port n'est pas spécifié sur le serveur, c'est le port auquel s'est adressé |
| le client qui sera utilisé. Cela permet de relayer tous les ports TCP d'une même |
| adresse avec une même instance et sans utiliser directement le mode transparent. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:65000 |
| mode tcp |
| server server01 192.168.1.1 check port 60000 |
| server server02 192.168.1.2 check port 60000 |
| |
| # iptables -t nat -A PREROUTING -i eth0 -p tcp -d 192.168.1.100 \ |
| -j REDIRECT --to-ports 65000 |
| |
| |
| 4.2) Journalisation des connexions |
| ---------------------------------- |
| 4.2.1) Niveaux de log |
| --------------------- |
| Les connexions TCP et HTTP peuvent donner lieu à une journalisation sommaire ou |
| détaillée indiquant, pour chaque connexion, la date, l'heure, l'adresse IP |
| source, le serveur destination, la durée de la connexion, les temps de réponse, |
| la requête HTTP, le code de retour, la quantité de données transmises, et même |
| dans certains cas, la valeur d'un cookie permettant de suivre les sessions. |
| Tous les messages sont envoyés en syslog vers un ou deux serveurs. Se référer à |
| la section 1.1 pour plus d'information sur les catégories de logs. La syntaxe |
| est la suivante : |
| |
| log <adresse_ip_1> <catégorie_1> [niveau_max_1] |
| log <adresse_ip_2> <catégorie_2> [niveau_max_2] |
| ou |
| log global |
| |
| Remarque : |
| ---------- |
| La syntaxe spécifique 'log global' indique que l'on souhaite utiliser les |
| paramètres de journalisation définis dans la section 'global'. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| log 192.168.2.200 local3 |
| log 192.168.2.201 local4 |
| |
| 4.2.2) Format des logs |
| ---------------------- |
| Par défaut, les connexions sont journalisées au niveau TCP dès l'établissement |
| de la session entre le client et le relais. En précisant l'option 'tcplog', |
| la connexion ne sera journalisée qu'en fin de session, ajoutant des précisions |
| sur son état lors de la déconnexion, ainsi que le temps de connexion et la |
| durée totale de la session. |
| |
| Une autre option, 'httplog', fournit plus de détails sur le protocole HTTP, |
| notamment la requête et l'état des cookies. Dans les cas où un mécanisme de |
| surveillance effectuant des connexions et déconnexions fréquentes, polluerait |
| les logs, il suffit d'ajouter l'option 'dontlognull', pour ne plus obtenir une |
| ligne de log pour les sessions n'ayant pas donné lieu à un échange de données |
| (requête ou réponse). |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| option httplog |
| option dontlognull |
| log 192.168.2.200 local3 |
| |
| 4.2.3) Chronométrage des événements |
| ----------------------------------- |
| Pour déceler des problèmes réseau, les mesures du temps écoulé entre certains |
| événements sont d'une très grande utilité. Tous les temps sont mesurés en |
| millisecondes (ms). En mode HTTP, quatre points de mesure sont rapportés sous |
| la forme Tq/Tc/Tr/Tt : |
| |
| - Tq: temps total de réception de la requête HTTP de la part du client. |
| C'est le temps qui s'est écoulé entre le moment où le client a établi |
| sa connexion vers le relais, et le moment où ce dernier a reçu le dernier |
| en-tête HTTP validant la fin de la requête. Une valeur '-1' ici indique |
| que la requête complète n'a jamais été reçue. |
| |
| - Tc: temps d'établissement de la connexion TCP du relais vers le serveur. |
| C'est le temps écoulé entre le moment ou le relais a initié la demande de |
| connexion vers le serveur, et le moment où ce dernier l'a acquittée, c'est |
| à dire le temps entre l'envoi du paquet TCP SYN la réception du SYN/ACK. |
| Une valeur '-1' ici indique que la connexion n'a jamais pu être établie |
| vers le serveur. |
| |
| - Tr: temps de réponse du serveur. C'est le temps que le serveur a mis pour |
| renvoyer la totalité des entêtes HTTP à partir du moment où il a acquitté |
| la connexion. Ca représente exactement le temps de traitement de la |
| transaction sans le transfert des données associées. Une valeur '-1' |
| indique que le serveur n'a pas envoyé la totalité de l'entête HTTP. |
| |
| - Tt: durée de vie totale de la session, entre le moment où la demande de |
| connexion du client a été acquittée et le moment où la connexion a été |
| refermée aux deux extrémités (client et serveur). On peut donc en déduire |
| Td, le temps de transfert des données, en excluant les autres temps : |
| |
| Td = Tt - (Tq + Tc + Tr) |
| |
| Les temps rapportés à '-1' sont simplement à éliminer de cette équation. |
| |
| En mode TCP ('option tcplog'), seuls les deux indicateurs Tc et Tt sont |
| rapportés. |
| |
| Ces temps fournissent de précieux renseignement sur des causes probables de |
| problèmes. Du fait que le protocole TCP définisse des temps de retransmission |
| de 3 secondes, puis 6, 12, etc..., l'observation de temps proches de multiples |
| de 3 secondes indique pratiquement toujours des pertes de paquets liés à un |
| problème réseau (câble ou négociation). De plus, si <Tt> est proche d'une |
| valeur de time-out dans la configuration, c'est souvent qu'une session a été |
| abandonnée sur expiration d'un time-out. |
| |
| Cas les plus fréquents : |
| |
| - Si Tq est proche de 3000, un paquet a très certainement été perdu entre |
| le client et le relais. |
| - Si Tc est proche de 3000, un paquet a très certainement été perdu entre |
| le relais et le serveur durant la phase de connexion. Cet indicateur |
| devrait normalement toujours être très bas (moins de quelques dizaines). |
| - Si Tr est presque toujours inférieur à 3000, et que certaines valeurs |
| semblent proches de la valeur moyenne majorée de 3000, il y a peut-être |
| de pertes entre le relais et le serveur. |
| - Si Tt est légèrement supérieur au time-out, c'est souvent parce que le |
| client et le serveur utilisent du keep-alive HTTP entre eux et que la |
| session est maintenue après la fin des échanges. Voir plus loin pour |
| savoir comment désactiver le keep-alive HTTP. |
| |
| Autres cas ('xx' représentant une valeur quelconque à ignorer) : |
| -1/xx/xx/Tt : le client n'a pas envoyé sa requête dans le temps imparti ou |
| a refermé sa connexion sans compléter la requête. |
| Tq/-1/xx/Tt : la connexion n'a pas pu s'établir vers le serveur (refus ou |
| time-out au bout de Tt-Tq ms). |
| Tq/Tc/-1/Tt : le serveur a accepté la connexion mais n'a pas répondu dans |
| les temps ou bien a refermé sa connexion trop tôt, au bout |
| de Tt-(Tq+Tc) ms. |
| |
| 4.2.4) Conditions de déconnexion |
| -------------------------------- |
| Les logs TCP et HTTP fournissent un indicateur de complétude de la session. |
| C'est un champ de 4 caractères (2 en TCP) précédant la requête HTTP, indiquant : |
| - sur le premier caractère, un code précisant le premier événement qui a causé |
| la terminaison de la session : |
| |
| C : fermeture de la session TCP de la part du client |
| S : fermeture de la session TCP de la part du serveur, ou refus de connexion |
| P : terminaison prématurée des sessions par le proxy, pour cas d'erreur |
| interne ou de configuration (ex: filtre d'URL) |
| c : expiration du délai d'attente côté client : clitimeout |
| s : expiration du délai d'attente côté serveur: srvtimeout et contimeout |
| - : terminaison normale. |
| |
| - sur le second caractère, l'état d'avancement de la session HTTP lors de la |
| fermeture : |
| |
| R : terminaison en attendant la réception totale de la requête du client |
| C : terminaison en attendant la connexion vers le serveur |
| H : terminaison en attendant la réception totale des entêtes du serveur |
| D : terminaison durant le transfert des données du serveur vers le client |
| L : terminaison durant le transfert des dernières données du proxy vers |
| le client, alors que le serveur a déjà fini. |
| - : terminaison normale, après fin de transfert des données |
| |
| - le troisième caractère indique l'éventuelle identification d'un cookie de |
| persistence (uniquement en mode HTTP) : |
| |
| N : aucun cookie de persistence n'a été présenté. |
| I : le client a présenté un cookie ne correspondant à aucun serveur |
| connu. |
| D : le client a présenté un cookie correspondant à un serveur hors |
| d'usage. Suivant l'option 'persist', il a été renvoyé vers un |
| autre serveur ou a tout de même tenté de se connecter sur celui |
| correspondant au cookie. |
| V : le client a présenté un cookie valide et a pu se connecter au |
| serveur correspondant. |
| - : non appliquable |
| |
| - le dernier caractère indique l'éventuel traitement effectué sur un cookie de |
| persistence retrourné par le serveur (uniquement en mode HTTP) : |
| |
| N : aucun cookie de persistence n'a été fourni par le serveur. |
| P : un cookie de persistence a été fourni par le serveur et transmis |
| tel quel. |
| I : aucun cookie n'a été fourni par le serveur, il a été inséré par le |
| proxy. |
| D : le cookie présenté par le serveur a été supprimé par le proxy pour |
| ne pas être retourné au client. |
| R : le cookie retourné par le serveur a été modifié par le proxy. |
| - : non appliquable |
| |
| Le mot clé "capture" permet d'ajouter dans des logs HTTP des informations |
| capturées dans les échanges. La version 1.1.17 supporte uniquement une capture |
| de cookies client et serveur, ce qui permet dans bien des cas, de reconstituer |
| la session d'un utilisateur. La syntaxe est la suivante : |
| |
| capture cookie <préfixe_cookie> len <longueur_capture> |
| |
| Le premier cookie dont le nom commencera par <préfixe_cookie> sera capturé, et |
| transmis sous la forme "NOM=valeur", sans toutefois, excéder <longueur_capture> |
| caractères (64 au maximum). Lorsque le nom du cookie est fixe et connu, on peut |
| le suffixer du signe "=" pour s'assurer qu'aucun autre cookie ne prendra sa |
| place dans les logs. |
| |
| Exemples : |
| ---------- |
| # capture du premier cookie dont le nom commence par "ASPSESSION" |
| capture cookie ASPSESSION len 32 |
| |
| # capture du premier cookie dont le nom est exactement "vgnvisitor" |
| capture cookie vgnvisitor= len 32 |
| |
| Dans les logs, le champ précédant l'indicateur de complétude contient le cookie |
| positionné par le serveur, précédé du cookie positionné par le client. Chacun de |
| ces champs est remplacé par le signe "-" lorsqu'aucun cookie n'est fourni par le |
| client ou le serveur. |
| |
| 4.2.5) Exemples de logs |
| ----------------------- |
| - haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 6559/7/147/6723 200 243 - - ---- "HEAD / HTTP/1.0" |
| => requête longue (6.5s) saisie à la main avec un client telnet. Le serveur a |
| répondu en 147 ms et la session s'est terminée normalement ('----') |
| |
| - haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55] relais-http <NOSRV> -1/-1/-1/8490 -1 0 - - CR-- "" |
| => Le client n'a pas envoyé sa requête et a refermé la connexion lui-même |
| ('C---') au bout de 8.5s, alors que le relais attendait l'entête ('-R--'). |
| Aucune connexion n'a été envoyée vers le serveur. |
| |
| - haproxy[18113]: 127.0.0.1:34549 [15/Oct/2003:15:19:06] relais-http <NOSRV> -1/-1/-1/50001 408 0 - - cR-- "" |
| => Le client n'a pas envoyé sa requête et son time-out a expiré ('c---') au |
| bout de 50s, alors que le relais attendait l'entête ('-R--'). Aucune |
| connexion n'a été envoyée vers le serveur, mais le relais a tout de même |
| pu renvoyer un message 408 au client. |
| |
| - haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28] relais-tcp Srv1 0/5007 0 cD |
| => log en mode 'tcplog'. Expiration du time-out côté client ('c----') au bout |
| de 5s. |
| |
| - haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31] relais-http Srv1 3183/-1/-1/11215 503 0 - - SC-- "HEAD / HTTP/1.0" |
| => La requête client met 3s à entrer (peut-être un problème réseau), et la |
| connexion ('SC--') vers le serveur échoue au bout de 4 tentatives de 2 |
| secondes (retries 3 dans la conf), puis un code 503 est retourné au client. |
| |
| 4.3) Modification des entêtes HTTP |
| ---------------------------------- |
| En mode HTTP uniquement, il est possible de remplacer certains en-têtes dans la |
| requête et/ou la réponse à partir d'expressions régulières. Il est également |
| possible de bloquer certaines requêtes en fonction du contenu des en-têtes ou de |
| la requête. Une limitation cependant : les en-têtes fournis au milieu de |
| connexions persistentes (keep-alive) ne sont pas vus car ils sont considérés |
| comme faisant partie des échanges de données consécutifs à la première requête. |
| Les données ne sont pas affectées, ceci ne s'applique qu'aux en-têtes. |
| |
| La syntaxe est : |
| reqadd <string> pour ajouter un en-tête dans la requête |
| reqrep <search> <replace> pour modifier la requête |
| reqirep <search> <replace> idem sans distinction majuscules/minuscules |
| reqdel <search> pour supprimer un en-tête dans la requête |
| reqidel <search> idem sans distinction majuscules/minuscules |
| reqallow <search> autoriser la requête si un entête valide <search> |
| reqiallow <search> idem sans distinction majuscules/minuscules |
| reqdeny <search> interdire la requête si un entête valide <search> |
| reqideny <search> idem sans distinction majuscules/minuscules |
| reqpass <search> inhibe ces actions sur les entêtes validant <search> |
| reqipass <search> idem sans distinction majuscules/minuscules |
| |
| rspadd <string> pour ajouter un en-tête dans la réponse |
| rsprep <search> <replace> pour modifier la réponse |
| rspirep <search> <replace> idem sans distinction majuscules/minuscules |
| rspdel <search> pour supprimer un en-tête dans la réponse |
| rspidel <search> idem sans distinction majuscules/minuscules |
| |
| |
| <search> est une expression régulière compatible POSIX regexp supportant le |
| groupage par parenthèses (sans les '\'). Les espaces et autres séparateurs |
| doivent êtres précédés d'un '\' pour ne pas être confondus avec la fin de la |
| chaîne. De plus, certains caractères spéciaux peuvent être précédés d'un |
| backslach ('\') : |
| |
| \t pour une tabulation |
| \r pour un retour charriot |
| \n pour un saut de ligne |
| \ pour différencier un espace d'un séparateur |
| \# pour différencier un dièse d'un commentaire |
| \\ pour utiliser un backslash dans la regex |
| \\\\ pour utiliser un backslash dans le texte |
| \xXX pour un caractère spécifique XX (comme en C) |
| |
| |
| <replace> contient la chaîne remplaçant la portion vérifiée par l'expression. |
| Elle peut inclure les caractères spéciaux ci-dessus, faire référence à un |
| groupe délimité par des parenthèses dans l'expression régulière, par sa |
| position numérale. Les positions vont de 1 à 9, et sont codées par un '\' |
| suivi du chiffre désiré. Il est également possible d'insérer un caractère non |
| imprimable (utile pour le saut de ligne) inscrivant '\x' suivi du code |
| hexadécimal de ce caractère (comme en C). |
| |
| <string> représente une chaîne qui sera ajoutée systématiquement après la |
| dernière ligne d'en-tête. |
| |
| Remarques : |
| ----------- |
| - la première ligne de la requête et celle de la réponse sont traitées comme |
| des en-têtes, ce qui permet de réécrire des URL et des codes d'erreur. |
| - 'reqrep' est l'équivalent de 'cliexp' en version 1.0, et 'rsprep' celui de |
| 'srvexp'. Ces noms sont toujours supportés mais déconseillés. |
| - pour des raisons de performances, le nombre total de caractères ajoutés sur |
| une requête ou une réponse est limité à 4096 depuis la version 1.1.5 (cette |
| limite était à 256 auparavant). Cette valeur est modifiable dans le code. |
| Pour un usage temporaire, on peut gagner de la place en supprimant quelques |
| entêtes inutiles avant les ajouts. |
| |
| Exemples : |
| ---------- |
| ###### a few examples ###### |
| |
| # rewrite 'online.fr' instead of 'free.fr' for GET and POST requests |
| reqrep ^(GET\ .*)(.free.fr)(.*) \1.online.fr\3 |
| reqrep ^(POST\ .*)(.free.fr)(.*) \1.online.fr\3 |
| |
| # force proxy connections to close |
| reqirep ^Proxy-Connection:.* Proxy-Connection:\ close |
| # rewrite locations |
| rspirep ^(Location:\ )([^:]*://[^/]*)(.*) \1\3 |
| |
| ###### A full configuration being used on production ###### |
| |
| # Every header should end with a colon followed by one space. |
| reqideny ^[^:\ ]*[\ ]*$ |
| |
| # block Apache chunk exploit |
| reqideny ^Transfer-Encoding:[\ ]*chunked |
| reqideny ^Host:\ apache- |
| |
| # block annoying worms that fill the logs... |
| reqideny ^[^:\ ]*\ .*(\.|%2e)(\.|%2e)(%2f|%5c|/|\\\\) |
| reqideny ^[^:\ ]*\ ([^\ ]*\ [^\ ]*\ |.*%00) |
| reqideny ^[^:\ ]*\ .*<script |
| reqideny ^[^:\ ]*\ .*/(root\.exe\?|cmd\.exe\?|default\.ida\?) |
| |
| # allow other syntactically valid requests, and block any other method |
| reqipass ^(GET|POST|HEAD|OPTIONS)\ /.*\ HTTP/1\.[01]$ |
| reqipass ^OPTIONS\ \\*\ HTTP/1\.[01]$ |
| reqideny ^[^:\ ]*\ |
| |
| # force connection:close, thus disabling HTTP keep-alive |
| reqidel ^Connection: |
| rspidel ^Connection: |
| reqadd Connection:\ close |
| rspadd Connection:\ close |
| |
| # change the server name |
| rspidel ^Server:\ |
| rspadd Server:\ Formilux/0.1.8 |
| |
| |
| Enfin, l'option 'forwardfor' ajoute l'adresse IP du client dans un champ |
| 'X-Forwarded-For' de la requête, ce qui permet à un serveur web final de |
| connaître l'adresse IP du client initial. |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| log global |
| option httplog |
| option dontlognull |
| option forwardfor |
| |
| 4.4) Répartition avec persistence |
| --------------------------------- |
| |
| La combinaison de l'insertion de cookie avec la répartition de charge interne |
| permet d'assurer une persistence dans les sessions HTTP d'une manière |
| pratiquement transparente pour les applications. Le principe est simple : |
| - attribuer une valeur d'un cookie à chaque serveur |
| - effectuer une répartition interne |
| - insérer un cookie dans les réponses issues d'une répartition uniquement, |
| et faire en sorte que des caches ne mémorisent pas ce cookie. |
| - cacher ce cookie à l'application lors des requêtes ultérieures. |
| |
| Exemple : |
| --------- |
| listen application 0.0.0.0:80 |
| mode http |
| cookie SERVERID insert nocache indirect |
| balance roundrobin |
| server 192.168.1.1:80 cookie server01 check |
| server 192.168.1.2:80 cookie server02 check |
| |
| 4.5) Personalisation des erreurs |
| -------------------------------- |
| |
| Certaines situations conduisent à retourner une erreur HTTP au client : |
| - requête invalide ou trop longue => code HTTP 400 |
| - requête mettant trop de temps à venir => code HTTP 408 |
| - requête interdite (bloquée par un reqideny) => code HTTP 403 |
| - erreur interne du proxy => code HTTP 500 |
| - le serveur a retourné une réponse incomplète ou invalide => code HTTP 502 |
| - aucun serveur disponible pour cette requête => code HTTP 503 |
| - le serveur n'a pas répondu dans le temps imparti => code HTTP 504 |
| |
| Un message d'erreur succint tiré de la RFC accompagne ces codes de retour. |
| Cependant, en fonction du type de clientèle, on peut préférer retourner des |
| pages personnalisées. Ceci est possible par le biais de la commande "errorloc" : |
| |
| errorloc <code_HTTP> <location> |
| |
| Au lieu de générer une erreur HTTP <code_HTTP> parmi les codes cités ci-dessus, |
| le proxy génèrera un code de redirection temporaire (HTTP 302) vers l'adresse |
| d'une page précisée dans <location>. Cette adresse peut être relative au site, |
| ou absolue. Comme cette réponse est traîtée par le navigateur du client |
| lui-même, il est indispensable que l'adresse fournie lui soit accessible. |
| |
| Exemple : |
| --------- |
| listen application 0.0.0.0:80 |
| errorloc 400 /badrequest.html |
| errorloc 403 /forbidden.html |
| errorloc 408 /toolong.html |
| errorloc 500 http://haproxy.domain.net/bugreport.html |
| errorloc 502 http://192.168.114.58/error50x.html |
| errorloc 503 http://192.168.114.58/error50x.html |
| errorloc 504 http://192.168.114.58/error50x.html |
| |
| 4.6) Changement des valeurs par défaut |
| -------------------------------------- |
| |
| Dans la version 1.1.22 est apparue la notion de valeurs par défaut, ce qui évite |
| de répéter des paramètres communs à toutes les instances, tels que les timeouts, |
| adresses de log, modes de fonctionnement, etc. |
| |
| Les valeurs par défaut sont positionnées dans la dernière section 'defaults' |
| précédent l'instance qui les utilisera. On peut donc mettre autant de sections |
| 'defaults' que l'on veut. Il faut juste se rappeler que la présence d'une telle |
| section implique une annulation de tous les paramètres par défaut positionnés |
| précédemment, dans le but de les remplacer. |
| |
| La section 'defaults' utilise la même syntaxe que la section 'listen', aux |
| paramètres près qui ne sont pas supportés. Le mot clé 'defaults' peut accepter |
| un commentaire en guise paramètre. |
| |
| Dans la version 1.1.23, seuls les paramètres suivants peuvent être positionnés |
| dans une section 'defaults' : |
| - log (le premier et le second) |
| - mode { tcp, http, health } |
| - balance { roundrobin } |
| - disabled (pour désactiver toutes les instances qui suivent) |
| - enabled (pour faire l'opération inverse, mais c'est le cas par défaut) |
| - contimeout, clitimeout, srvtimeout, grace, retries, maxconn |
| - option { redispatch, transparent, keepalive, forwardfor, httplog, |
| dontlognull, persist, httpchk } |
| - redispatch, redisp, transparent, source { addr:port } |
| - cookie, capture |
| - errorloc |
| |
| Ne sont pas supportés dans cette version, les adresses de dispatch et les |
| configurations de serveurs, ainsi que tous les filtres basés sur les |
| expressions régulières : |
| - dispatch, server, |
| - req*, rsp* |
| |
| Enfin, il n'y a pas le moyen, pour le moment, d'invalider un paramètre booléen |
| positionné par défaut. Donc si une option est spécifiée dans les paramètres par |
| défaut, le seul moyen de la désactiver pour une instance, c'est de changer les |
| paramètres par défaut avant la déclaration de l'instance. |
| |
| Exemples : |
| ---------- |
| defaults applications TCP |
| log global |
| mode tcp |
| balance roundrobin |
| clitimeout 180000 |
| srvtimeout 180000 |
| contimeout 4000 |
| retries 3 |
| redispatch |
| |
| listen app_tcp1 10.0.0.1:6000-6063 |
| server srv1 192.168.1.1 check port 6000 inter 10000 |
| server srv2 192.168.1.2 backup |
| |
| listen app_tcp2 10.0.0.2:6000-6063 |
| server srv1 192.168.2.1 check port 6000 inter 10000 |
| server srv2 192.168.2.2 backup |
| |
| defaults applications HTTP |
| log global |
| mode http |
| option httplog |
| option forwardfor |
| option dontlognull |
| balance roundrobin |
| clitimeout 20000 |
| srvtimeout 20000 |
| contimeout 4000 |
| retries 3 |
| |
| listen app_http1 10.0.0.1:80-81 |
| cookie SERVERID postonly insert indirect |
| capture cookie userid= len 10 |
| server srv1 192.168.1.1:+8000 cookie srv1 check port 8080 inter 1000 |
| server srv1 192.168.1.2:+8000 cookie srv2 check port 8080 inter 1000 |
| |
| defaults |
| # section vide qui annule tous les paramètes par défaut. |
| |
| ======================= |
| | Paramétrage système | |
| ======================= |
| |
| Sous Linux 2.4 |
| ============== |
| |
| -- cut here -- |
| #!/bin/sh |
| # set this to about 256/4M (16384 for 256M machine) |
| MAXFILES=16384 |
| echo $MAXFILES > /proc/sys/fs/file-max |
| ulimit -n $MAXFILES |
| |
| if [ -e /proc/sys/net/ipv4/ip_conntrack_max ]; then |
| echo 65536 > /proc/sys/net/ipv4/ip_conntrack_max |
| fi |
| |
| if [ -e /proc/sys/net/ipv4/netfilter/ip_ct_tcp_timeout_fin_wait ]; then |
| # 30 seconds for fin, 15 for time wait |
| echo 3000 > /proc/sys/net/ipv4/netfilter/ip_ct_tcp_timeout_fin_wait |
| echo 1500 > /proc/sys/net/ipv4/netfilter/ip_ct_tcp_timeout_time_wait |
| echo 0 > /proc/sys/net/ipv4/netfilter/ip_ct_tcp_log_invalid_scale |
| echo 0 > /proc/sys/net/ipv4/netfilter/ip_ct_tcp_log_out_of_window |
| fi |
| |
| echo 1024 60999 > /proc/sys/net/ipv4/ip_local_port_range |
| echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout |
| echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog |
| echo 262144 > /proc/sys/net/ipv4/tcp_max_tw_buckets |
| echo 262144 > /proc/sys/net/ipv4/tcp_max_orphans |
| echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time |
| echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle |
| echo 0 > /proc/sys/net/ipv4/tcp_timestamps |
| echo 0 > /proc/sys/net/ipv4/tcp_ecn |
| echo 0 > /proc/sys/net/ipv4/tcp_sack |
| echo 0 > /proc/sys/net/ipv4/tcp_dsack |
| |
| # auto-tuned on 2.4 |
| #echo 262143 > /proc/sys/net/core/rmem_max |
| #echo 262143 > /proc/sys/net/core/rmem_default |
| |
| echo 16384 65536 524288 > /proc/sys/net/ipv4/tcp_rmem |
| echo 16384 349520 699040 > /proc/sys/net/ipv4/tcp_wmem |
| |
| -- cut here -- |
| |
| Sous FreeBSD |
| ============ |
| |
| Un port de HA-Proxy sous FreeBSD est désormais disponible, grâce à |
| Clement Laforet <sheepkiller@cultdeadsheep.org>. |
| |
| Pour plus d'informations : |
| http://www.freebsd.org/cgi/url.cgi?ports/net/haproxy/pkg-descr |
| http://www.freebsd.org/cgi/cvsweb.cgi/ports/net/haproxy/ |
| http://www.freshports.org/net/haproxy |
| |
| |
| -- fin -- |