mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-05 22:56:57 +02:00
* add the notion of "backup" servers, which are used only when all other servers are down. * make Set-Cookie return "" instead of "(null)" when the server has no cookie assigned (useful for backup servers). * "log" now supports an optionnal level name (info, notice, err ...) above which nothing is sent. * replaced some strncmp() with memcmp() for better efficiency. * added "capture cookie" option which logs client and/or server cookies * cleaned up/down messages and dump servers states upon SIGHUP * added a redirection feature for errors : "errorloc <errnum> <url>" * now we won't insist on connecting to a dead server, even with a cookie, unless option "persist" is specified. * added HTTP/408 response for client request time-out and HTTP/50[234] for server reply time-out or errors. * updates to the examples files * added a 'do_status' command to the Formilux init script
973 lines
38 KiB
Plaintext
973 lines
38 KiB
Plaintext
|
|
H A - P r o x y
|
|
---------------
|
|
version 1.1.17
|
|
willy tarreau
|
|
2002/10/25
|
|
|
|
================
|
|
| 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
|
|
-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'
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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 proxy
|
|
- 1 socket pour chaque serveur en cours de health-check
|
|
- 1 socket pour les logs (tous serveurs confondus)
|
|
|
|
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
|
|
parfois contournable sur certains OS (Linux 2.2, Solaris), mais visiblement
|
|
fiable sur d'autres (Linux 2.4). 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
|
|
|
|
|
|
2) Définition d'un service en écoute
|
|
====================================
|
|
|
|
Les sections de service débutent par le mot clé "listen" :
|
|
|
|
listen <nom_instance> <adresse_IP>:<port>
|
|
|
|
- <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'adresse 0.0.0.0 signifie que les connexions pourront s'effectuer
|
|
sur toutes les adresses de la machine.
|
|
|
|
- <port> est le numéro de port TCP sur lequel le relais attend ses
|
|
connexions. 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').
|
|
|
|
Exemple :
|
|
---------
|
|
listen http_proxy 127.0.0.1:80
|
|
|
|
|
|
2.1) Inhibition d'un service
|
|
----------------------------
|
|
Un serveur 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
|
|
|
|
2.2) Mode de fonctionnement
|
|
---------------------------
|
|
Un serveur 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. Pour activer ce mode, préciser
|
|
le mode HEALTH sous la déclaration du relais.
|
|
|
|
Exemple :
|
|
---------
|
|
listen health_check 0.0.0.0:60000
|
|
mode health
|
|
|
|
|
|
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.
|
|
|
|
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,
|
|
elle sera choisie librement par le systeme. Si le port est 0, il
|
|
sera choisi librement par le système.
|
|
|
|
Exemples :
|
|
----------
|
|
listen http_proxy 0.0.0.0:80
|
|
# toutes les connexions prennent l'adresse 192.168.1.200
|
|
source 192.168.1.200:0
|
|
|
|
listen rlogin_proxy 0.0.0.0: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 0.0.0.0: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 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
|
|
|
|
Attention : la syntaxe a changé depuis la version 1.0.
|
|
-----------
|
|
|
|
3) Répartiteur de charge interne
|
|
=================================
|
|
|
|
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 0.0.0.0: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
|
|
|
|
|
|
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
|
|
|
|
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 : "OPTIONS / HTTP/1.0". Elles
|
|
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".
|
|
|
|
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.
|
|
|
|
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 :
|
|
----------
|
|
# même que précédemment 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
|
|
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
|
|
|
|
# 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, 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.1.3:80 cookie server03 check backup
|
|
server web-excuse 192.168.1.4:80 check 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
|
|
|
|
|
|
4.2) Journalisation des connexions
|
|
----------------------------------
|
|
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
|
|
|
|
Par défaut, les informations contenues dans les logs se situent au niveau TCP
|
|
uniquement. Il faut préciser l'option 'httplog' pour obtenir les détails du
|
|
protocole HTTP. 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).
|
|
|
|
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 la requête HTTP est 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.
|
|
|
|
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
|
|
capture cookie userid= len 20
|
|
|
|
|
|
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 une requête qui valide <search>
|
|
reqiallow <search> idem sans distinction majuscules/minuscules
|
|
reqdeny <search> interdire une requête qui valide <search>
|
|
reqideny <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 GNU 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 un backslash
|
|
\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 :
|
|
--------
|
|
reqrep ^(GET.*)(.free.fr)(.*) \1.online.fr\3
|
|
reqrep ^(POST.*)(.free.fr)(.*) \1.online.fr\3
|
|
reqirep ^Proxy-Connection:.* Proxy-Connection:\ close
|
|
rspirep ^Server:.* Server:\ Tux-2.0
|
|
rspirep ^(Location:\ )([^:]*://[^/]*)(.*) \1\3
|
|
rspidel ^Connection:
|
|
rspadd Connection:\ close
|
|
|
|
|
|
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
|
|
|
|
|
|
=======================
|
|
| 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 --
|
|
|
|
-- fin --
|