1455 lines
59 KiB
Plaintext
1455 lines
59 KiB
Plaintext
|
|
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 --
|