mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-12 14:35:14 +00:00
acafc5f88c
This patch adds the "maxqueue" parameter to the server. This allows new sessions to be immediately rebalanced when the server's queue is filled. It's useful when session stickiness is just a performance boost (even a huge one) but not a requirement. This should only be used if session affinity isn't a hard functional requirement but provides performance boost by keeping server-local caches hot and compact). Absence of 'maxqueue' option means unlimited queue. When queue gets filled up to 'maxqueue' client session is moved from server-local queue to a global one.
2858 lines
128 KiB
Plaintext
2858 lines
128 KiB
Plaintext
-------------------
|
|
HAProxy
|
|
Manuel de référence
|
|
-------------------
|
|
version 1.3.2
|
|
willy tarreau
|
|
2006/09/03
|
|
|
|
================
|
|
| Introduction |
|
|
================
|
|
|
|
HAProxy 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 en-tê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.
|
|
- maintenir des clients sur le bon serveur serveur d'application en fonction
|
|
de cookies applicatifs.
|
|
- fournir des rapports d'état en HTML à des utilisateurs authentifiés, à
|
|
travers des URI de l'application interceptées.
|
|
|
|
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>
|
|
= 'maxconn' dans la section 'global'
|
|
-N <nombre maximal de connexions simultanées par instance>
|
|
= 'maxconn' dans les sections 'listen' ou 'default'
|
|
-d active le mode debug
|
|
-D passe en daemon
|
|
-q désactive l'affichage de messages sur la sortie standard.
|
|
-V affiche les messages sur la sortie standard, même si -q ou 'quiet' sont
|
|
spécifiés.
|
|
-c vérifie le fichier de configuration puis quitte avec un code de retour 0
|
|
si aucune erreur n'a été trouvée, ou 1 si une erreur de syntaxe a été
|
|
détectée.
|
|
-p <fichier> indique au processus père qu'il doit écrire les PIDs de ses
|
|
fils dans ce fichier en mode démon.
|
|
-sf specifie une liste de PIDs auxquels envoyer un signal FINISH
|
|
-st specifie une liste de PIDs auxquels envoyer un signal TERMINATE
|
|
-s affiche les statistiques (si option compilée)
|
|
-l ajoute des informations aux statistiques
|
|
-dk désactive l'utilisation de kqueue()
|
|
-ds désactive l'utilisation de epoll() speculatif
|
|
-de désactive l'utilisation de epoll()
|
|
-dp désactive l'utilisation de poll()
|
|
-db désactive la mise en arrière-plan (utile pour débugger)
|
|
-m <megs> applique une limitation de <megs> Mo d'utilisation mémoire
|
|
|
|
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'en-têtes HTTP
|
|
sont affichés.
|
|
|
|
Pour debugger, l'option '-db' est très pratique car elle désactive
|
|
temporairement le mode daemon et le mode multi-processus. Le service peut alors
|
|
être arrêté par un simple appui sur Ctrl-C, sans avoir à modifier la
|
|
configuration ni à activer le mode debug complet.
|
|
|
|
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, et sont amenées à disparaitre.
|
|
|
|
Les paramètres '-st' et '-sf' sont utilisés pour la reconfiguration à chaud.
|
|
Voir la section à ce sujet.
|
|
|
|
============================
|
|
| 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>
|
|
- user <nom d'utilisateur>
|
|
- group <nom de groupe>
|
|
- chroot <répertoire>
|
|
- nbproc <nombre>
|
|
- daemon
|
|
- debug
|
|
- nokqueue
|
|
- nosepoll
|
|
- noepoll
|
|
- nopoll
|
|
- quiet
|
|
- pidfile <fichier>
|
|
- ulimit-n <nombre>
|
|
- tune.maxpollevents <nombre>
|
|
|
|
|
|
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 à l'aide du mot clé global 'maxconn'. 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). A partir des versions 1.1.32/1.2.6,
|
|
il est possible de spécifier cette limite dans la configuration à l'aide du
|
|
mot-clé global 'ulimit-n', à condition bien entendu que le proxy ait été
|
|
démarré sous le compte root (ou avec des droits suffisants pour élever le
|
|
nombre de descripteurs de fichiers). Cette solution met un terme au problème
|
|
récurrent d'incertitude de l'adéquation entre les limites systèmes lors de la
|
|
dernière relance du proxessus et les limites en nombre de connexions. Noter que
|
|
cette limite s'applique par processus.
|
|
|
|
Exemple :
|
|
---------
|
|
global
|
|
maxconn 32000
|
|
ulimit-n 65536
|
|
|
|
|
|
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. Dans le cas où il ne serait pas possible de spécifier un identifiant
|
|
numérique pour l'uid, il est possible de spécifier un nom d'utilisateur après
|
|
le mot-clé 'user'. De la même manière, il est possible de préciser un nom de
|
|
groupe après le mot-clé 'group'.
|
|
|
|
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 importante :
|
|
---------------------
|
|
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 :
|
|
---------
|
|
|
|
# with uid/gid
|
|
global
|
|
uid 30000
|
|
gid 30000
|
|
chroot /var/chroot/haproxy
|
|
|
|
# with user/group
|
|
global
|
|
user haproxy
|
|
group public
|
|
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.
|
|
|
|
Le paramètre de ligne de commande '-db' inhibe les options globales 'daemon'
|
|
et 'nbproc' pour faire fonctionner le processus en mode normal, avant-plan.
|
|
|
|
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'. Un usage déjà rencontré pour ce paramètre fut de dépasser
|
|
la limite de nombre de descripteurs de fichiers allouée par processus sous
|
|
Solaris.
|
|
|
|
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)
|
|
|
|
# pour recharger une configuration avec un impact minimal sur le service,
|
|
# et sans casser les sessions existantes :
|
|
# haproxy -f haproxy.cfg -p /var/run/haproxy-private.pid -sf $(</var/run/haproxy-private.pid)
|
|
|
|
1.7) Mécanismes de traitements des événements
|
|
---------------------------------------------
|
|
A partir de la version 1.2.5, haproxy supporte les mécanismes poll() et
|
|
epoll(). Sur les systems où select() est limité par FD_SETSIZE (comme Solaris),
|
|
poll() peut être une alternative intéressante. Des tests de performance
|
|
montrent que les performances de poll() ne décroissent pas aussi vite que le
|
|
nombre de sockets augmente, ce qui en fait une solution sûre pour les fortes
|
|
charges. Cela dit, Soalris utilise déjà poll() pour émuler select(), donc tant
|
|
que le nombre de sockets ne dépasse pas FD_SETSIZE, poll() ne devrait pas
|
|
apporter de performances supplémentaires. Sur les systèmes à base Linux
|
|
incluant le patch epoll() (ou tous les Linux 2.6), haproxy utilisera epoll()
|
|
qui est extrèmement rapide indépendamment du nombre de sockets. Les tests sur
|
|
haproxy ont montré une performance constante de 1 à 40000 sessions simultanées.
|
|
La version 1.3.9 a introduit le support de kqueue() pour FreeBSD/OpenBSD, ainsi
|
|
qu'une variante appelée "speculative epoll()" consistant à tenter d'effectuer
|
|
les opérations d'entrées/sorties avant de chaîner les événements par les appels
|
|
système.
|
|
|
|
Afin d'optimiser la latence, il est désormais possible de limiter le nombre
|
|
d'événements remontés à chaque appel. La limite par défaut est fixée à 200. Si
|
|
une latence plus petite est recherchée, il peut être justifié d'abaisser cette
|
|
limite par l'utilisation du paramètre 'tune.maxpollevents' dans la section
|
|
'global'. L'augmenter permettra d'économiser un peu le processeur en présence
|
|
de très grands nombres de connexions simultanées.
|
|
|
|
Haproxy utilisera kqueue() ou speculative epoll() lorsque ce sera disponible,
|
|
puis epoll(), et se repliera sur poll(), puis en dernier lieu sur select().
|
|
Cependant, si pour une raison quelconque il s'avérait nécessaire de désactiver
|
|
epoll() ou poll() (p.ex: à cause d'un bug ou juste pour comparer les
|
|
performances), de nouvelles options globales ont été ajoutées dans ce but :
|
|
'nosepoll', 'nokqueue', 'noepoll' et 'nopoll'.
|
|
|
|
Exemple :
|
|
---------
|
|
global
|
|
# utiliser seulement select()
|
|
noepoll
|
|
nopoll
|
|
tune.maxpollevents 100
|
|
|
|
Remarque :
|
|
----------
|
|
Dans le but d'assurer une portabilité maximale des configurations, ces options
|
|
sont acceptées et ignorées si les mécanismes poll() ou epoll() n'ont pas été
|
|
activés lors de la compilation.
|
|
|
|
Afin de simplifier la résolution de problèmes, le paramètre '-de' en ligne de
|
|
commande désactive epoll(), le paramètre '-dp' désactive poll(), '-dk' kqueue()
|
|
et '-ds' désactive speculative epoll(). Ils sont respectivement équivalents à
|
|
'noepoll', 'nopoll', 'nokqueue' et 'nosepoll'.
|
|
|
|
|
|
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
|
|
- état de santé
|
|
|
|
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 en-tê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.2.1 Supervision
|
|
-----------------
|
|
Les versions 1.1.32 et 1.2.6 apportent une nouvelle solution pour valider le
|
|
bon fonctionnement du proxy sans perturber le service. Le mot-clé 'monitor-net'
|
|
a été créé dans le butd de spécifier un réseau d'équipements qui ne PEUVENT PAS
|
|
utiliser le service pour autre chose que des tests de fonctionnement. C'est
|
|
particulièrement adapté aux proxies TCP, car cela empêche le proxy de relayer
|
|
des établissements de connexion émis par un outil de surveillance.
|
|
|
|
Lorsque c'est utilisé sur un proxy TCP, la connexion est acceptée puis refermée
|
|
et rien n'est logué. C'est suffisant pour qu'un répartiteur de charge en amont
|
|
détecte que le service est disponible.
|
|
|
|
Lorsque c'est utilisé sur un proxy HTTP, la connexion est acceptée, rien n'est
|
|
logué, puis la réponse suivante est envoyée et la session refermée :
|
|
"HTTP/1.0 200 OK". C'est normalement suffisant pour qu'un répartiteur de charge
|
|
HTTP en amont détecte le service comme opérationnel, aussi bien à travers des
|
|
tests TCP que HTTP.
|
|
|
|
Les proxies utilisant le mot-clé 'monitor-net' peuvent accessoirement se passer
|
|
de l'option 'dontlognull', ce qui permettra de loguer les connexions vides
|
|
émises depuis d'autres adresses que celles du réseau de tests.
|
|
|
|
Exemple :
|
|
---------
|
|
|
|
listen tse-proxy
|
|
bind :3389,:1494,:5900 # TSE, ICA and VNC at once.
|
|
mode tcp
|
|
balance roundrobin
|
|
server tse-farm 192.168.1.10
|
|
monitor-net 192.168.1.252/31 # L4 load-balancers on .252 and .253
|
|
|
|
|
|
Lorsque le système effectuant les tests est situé derrière un proxy, le mot-clé
|
|
'monitor-net' n'est pas utilisable du fait que haproxy verra toujours la même
|
|
adresse pour le proxy. Pour pallier à cette limitation, la version 1.2.15 a
|
|
apporté le mot-clé 'monitor-uri'. Il définit une URI qui ne sera ni retransmise
|
|
ni logée, mais pour laquelle haproxy retournera immédiatement une réponse
|
|
"HTTP/1.0 200 OK". Cela rend possibles les tests de validité d'une chaîne
|
|
reverse-proxy->haproxy en une requête HTTP. Cela peut être utilisé pour valider
|
|
une combinaision de stunnel+haproxy à l'aide de tests HTTPS par exemple. Bien
|
|
entendu, ce mot-clé n'est valide qu'en mode HTTP, sinon il n'y a pas de notion
|
|
d'URI. Noter que la méthode et la version HTTP sont simplement ignorées.
|
|
|
|
Exemple :
|
|
---------
|
|
|
|
listen stunnel_backend :8080
|
|
mode http
|
|
balance roundrobin
|
|
server web1 192.168.1.10:80 check
|
|
server web2 192.168.1.11:80 check
|
|
monitor-uri /haproxy_test
|
|
|
|
|
|
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
|
|
SIGUSR1 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, ou bien tuer
|
|
manuellement le processus par l'envoi d'un signal SIGTERM. La valeur par défaut
|
|
du paramètre 'grace' 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
|
|
|
|
A partir de la version 1.2.8, un nouveau mécanisme de reconfiguration à chaud
|
|
a été introduit. Il est désormais possible de mettre les proxies en "pause" en
|
|
envoyant un signal SIGTTOU aux processus. Cela désactivera les sockets d'écoute
|
|
sans casser les sessions existantes. Suite à cela, l'envoi d'un signal SIGTTIN
|
|
réactivera les sockets d'écoute. Ceci est très pratique pour tenter de charger
|
|
une nouvelle configuration ou même une nouvelle version de haproxy sans casser
|
|
les connexions existantes. Si le rechargement s'effectue correctement, il ne
|
|
reste plus qu'à envoyer un signal SIGUSR1 aux anciens processus, ce qui
|
|
provoquera leur arrêt immédiat dès que leurs connexions seront terminées ; en
|
|
revanche, si le rechargement échoue, il suffit d'envoyer un signal SIGTTIN pour
|
|
remettre les ports en écoute et rétablir le service immédiatement. Veuillez
|
|
noter que le paramètre 'grace' est ignoré pour le signal SIGTTOU ainsi que le
|
|
signal SIGUSR1 une fois le processus en pause. Aussi, il peut s'avérer très
|
|
utile de sauver le fichier de pid avant de démarrer une nouvelle instance.
|
|
|
|
Ce mécanisme est pleinement exploité à partir de la version 1.2.11 avec les
|
|
options '-st' et '-sf' (voir ci-dessous).
|
|
|
|
2.4) Reconfiguration à chaud
|
|
----------------------------
|
|
Les paramètres '-st' et '-sf' sont utilisés pour informer des processus
|
|
existants que la configuration va être rechargée. Ils recevront le signal
|
|
SIGTTOU, leur demandant de libérer les ports en écoute afin que le nouveau
|
|
processus puisse les prendre. Si quoi que ce soit se passe mal, le nouveau
|
|
processus leur enverra un signal SIGTTIN pour leur indiquer qu'ils peuvent
|
|
se remettre en écoute et continuer leur travail. En revanche, si la
|
|
configuration se charge correctement, alors ils recevront un signal de demande
|
|
de fin de travail en douceur (-sf), ou de terminaison immédiate (-st) qui
|
|
coupera les sessions en cours. Un usage typique tel que celui-ci permet de
|
|
recharger une configuration sans interruption de service :
|
|
|
|
# haproxy -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)
|
|
|
|
|
|
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
|
|
|
|
Il est à noter que la tentative de reconnexion peut amener à utiliser un autre
|
|
serveur si le premier a disparu entre deux tentatives de connexion.
|
|
|
|
|
|
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 réutiliser un cookie applicatif et lui préfixer l'identifiant du serveur,
|
|
puis le supprimer dans les requêtes suivantes, utiliser l'option 'prefix'. Elle
|
|
permet d'insérer une instance de haproxy devant une application sans risquer
|
|
d'incompatibilités dûes à des clients qui ne supporteraient pas d'apprendre
|
|
plus d'un cookie :
|
|
|
|
cookie JSESSIONID prefix
|
|
|
|
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.
|
|
|
|
- le mode 'prefix' ne nécessite pas d'utiliser 'indirect', 'nocache', ni
|
|
'postonly', car tout comme le mode 'rewrite', il s'appuie sur un cookie
|
|
présenté par l'application qui est censée savoir à quel moment il peut
|
|
être émis sans risque. Toutefois, comme il nécessite de rectifier le cookie
|
|
présenté par le client dans chaque requête ultérieure, il est indispensable
|
|
de s'assurer que le client et le serveur communiqueront sans "keep-alive
|
|
HTTP". Dans le doute, il est recommandé d'utiliser l'option "httpclose".
|
|
|
|
- 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. Jusqu'à la version
|
|
1.2.11, seul 'roundrobin' était géré, et c'est aussi la valeur implicite par
|
|
défaut. Avec la version 1.2.12, le nouveau mot clé 'source' est apparu. La
|
|
version 1.3.10 a également apporté le mot clé 'uri'. 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
|
|
|
|
Comme indiqué précédemment, la version 1.2.12 apporta le nouveau mot clé
|
|
'source'. Lorsque celui-ci est utilisé, l'adresse IP du client est hachée et
|
|
distribuée de manière homogène parmi les serveurs disponibles, de sorte qu'une
|
|
même adresse IP aille toujours sur le même serveur tant qu'il n'y a aucun
|
|
changement dans le nombre de serveurs disponibles. Ceci peut être utilisé par
|
|
exemple pour attacher le HTTP et le HTTPS sur un même serveur pour un même
|
|
client. Cela peut également être utilisé pour améliorer la persistance
|
|
lorsqu'une partie de la population des clients n'accepte pas les cookies. Dans
|
|
ce cas, seuls ces derniers seront perturbés par la perte d'un serveur.
|
|
|
|
NOTE: il est important de prendre en compte le fait que beaucoup d'internautes
|
|
naviguent à travers des fermes de proxies qui assignent des adresses IP
|
|
différentes à chaque requête. D'autres internautes utilisent des liens à
|
|
la demande et obtiennent une adresse IP différente à chaque connexion. De
|
|
ce fait, le paramètre 'source' doit être utilisé avec une extrème
|
|
précaution.
|
|
|
|
Exemples :
|
|
----------
|
|
|
|
# assurer qu'une même adresse IP ira sur le même serveur pour tout service
|
|
|
|
listen http_proxy
|
|
bind :80,:443
|
|
mode http
|
|
balance source
|
|
server web1 192.168.1.1
|
|
server web2 192.168.1.2
|
|
|
|
# améliorer la persistance par l'utilisation de la source en plus du cookie :
|
|
|
|
listen http_proxy :80
|
|
mode http
|
|
cookie SERVERID
|
|
balance source
|
|
server web1 192.168.1.1 cookie server01
|
|
server web2 192.168.1.2 cookie server02
|
|
|
|
De plus, tel qu'indiqué ci-dessus, la version 1.3.10 a introduit le mot clé
|
|
'uri'. Il est très pratique dans le cas de répartition de charge entre des
|
|
reverse-proxy-caches, parce qu'il utilisera le résultat d'un hachage de l'URI
|
|
pour choisir un serveur, ce qui aura pour effet d'optimiser le taux de cache
|
|
du fait que la même URI sera toujours envoyée au même cache. Ce mot-clé n'est
|
|
autorisé qu'en mode HTTP.
|
|
|
|
Example :
|
|
---------
|
|
|
|
# Envoie toujours une URI donnée au même serveur
|
|
|
|
listen http_proxy
|
|
bind :3128
|
|
mode http
|
|
balance uri
|
|
server squid1 192.168.1.1
|
|
server squid2 192.168.1.2
|
|
|
|
|
|
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
|
|
- addr : adresse de connexion du serveur (par defaut: adresse 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>
|
|
|
|
HAProxy est souvent utilisé pour relayer divers protocoles reposant sur TCP,
|
|
tels que HTTPS, SMTP ou LDAP, le plus commun étant HTTPS. Un problème assez
|
|
couramment rencontré dans les data centers est le besoin de relayer du trafic
|
|
vers des serveurs lointains tout en maintenant la possibilité de basculer sur
|
|
un serveur de secours. Les tests purement TCP ne suffisent pas toujours dans
|
|
ces situations car l'on trouve souvent, dans la chaîne, des proxies, firewalls
|
|
ou répartiteurs de charge qui peuvent acquitter la connexion avant qu'elle
|
|
n'atteigne le serveur. La seule solution à ce problème est d'envoyer des tests
|
|
applicatifs. Comme la demande pour les tests HTTPS est élevée, ce test a été
|
|
implémenté en version 1.2.15 sur la base de messages SSLv3 CLIENT HELLO. Pour
|
|
l'activer, utiliser "option ssl-hello-chk". Ceci enverra des messages SSLv3
|
|
CLIENT HELLO aux serveurs, en annonçant un support pour la majorité des
|
|
algorithmes de chiffrement. Si en retour, le serveur envoie ce qui ressemble à
|
|
une réponse SSLv3 SERVER HELLO ou ALERT (refus des algorithmes), alors la
|
|
réponse sera considérée comme valide. Noter qu'Apache ne produit pas de log
|
|
lorsqu'il reçoit des messages HELLO, ce qui en fait un type de message
|
|
parfaitement adapté à ce besoin.
|
|
|
|
La version 1.3.10 est accompagnée d'un nouveau test d'état pour le SMTP. Par
|
|
défaut, il consiste à envoyer "HELO localhost" aux serveurs, et à attendre le
|
|
message "250" en retour. Notez qu'il peut aussi envoyer une requête plus
|
|
spécifique :
|
|
|
|
- option smtpchk -> envoie "HELO localhost"
|
|
- option smtpchk EHLO mail.mydomain.com -> envoie ce message ESMTP
|
|
|
|
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 par défaut. A partir
|
|
de la version 1.2.9, il est possible de les utiliser simultanément grâce à
|
|
l'option 'allbackups'. 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. Il
|
|
est possible d'envoyer les tests de fonctionnement vers une adresse différente
|
|
de celle de service. Cela permet d'utiliser, sur la machine faisant fonctionner
|
|
HAproxy, un démon permettant des tests specifiques ( REGEX sur un résultat et
|
|
basculement de plusieurs fermes en cas d'erreur sur l'une d'elles).
|
|
|
|
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.
|
|
|
|
Depuis la version 1.1.18 (et 1.2.1), un message d'urgence est envoyé dans les
|
|
logs en niveau 'emerg' si tous les serveurs d'une même instance sont tombés,
|
|
afin de notifier l'administrateur qu'il faut prendre une action immédiate.
|
|
|
|
Depuis les versions 1.1.30 et 1.2.3, plusieurs serveurs peuvent partager la
|
|
même valeur de cookie. C'est particulièrement utile en mode backup, pour
|
|
sélectionner des chemins alternatifs pour un serveur donné, pour mettre en
|
|
oeuvre l'arrêt en douceur d'un serveur, ou pour diriger les clients
|
|
temporairement vers une page d'erreur en attendant le redémarrage d'une
|
|
application. Le principe est que lorsqu'un serveur est détecté comme inopérant,
|
|
le proxy cherchera le prochain serveur possédant la même valeur de cookie pour
|
|
chaque client qui le demandera. S'il ne trouve pas de serveur normal, alors il
|
|
le cherchera parmi les serveurs de backup. Consulter le guide d'architecture
|
|
pour plus d'informations.
|
|
|
|
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
|
|
|
|
# répartition avec persistence basée sur le préfixe de cookie, et arrêt en
|
|
# douceur utilisant un second port (81) juste pour les health-checks.
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
cookie JSESSIONID prefix
|
|
balance roundrobin
|
|
option httpchk HEAD /index.jsp? HTTP/1.1\r\nHost:\ www
|
|
server web1-norm 192.168.1.1:80 cookie s1 check port 81
|
|
server web2-norm 192.168.1.2:80 cookie s2 check port 81
|
|
server web1-stop 192.168.1.1:80 cookie s1 check port 80 backup
|
|
server web2-stop 192.168.1.2:80 cookie s2 check port 80 backup
|
|
|
|
# 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
|
|
|
|
# relayage HTTPS avec test du serveur et serveur de backup
|
|
|
|
listen http_proxy :443
|
|
mode tcp
|
|
option ssl-hello-chk
|
|
balance roundrobin
|
|
server srv1 192.168.1.1 check inter 30000 rise 1 fall 2
|
|
server srv2 192.168.1.2 backup
|
|
|
|
# Utilisation d'un groupe de serveurs pour le backup (nécessite haproxy 1.2.9)
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
balance roundrobin
|
|
option httpchk
|
|
server inst1 192.168.1.1:80 cookie s1 check
|
|
server inst2 192.168.1.2:80 cookie s2 check
|
|
server inst3 192.168.1.3:80 cookie s3 check
|
|
server back1 192.168.1.10:80 check backup
|
|
server back2 192.168.1.11:80 check backup
|
|
option allbackups # all backups will be used
|
|
|
|
|
|
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.
|
|
|
|
|
|
3.3) Assignation de poids différents à des serveurs
|
|
---------------------------------------------------
|
|
Parfois il arrive d'ajouter de nouveaux serveurs pour accroître la capacité
|
|
d'une ferme de serveur, mais le nouveau serveur est soit beaucoup plus petit
|
|
que les autres (dans le cas d'un ajout d'urgence de matériel de récupération),
|
|
soit plus puissant (lors d'un investissement dans du matériel neuf). Pour cette
|
|
raison, il semble parfois judicieux de pouvoir envoyer plus de clients vers les
|
|
plus gros serveurs. Jusqu'à la version 1.2.11, il était nécessaire de répliquer
|
|
plusieurs fois les définitions des serveurs pour augmenter leur poids. Depuis
|
|
la version 1.2.12, l'option 'weight' est disponible. HAProxy construit alors
|
|
une vue des serveurs disponibles la plus homogène possible en se basant sur
|
|
leur poids de sorte que la charge se distribue de la manière la plus lisse
|
|
possible. Le poids compris entre 1 et 256 doit refléter la capacité d'un
|
|
serveur par rapport aux autres. Le poids de 1 donne la fréquence d'apparition
|
|
la plus faible, et 256 la fréquence la plus élevée. De cette manière, si un
|
|
serveur disparait, les capacités restantes sont toujours respectées.
|
|
|
|
|
|
Exemple :
|
|
---------
|
|
# distribution équitable sur 2 opteron and un ancien pentium3
|
|
|
|
listen web_appl 0.0.0.0:80
|
|
mode http
|
|
cookie SERVERID insert nocache indirect
|
|
balance roundrobin
|
|
server pentium3-800 192.168.1.1:80 cookie server01 weight 8 check
|
|
server opteron-2.0G 192.168.1.2:80 cookie server02 weight 20 check
|
|
server opteron-2.4G 192.168.1.3:80 cookie server03 weight 24 check
|
|
server web-backup1 192.168.2.1:80 cookie server04 check backup
|
|
server web-excuse 192.168.3.1:80 check backup
|
|
|
|
Notes :
|
|
-------
|
|
- lorsque le poids n'est pas spécifié, la valeur par défaut est à 1
|
|
|
|
- le poids n'impacte pas les tests de fonctionnement (health checks), donc il
|
|
est plus propre d'utiliser les poids que de répliquer le même serveur
|
|
plusieurs fois.
|
|
|
|
- les poids s'appliquent également aux serveurs de backup si l'option
|
|
'allbackups' est positionnée.
|
|
|
|
- le poids s'applique aussi à la répartition selon la source
|
|
('balance source').
|
|
|
|
- quels que soient les poids, le premier serveur sera toujours assigné en
|
|
premier. Cette règle facilite les diagnostics.
|
|
|
|
- pour les puristes, l'algorithme de calculation de la vue des serveurs donne
|
|
une priorité aux premiers serveurs, donc la vue est la plus uniforme si les
|
|
serveurs sont déclarés dans l'ordre croissant de leurs poids.
|
|
|
|
La distribution du trafic suivra exactement le séquencement suivant :
|
|
|
|
Request| 1 1 1 1
|
|
number | 1 2 3 4 5 6 7 8 9 0 1 2 3
|
|
--------+---------------------------
|
|
p3-800 | X . . . . . . X . . . . .
|
|
opt-20 | . X . X . X . . . X . X .
|
|
opt-24 | . . X . X . X . X . X . X
|
|
|
|
|
|
3.4) Limitation du nombre de sessions concurrentes par serveur
|
|
--------------------------------------------------------------
|
|
Certains serveurs web multi-processus tels qu'Apache souffrent dès qu'il y a
|
|
trop de sessions concurrentes, parce qu'il est très coûteux de faire
|
|
fonctionner des centaines ou des milliers de processus sur un système. Une
|
|
solution consiste à augmenter le nombre de serveurs et de répartir la charge
|
|
entre eux, mais cela pose un problème lorsque le but est uniquement de résister
|
|
à des pics de charge occasionnels.
|
|
|
|
Pour résoudre ce problème, une nouvelle fonctionnalité a été implémentée dans
|
|
HAProxy 1.2.13. Il s'agit d'une limite "maxconn" par serveur, associée à une
|
|
file d'attente par serveur et par proxy. Ceci transforme HAProxy en un tampon
|
|
entre des milliers de clients et quelques serveurs. Dans bien des cas, le fait
|
|
de diminuer la valeur maxconn améliorera notablement les performances des
|
|
serveurs et diminuera les temps de réponse simplement parce que les serveurs
|
|
seront moins congestionnés.
|
|
|
|
Quand une requête cherche à joindre n'importe quel serveur, le premier serveur
|
|
non saturé est utilisé, en respectant l'algorithme de répartition de charge. Si
|
|
tous les serveurs sont saturés, alors la requête sera mise dans la file
|
|
d'attente globale de l'instance. Elle sortira de cette file d'attente lorsque
|
|
toutes les requêtes précédentes auront été libérées et qu'un serveur aura été
|
|
libéré d'une connexion pour la traiter.
|
|
|
|
Si une requête fait référence à un serveur en particulier (p.ex: hachage d'IP
|
|
source, ou persistance par cookie), et que ce server est saturé, alors la
|
|
requête sera mise dans la file d'attente dédiée à ce serveur. Cette file
|
|
d'attente est prioritaire sur la file d'attente globale, de sorte qu'il soit
|
|
plus facile d'atteindre le site pour les utilisateurs qui s'y trouvent déjà
|
|
que pour les nouveaux utilisateurs.
|
|
|
|
Pour cela, les logs ont dû être enrichis pour indiquer le nombre de sessions
|
|
par serveur, la position de la requête dans les files d'attentes, et le temps
|
|
passé en file d'attente. Ceci aide considérablement à faire de la prévision de
|
|
capacité. Voir la section 'logs' plus bas pour plus d'informations.
|
|
|
|
Exemple :
|
|
---------
|
|
# Prendre soin du P3 qui n'a que 256 Mo de RAM.
|
|
listen web_appl 0.0.0.0:80
|
|
maxconn 10000
|
|
mode http
|
|
cookie SERVERID insert nocache indirect
|
|
balance roundrobin
|
|
server pentium3-800 192.168.1.1:80 cookie s1 weight 8 maxconn 100 check
|
|
server opteron-2.0G 192.168.1.2:80 cookie s2 weight 20 maxconn 300 check
|
|
server opteron-2.4G 192.168.1.3:80 cookie s3 weight 24 maxconn 300 check
|
|
server web-backup1 192.168.2.1:80 cookie s4 check maxconn 200 backup
|
|
server web-excuse 192.168.3.1:80 check backup
|
|
|
|
Cette option se montra si efficace pour réduire les temps de réponse des
|
|
serveurs que certains utilisateurs voulaient utiliser des valeurs trop basses
|
|
pour améliorer les performances de leurs serveurs. Seulement, ils n'étaient
|
|
alors plus en mesure de supporter de très fortes charges parce qu'il n'était
|
|
plus possible de les saturer. Pour cette raison, la version 1.2.14 a apporté la
|
|
limitation dynamique de connexions avec l'addition du paramètre "minconn".
|
|
Lorsque ce paramètre est associé à "maxconn", il active la limitation dynamique
|
|
basée sur la charge de l'instance. Le nombre maximal de sessions concurrentes
|
|
sur un serveur devient alors proportionnel au nombre de sessions de l'instance
|
|
par rapport à son 'maxconn'. Un minimum de <minconn> sessions sera toujours
|
|
permis quelle que soit la charge. Ceci assurera que les serveurs travailleront
|
|
au meilleur de leurs performances sous des charges normales, et qu'ils seront
|
|
tout de même capables de supporter de fortes pointes lorsque nécessaire. La
|
|
limite dynamique est calculée comme ceci :
|
|
|
|
srv.dyn_limit = max(srv.minconn, srv.maxconn * inst.sess / inst.maxconn)
|
|
|
|
Exemple :
|
|
---------
|
|
# Prendre soin du P3 qui n'a que 256 Mo de RAM.
|
|
listen web_appl 0.0.0.0:80
|
|
maxconn 10000
|
|
mode http
|
|
cookie SERVERID insert nocache indirect
|
|
balance roundrobin
|
|
server pentium3-800 192.168.1.1:80 cookie s1 weight 8 minconn 10 maxconn 100 check
|
|
server opteron-2.0G 192.168.1.2:80 cookie s2 weight 20 minconn 30 maxconn 300 check
|
|
server opteron-2.4G 192.168.1.3:80 cookie s3 weight 24 minconn 30 maxconn 300 check
|
|
server web-backup1 192.168.2.1:80 cookie s4 check maxconn 200 backup
|
|
server web-excuse 192.168.3.1:80 check backup
|
|
|
|
Dans l'exemple ci-dessus, le serveur "pentium3-800' recevra au plus 100
|
|
connexions simultanées lorsque l'instance du proxy en atteindra 10000, et
|
|
recevra seulement 10 connexions simultanées tant que le proxy sera sous les 1000
|
|
sessions.
|
|
|
|
Il est possible de limiter la taille de la file d'attente dans le but de
|
|
redistribuer les connexions destinées à un serveur en particulier qui sont trop
|
|
loin pour avoir une chance d'être servies en un temps raisonnable. Ceci n'est
|
|
acceptable que dans le cas où l'affinité entre le client et le serveur n'est
|
|
pas obligatoire, mais motivée uniquement par des raisons de performances, par
|
|
exemple, par l'utilisation d'un cache local au serveur. L'option 'maxqueue'
|
|
permet de préciser la limite par serveur, tel que dans l'exemple ci-dessous :
|
|
|
|
... (même exemple que précédemment)
|
|
server pentium3-800 192.168.1.1:80 cookie s1 weight 8 minconn 10 maxconn 100 check maxqueue 50
|
|
server opteron-2.0G 192.168.1.2:80 cookie s2 weight 20 minconn 30 maxconn 300 check maxqueue 200
|
|
server opteron-2.4G 192.168.1.3:80 cookie s3 weight 24 minconn 30 maxconn 300 check
|
|
|
|
En l'absence du paramètre 'maxqueue', la file d'un serveur n'a pas de limite
|
|
définie. Dans le cas contraire, lorsque la file atteint la limite fixée par
|
|
'maxqueue', les clients sont déplacés vers la file globale.
|
|
|
|
Notes :
|
|
-------
|
|
- la requête ne restera pas indéfiniment en file d'attente, elle est
|
|
assujétie au paramètre 'contimeout', et si une requête ne peut pas
|
|
sortir de la file avant ce time-out, soit parce que le serveur est
|
|
saturé, soit parce qu'il y a trop de requêtes en file d'attente,
|
|
alors elle expirera avec une erreur 503.
|
|
|
|
- si seul <minconn> est spécifié, il a le même effet que <maxconn>
|
|
|
|
- positionner des valeurs trop basses pour 'maxconn' peut améliorer les
|
|
performances mais aussi permettre à des utilisateurs trop lents de bloquer
|
|
un serveur pour les autres utilisateurs.
|
|
|
|
|
|
3.5) Abandon des requêtes abortées
|
|
----------------------------------
|
|
En présence de très fortes charges, les serveurs mettront un certain temps à
|
|
répondre. La file d'attente du proxy se remplira, et les temps de réponse
|
|
suivront une croissance proportionnelle à la taille de file d'attente fois
|
|
le temps moyen de réponse par session. Lorsque les clients attendront plus de
|
|
quelques secondes, ils cliqueront souvent sur le bouton 'STOP' de leur
|
|
navigateur, laissant des requêtes inutiles en file d'attente et ralentissant
|
|
donc les autres utilisateurs.
|
|
|
|
Comme il n'y a aucun moyen de distinguer un vrai clic sur STOP d'une simple
|
|
fermeture du canal de sortie sur le client (shutdown(SHUT_WR)), les agents HTTP
|
|
doivent être conservateurs et considérer que le client n'a probablement fermé
|
|
que le canal de sortie en attendant la réponse. Toutefois, ceci introduit des
|
|
risques de congestion lorsque beaucoup d'utilisateurs font de même, et s'avère
|
|
aujourd'hui complètement inutile car probablement aucun client ne referme la
|
|
session en attendant la réponse. Certains agents HTTP supportent ceci (Squid,
|
|
Apache, HAProxy), et d'autres ne le supportent pas (TUX, et la plupart des
|
|
répartiteurs de charge matériels). Donc la probabilité pour qu'une notification
|
|
de fermeture d'un canal d'entrée côté client représente un utilisateur cliquant
|
|
sur 'STOP' est proche de 100%, et il est vraiment tentant d'abandonner la
|
|
requête prématurément sans polluer les serveurs.
|
|
|
|
Pour cette raison, une nouvelle option "abortonclose" a été introduite en
|
|
version 1.2.14. Par défaut (sans l'option), le comportement reste conforme à
|
|
HTTP. Mais lorsque l'option est spécifiée, une session dont le canal entrant
|
|
est fermé sera abortée si cela est possible, c'est à dire que la requête est
|
|
soit en file d'attente, soit en tentative de connexion. Ceci réduit
|
|
considérablement la longueur des files d'attentes et la charge sur les serveurs
|
|
saturés lorsque les utilisateurs sont tentés de cliquer sur 'STOP', ce qui à
|
|
son tour, réduit les temps de réponse pour les autres utilisateurs.
|
|
|
|
Exemple :
|
|
---------
|
|
listen web_appl 0.0.0.0:80
|
|
maxconn 10000
|
|
mode http
|
|
cookie SERVERID insert nocache indirect
|
|
balance roundrobin
|
|
server web1 192.168.1.1:80 cookie s1 weight 10 maxconn 100 check
|
|
server web2 192.168.1.2:80 cookie s2 weight 10 maxconn 100 check
|
|
server web3 192.168.1.3:80 cookie s3 weight 10 maxconn 100 check
|
|
server bck1 192.168.2.1:80 cookie s4 check maxconn 200 backup
|
|
option abortonclose
|
|
|
|
|
|
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, de la
|
|
réécriture des en-têtes, et du statut sous forme de page HTML.
|
|
|
|
|
|
4.1) Fonctionnalités réseau
|
|
---------------------------
|
|
4.1.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.1.2) Choix d'une adresse source par serveur
|
|
---------------------------------------------------
|
|
Avec les versions 1.1.30 et 1.2.3, il devient possible de spécifier une adresse
|
|
IP source pour joindre chaque serveur. C'est utile pour joindre des serveurs de
|
|
backup à partir d'un LAN différent, ou pour utiliser des chemins alternatifs
|
|
pour joindre le même serveur. C'est également utilisable pour faciliter une
|
|
répartition de charge selon l'adresse IP source pour des connexions sortantes.
|
|
Bien entendu, la même adresse est utilisée pour les health-checks.
|
|
|
|
Exemple :
|
|
---------
|
|
# utiliser une adresse particulière pour joindre les 2 serveur
|
|
listen http_proxy 0.0.0.0:65000
|
|
mode http
|
|
balance roundrobin
|
|
server server01 192.168.1.1:80 source 192.168.2.13
|
|
server server02 192.168.1.2:80 source 192.168.2.13
|
|
|
|
Exemple :
|
|
---------
|
|
# utiliser une adresse particulière pour joindre chaque serveur
|
|
listen http_proxy 0.0.0.0:65000
|
|
mode http
|
|
balance roundrobin
|
|
server server01 192.168.1.1:80 source 192.168.1.1
|
|
server server02 192.168.2.1:80 source 192.168.2.1
|
|
|
|
Exemple :
|
|
---------
|
|
# faire une répartition d'adresse sources pour joindre le même proxy à
|
|
# travers deux liens WAN
|
|
listen http_proxy 0.0.0.0:65000
|
|
mode http
|
|
balance roundrobin
|
|
server remote-proxy-way1 192.168.1.1:3128 source 192.168.2.1
|
|
server remote-proxy-way2 192.168.1.1:3128 source 192.168.3.1
|
|
|
|
Exemple :
|
|
---------
|
|
# forcer une connexion TCP à s'attacher à un port particulier
|
|
listen http_proxy 0.0.0.0:2000
|
|
mode tcp
|
|
balance roundrobin
|
|
server srv1 192.168.1.1:80 source 192.168.2.1:20
|
|
server srv2 192.168.1.2:80 source 192.168.2.1:20
|
|
|
|
4.1.3) Maintien de session TCP (keep-alive)
|
|
-------------------------------------------
|
|
Avec la version 1.2.7, il devient possible d'activer le maintien de session
|
|
TCP (TCP keep-alive) à la fois côté client et côté serveur. Cela permet
|
|
d'empêcher des sessions longues d'expirer sur des équipements de niveau 4
|
|
externes tels que des firewalls ou des répartiteurs de charge. Cela permet
|
|
aussi au système de détecter et terminer des sessions figées lorsqu'aucun
|
|
time-out n'a été positionné (fortement déconseillé). Le proxy ne peut pas
|
|
positionner l'intervalle entre les annonces ni le nombre maximal, veuillez
|
|
vous référer au manuel du système d'exploitation pour cela. Il existe 3 options
|
|
pour activer le maintien de session TCP :
|
|
|
|
option tcpka # active le keep-alive côté client et côté serveur
|
|
option clitcpka # active le keep-alive côté client
|
|
option srvtcpka # active le keep-alive côté serveur
|
|
|
|
4.1.4) Rémanence des données TCP (lingering)
|
|
--------------------------------------------
|
|
Il est possible de désactiver la conservation de données non acquittées par un
|
|
client à la fin d'une session. Cela peut parfois s'avérer nécessaire lorsque
|
|
haproxy est utilisé en face d'un grand nombre de clients non fiables et qu'un
|
|
nombre élevé de sockets en état FIN_WAIT est observé sur la machine. L'option
|
|
peut être utilisée dans un frontend pour ajuster les connexions vers les
|
|
clients, et dans un backend pour ajuster les connexions vers les serveurs :
|
|
|
|
option nolinger # désactive la conservation de données
|
|
|
|
|
|
4.2) Journalisation des connexions
|
|
----------------------------------
|
|
|
|
L'un des points forts de HAProxy est indéniablement la précision de ses logs.
|
|
Il fournit probablement le plus fin niveau d'information disponible pour un
|
|
tel outil, ce qui est très important pour les diagnostics en environnements
|
|
complexes. En standard, les informations journalisées incluent le port client,
|
|
les chronométrages des états TCP/HTTP, des états de session précis au moment de
|
|
la terminaison et sa cause, des informations sur les décisions d'aiguillage du
|
|
trafic vers un serveur, et bien sûr la possibilité de capturer des en-têtes
|
|
arbitraires.
|
|
|
|
Dans le but d'améliorer la réactivité des administrateurs, il offre une grande
|
|
transparence sur les problèmes rencontrés, à la fois internes et externes, et
|
|
il est possible d'envoyer les logs vers des serveurs différents en même temps
|
|
avec des niveaux de filtrage différents :
|
|
|
|
- logs globaux au niveau processus (erreurs système, arrêts/démarrages, ...)
|
|
- erreurs système et internes par instance (manque de ressources, bugs, ...)
|
|
- problèmes externes par instance (arrêts/relance serveurs, limites, ...)
|
|
- activité par instance (connexions clients), aussi bien lors de leur
|
|
établissement qu'à leur terminaison.
|
|
|
|
La possibilité de distribuer différents niveaux de logs à différents serveurs
|
|
permet à plusieurs équipes de production d'intéragir et de corriger leurs
|
|
problèmes le plus tôt possible. Par exemple, l'équipe système peut surveiller
|
|
occasionnellement les erreurs système, pendant que l'équipe application
|
|
surveille les alertes d'arrêts/démarrages de ses serveurs en temps réel, et
|
|
que l'équipe sécurité analyse l'activité en différé d'une heure.
|
|
|
|
|
|
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. Le nombre de sessions restantes après la
|
|
déconnexion est également indiqué (pour le serveur, l'instance et le process).
|
|
|
|
Exemple de journalisation TCP :
|
|
-------------------------------
|
|
listen relais-tcp 0.0.0.0:8000
|
|
mode tcp
|
|
option tcplog
|
|
log 192.168.2.200 local3
|
|
|
|
>>> haproxy[18989]: 127.0.0.1:34550 [15/Oct/2003:15:24:28] relais-tcp Srv1 0/0/5007 0 -- 1/1/1 0/0
|
|
|
|
Champ Format / Description Exemple
|
|
|
|
1 nom_processus '[' pid ']:' haproxy[18989]:
|
|
2 ip_client ':' port_client 127.0.0.1:34550
|
|
3 '[' date ']' [15/Oct/2003:15:24:28]
|
|
4 nom_instance relais-tcp
|
|
5 nom_serveur Srv1
|
|
6 temps_file '/' temps_connect '/' temps_total 0/0/5007
|
|
7 octets lus 0
|
|
8 etat_terminaison --
|
|
9 conn_srv '/' conns_inst '/' conns_processus 1/1/1
|
|
10 position en file d'attente srv '/' globale 0/0
|
|
|
|
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 de journalisation HTTP :
|
|
--------------------------------
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
option httplog
|
|
option dontlognull
|
|
log 192.168.2.200 local3
|
|
|
|
>>> haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 9/0/7/147/723 200 243 - - ---- 2/3/3 0/0 "HEAD / HTTP/1.0"
|
|
|
|
Exemple plus complet :
|
|
|
|
haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31] relais-http Srv1 3183/-1/-1/-1/11215 503 0 - - SC-- 137/202/205 0/0 {w.ods.org|Mozilla} {} "HEAD / HTTP/1.0"
|
|
|
|
Champ Format / Description Exemple
|
|
|
|
1 nom_processus '[' pid ']:' haproxy[18989]:
|
|
2 ip_client ':' port_client 10.0.0.1:34552
|
|
3 '[' date ']' [15/Oct/2003:15:26:31]
|
|
4 nom_instance relais-http
|
|
5 nom_serveur Srv1
|
|
6 Tq '/' Tw '/' Tc '/' Tr '/' Tt 3183/-1/-1/-1/11215
|
|
7 Code_retour_HTTP 503
|
|
8 octets lus 0
|
|
9 cookies_requête_capturés -
|
|
10 cookies_reponse_capturés -
|
|
11 etat_terminaison SC--
|
|
12 conns_srv '/' conns_inst '/' conns_processus 137/202/205
|
|
13 position file serveur '/' globale 0/0
|
|
14 '{' entetes_requête_capturés '}' {w.ods.org|Mozilla}
|
|
15 '{' entetes_reponse_capturés '}' {}
|
|
16 '"' requête_HTTP '"' "HEAD / HTTP/1.0"
|
|
|
|
Note pour les analyseurs de logs : l'URI est TOUJOURS le dernier champ de la ligne, et
|
|
commence par un guillemet '"'.
|
|
|
|
Le problème de loguer uniquement en fin de session, c'est qu'il est impossible
|
|
de savoir ce qui se passe durant de gros transferts ou des sessions longues.
|
|
Pour pallier à ce problème, une nouvelle option 'logasap' a été introduite dans
|
|
la version 1.1.28 (1.2.1). Lorsqu'elle est activée, le proxy loguera le plus
|
|
tôt possible, c'est à dire juste avant que ne débutent les transferts de
|
|
données. Cela signifie, dans le cas du TCP, qu'il loguera toujours le résultat
|
|
de la connexion vers le serveur, et dans le cas HTTP, qu'il loguera en fin de
|
|
traitement des en-têtes de la réponse du serveur, auquel cas le nombre d'octets
|
|
représentera la taille des en-têtes retournés au client.
|
|
|
|
Afin d'éviter toute confusion avec les logs normaux, le temps total de
|
|
transfert et le nombre d'octets transférés sont préfixés d'un signe '+'
|
|
rappelant que les valeurs réelles sont certainement plus élevées.
|
|
|
|
Exemple :
|
|
---------
|
|
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
option httplog
|
|
option dontlognull
|
|
option logasap
|
|
log 192.168.2.200 local3
|
|
|
|
>>> haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/7/14/+30 200 +243 - - ---- 3/3 "GET /image.iso HTTP/1.0"
|
|
|
|
|
|
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/Tw/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.
|
|
|
|
- Tw: temps total passé dans les files d'attente avant d'obtenir une place
|
|
vers un serveur. Ceci tient compte à la fois de la file d'attente globale
|
|
et de celle du serveur, et dépend du nombre de requêtes dans la file et du
|
|
temps nécessaire au serveur pour compléter les sessions précédentes. La
|
|
valeur '-1' indique que la requête a été détruite avant d'atteindre une
|
|
file.
|
|
|
|
- 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 en-tê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'en-tê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). La signification change
|
|
un peu si l'option 'logasap' est présente. Dans ce cas, le temps correspond
|
|
uniquement à (Tq + Tw + Tc + Tr), et se trouve préfixé d'un signe '+'. On
|
|
peut donc déduire Td, le temps de transfert des données, en excluant les
|
|
autres temps :
|
|
|
|
Td = Tt - (Tq + Tw + Tc + Tr)
|
|
|
|
Les temps rapportés à '-1' sont simplement à éliminer de cette équation.
|
|
|
|
En mode TCP ('option tcplog'), seuls les deux indicateurs Tw, 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/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/xx/Tt: Il n'était pas possible de traiter la request, probablement
|
|
parce que tous les serveurs étaient hors d'usage.
|
|
Tq/Tw/-1/xx/Tt: la connexion n'a pas pu s'établir vers le serveur (refus ou
|
|
time-out au bout de Tt-(Tq+Tw) ms).
|
|
Tq/Tw/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+Tw+Tc) ms.
|
|
|
|
4.2.4) Conditions de déconnexion
|
|
--------------------------------
|
|
Les logs TCP et HTTP fournissent un indicateur de complétude de la session dans
|
|
le champ 'etat_terminaison', juste avant le nombre de connexions actives. C'est
|
|
un champ long de 2 caractères en TCP et de 4 caractères en HTTP, chacun ayant
|
|
une signification précise :
|
|
|
|
- sur le premier caractère, un code précisant le premier événement qui a causé
|
|
la terminaison de la session :
|
|
|
|
C : fermeture inattendue de la session TCP de la part du client.
|
|
|
|
S : fermeture inattendue de la session TCP de la part du serveur, ou
|
|
refus explicite de connexion de la part de ce dernier.
|
|
|
|
P : terminaison prématurée des sessions par le proxy, pour cause
|
|
d'imposition d'une limite sur le nombre de connexions, pour cause
|
|
de configuration (ex: filtre d'URL), ou parce qu'un contrôle de
|
|
sécurité a détecté et bloqué une anomalie dans la réponse du
|
|
serveur qui aurait pu causer une fuite d'informations (par exemple,
|
|
un cookie cachable).
|
|
|
|
R : une ressource sur le proxy a été épuisée (mémoire, sockets, ports
|
|
source, ...). Généralement, cela arrive au cours de l'établissement
|
|
d'une connexion, et les logs système doivent contenir une copie de
|
|
l'érreur précise.
|
|
|
|
I : une erreur interne a été identifiée par le proxy à la suite d'un
|
|
auto-contrôle. Ceci ne doit JAMAIS arriver, et vous êtes encouragés
|
|
à remonter n'importe quel log contenant ceci car il s'agira un bug.
|
|
|
|
c : le délai maximal d'attente du client a expiré (clitimeout).
|
|
|
|
s : le délai maximal d'attente du serveur a expiré (srvtimeout et contimeout)
|
|
|
|
- : terminaison normale de session.
|
|
|
|
- sur le second caractère, l'état d'avancement de la session TCP/HTTP lors de
|
|
la fermeture :
|
|
|
|
R : attente d'une REQUETE HTTP complète de la part du client. Rien n'a
|
|
été transmis au serveur.
|
|
|
|
Q : attente en file d'attente (QUEUE) d'une place pour avoir une
|
|
connexion vers un serveur. Ne peut apparaître que sur un serveur
|
|
possédant un paramètre 'maxconn'. Aucune connexion n'a été envoyée
|
|
au serveur.
|
|
|
|
C : attente de l'établissement d'une CONNEXION vers le serveur. Le
|
|
serveur peut au plus avoir vu la tentative de connexion, mais
|
|
aucune donnée n'a été échangée.
|
|
|
|
H : attente, réception ou traitement des en-têtes HTTP ("HEADERS").
|
|
|
|
D : transfert des DONNEES du serveur vers le client.
|
|
|
|
L : transfert des dernières ("LAST") données du proxy vers le client,
|
|
alors que le serveur a déjà fini.
|
|
|
|
T : requête bloquée en mode "tarpit" par le proxy. Elle a été maintenue
|
|
ouverte vers le client pendant toute la durée du contimeout ou
|
|
jusqu'à l'abandon de la part du client.
|
|
|
|
- : 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é. C'est généralement le
|
|
cas sur les NOUVELLES connexions clients.
|
|
|
|
I : le client a présenté un cookie INVALIDE ne correspondant à aucun
|
|
serveur connu. Ceci peut être dû à un changement de configuration
|
|
récent, à des mélanges de noms de cookies entre sites HTTP/HTTPS,
|
|
ou à une attaque.
|
|
|
|
D : le client a présenté un cookie correspondant à un serveur hors
|
|
d'usage ("DOWN"). 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 (pas de cookie positionné dans la configuration).
|
|
|
|
- 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 persistance n'a été fourni par le serveur, et aucun
|
|
n'a été inséré.
|
|
|
|
I : aucun cookie de persistance n'a été fourni par le serveur, et le
|
|
proxy en a INSERE un.
|
|
|
|
P : un cookie de persistence a été fourni par le serveur et transmis
|
|
tel quel ("PASSIF").
|
|
|
|
R : le cookie retourné par le serveur a été REECRIT par le proxy.
|
|
|
|
D : le cookie présenté par le serveur a été DETRUIT par le proxy pour
|
|
ne pas être retourné au client.
|
|
|
|
- : non appliquable
|
|
|
|
|
|
La combinaison des deux premiers indicateurs fournit une grande quantitié
|
|
d'informations sur ce qui se passait lorsque la session s'est terminée. Cela
|
|
peut notamment aider à détecter une saturation de serveur, des troubles réseau,
|
|
des épuisements de ressources système locales, des attaques, etc...
|
|
|
|
Les combinaisons d'indicateurs les plus fréquentes sont énumérées ici.
|
|
|
|
Indic Raison
|
|
CR Le client a abandonné avant d'émettre une requête complète. Il est
|
|
très probable que la requête ait été tapée à la main dans un client
|
|
telnet et abortée trop tôt.
|
|
|
|
cR Le temps imparti au client a expiré avant réception d'une requête
|
|
complète. Ceci est parfois causé par un paramètre TCP MSS trop élevé
|
|
sur le client pour des réseaux PPPoE sur ADSL qui ne peuvent pas
|
|
transporter des paquets entiers, ou par des clients qui énvoient des
|
|
requêtes à la main et ne tapent pas assez vite.
|
|
|
|
SC Le serveur a explicitement refusé la connexion (le proxy a reçu un
|
|
RST TCP ou un message ICMP en retour). Dans certains cas, cela peut
|
|
être la couche réseau qui indique au proxy que le serveur n'est pas
|
|
joignable (p.ex: pas de route, pas de réponse ARP en local, etc...)
|
|
|
|
sC La connexion au serveur n'a pas pu s'établir dans le temps imparti.
|
|
|
|
PC Le proxy a refusé d'établir une connexion au serveur parce que le
|
|
nombre de connexions a atteint la limite 'maxconn' (global ou de
|
|
l'instance). Le paramètre 'maxconn' de l'instance pourrait être
|
|
augmenté, tout comme le paramètre 'maxconn' global.
|
|
|
|
RC Une ressource locale a été épuisée (mémoire, sockets, ports source),
|
|
empêchant la connexion au serveur de s'établir. Les logs d'erreurs
|
|
diront précisément ce qui manquait. Dans tous les cas, le seul remède
|
|
consiste à affiner le paramétrage système.
|
|
|
|
cH Le temps imparti au client a expiré au cours d'une requête POST. Ceci
|
|
est parfois causé par un paramètre TCP MSS trop élevé sur le client
|
|
pour des réseaux PPPoE sur ADSL qui ne peuvent pas transporter des
|
|
paquets entiers.
|
|
|
|
CH Le client a abandonné alors qu'il attendait un début de réponse de la
|
|
part du serveur. Cela peut être causé par le serveur qui mettait trop
|
|
de temps à répondre, ou par un client cliquant précipitamment sur le
|
|
bouton 'Stop'.
|
|
|
|
CQ Le client a abandonné alors que sa session était mise en file
|
|
d'attente pour obtenir un serveur avec suffisamment de connexions
|
|
libres pour l'accepter. Cela signifie soit que l'ensemble des
|
|
serveurs étaient saturés, soit que le serveur assigné a mis trop de
|
|
temps à répondre.
|
|
|
|
CT Le client a abandonné alors que sa session était bloquée en mode
|
|
tarpit.
|
|
|
|
sQ La session a attendu trop longtemps en file d'attente et a été
|
|
expirée.
|
|
|
|
SH Le serveur a aborté brutalement alors qu'il devait envoyer ses
|
|
en-têtes. En général, cela indique qu'il a crashé.
|
|
|
|
sH Le serveur n'a pas pu répondre durant le temps imparti, ce qui montre
|
|
des transactions trop longues, probablement causées par un back-end
|
|
saturé. Les seules solutions sont de corriger le problème sur
|
|
l'application, d'accroître le paramètre 'srvtimeout' pour supporter
|
|
des attentes plus longues au risque que les clients abandonnent à
|
|
leur tour, ou bien d'ajouter des serveurs.
|
|
|
|
PR Le proxy a bloqué une requête du client, soit à cause d'une syntaxe
|
|
HTTP invalide, auquel cas il a renvoyé une erreur HTTP 400 au client,
|
|
soit à cause d'une requête validant un filtre d'interdiction, auquel
|
|
cas le proxy a renvoyé une erreur HTTP 403.
|
|
|
|
PH Le proxy a bloqué la réponse du serveur parce qu'elle était invalide,
|
|
incomplète, dangereuse ('cache control'), ou parce qu'elle validait
|
|
un filtre de sécurité. Dans tous les cas, une erreur HTTP 502 est
|
|
renvoyée au client.
|
|
|
|
PT Le proxy a bloqué une requête du client et a maintenu sa connection
|
|
ouverte avant de lui retourner une erreur "500 server error". Rien
|
|
n'a été envoyé au serveur.
|
|
|
|
cD Le client n'a pas lu de données pendant le temps qui lui était
|
|
imparti. Ceci est souvent causé par des problèmes réseau côté client.
|
|
|
|
CD Le client a aborté sa connection de manière inattendue pendant le
|
|
transfert des données. Ceci est provoqué soit par le crash d'un
|
|
navigateur, ou par une session en HTTP keep-alive entre le serveur
|
|
et le client terminée en premier par le client.
|
|
|
|
sD Le serveur n'a rien fait durant le temps imparti par le paramètre
|
|
'srvtimeout'. Ceci est souvent causé par des timeouts trop courts
|
|
sur des équipements de niveau 4 (firewalls, répartiteurs de charge)
|
|
situés entre le proxy et le serveur.
|
|
|
|
4.2.5) Caractères non-imprimables
|
|
---------------------------------
|
|
Depuis la version 1.1.29, les caractères non-imprimables ne sont plus envoyés
|
|
tels quels dans les lignes de logs, mais inscrits sous la forme de deux chiffres
|
|
hexadécimaux, préfixés du caractère d'échappement '#'. Les seuls caractères
|
|
dorénavant logués tels quels sont compris entre 32 et 126. Bien évidemment, le
|
|
caractère d'échappement '#' est lui-même encodé afin de lever l'ambiguité. Il en
|
|
est de même pour le caractère '"', ainsi que les caractères '{', '|' et '}' pour
|
|
les en-têtes.
|
|
|
|
4.2.6) Capture d'en-têtes HTTP et de cookies
|
|
--------------------------------------------
|
|
La version 1.1.23 a apporté la capture des cookies, et la version 1.1.29 la
|
|
capture d'en-têtes. Tout ceci est effectué en utilisant le mot-clé 'capture'.
|
|
|
|
Les captures de cookies facilitent le suivi et la reconstitution d'une session
|
|
utilisateur. La syntaxe est la suivante :
|
|
|
|
capture cookie <préfixe_cookie> len <longueur_capture>
|
|
|
|
Ceci activera la capture de cookies à la fois dans les requêtes et dans les
|
|
réponses. De cette manière, il devient facile de détecter lorsqu'un utilisateur
|
|
bascule sur une nouvelle session par exemple, car le serveur lui réassignera un
|
|
nouveau cookie.
|
|
|
|
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, ou lorsque l'option est désactivée..
|
|
|
|
Les captures d'en-têtes ont un rôle complètement différent. Elles sont utiles
|
|
pour suivre un identifiant de requête globalement unique positionné par un
|
|
autre proxy en amont, pour journaliser les noms de serveurs virtuels, les types
|
|
de clients web, la longueur des POST, les 'referrers', etc. Dans la réponse, on
|
|
peut chercher des informations relatives à la longueur annoncée de la réponse,
|
|
le fonctionnement attendu du cache, ou encore la localisation d'un objet en cas
|
|
de redirection. Tout comme pour les captures de cookies, il est possible
|
|
d'inclure les en-têtes de requêtes et de réponse simultanément. La syntaxe est
|
|
la suivante :
|
|
|
|
capture request header <nom> len <longueur max>
|
|
capture response header <nom> len <longueur max>
|
|
|
|
Note: Les noms d'en-têtes ne sont pas sensibles à la casse.
|
|
|
|
Exemples:
|
|
---------
|
|
# conserver le nom du serveur virtuel accédé par le client
|
|
capture request header Host len 20
|
|
# noter la longueur des données envoyées dans un POST
|
|
capture request header Content-Length len 10
|
|
|
|
# noter le fonctionnement attendu du cache par le serveur
|
|
capture response header Cache-Control len 8
|
|
# noter l'URL de redirection
|
|
capture response header Location len 20
|
|
|
|
Les en-têtes non trouvés sont logués à vide, et si un en-tête apparait plusieurs
|
|
fois, seule la dernière occurence sera conservée. Les en-têtes de requête sont
|
|
regroupés entre deux accolades '{' et '}' dans l'ordre de leur déclaration, et
|
|
chacun séparés par une barre verticale '|', sans aucun espace. Les en-têtes de
|
|
réponse sont présentés de la même manière, mais après un espace suivant le bloc
|
|
d'en-tête de requête. Le tout précède la requête HTTP. Exemple :
|
|
|
|
Config:
|
|
|
|
capture request header Host len 20
|
|
capture request header Content-Length len 10
|
|
capture request header Referer len 20
|
|
capture response header Server len 20
|
|
capture response header Content-Length len 10
|
|
capture response header Cache-Control len 8
|
|
capture response header Via len 20
|
|
capture response header Location len 20
|
|
|
|
Log :
|
|
|
|
Aug 9 20:26:09 localhost haproxy[2022]: 127.0.0.1:34014 [09/Aug/2004:20:26:09] relais-http netcache 0/0/0/162/+162 200 +350 - - ---- 0/0/0 0/0 {fr.adserver.yahoo.co||http://fr.f416.mail.} {|864|private||} "GET http://fr.adserver.yahoo.com/"
|
|
Aug 9 20:30:46 localhost haproxy[2022]: 127.0.0.1:34020 [09/Aug/2004:20:30:46] relais-http netcache 0/0/0/182/+182 200 +279 - - ---- 0/0/0 0/0 {w.ods.org||} {Formilux/0.1.8|3495|||} "GET http://w.ods.org/sytadin.html HTTP/1.1"
|
|
Aug 9 20:30:46 localhost haproxy[2022]: 127.0.0.1:34028 [09/Aug/2004:20:30:46] relais-http netcache 0/0/2/126/+128 200 +223 - - ---- 0/0/0 0/0 {www.infotrafic.com||http://w.ods.org/syt} {Apache/2.0.40 (Red H|9068|||} "GET http://www.infotrafic.com/images/live/cartesidf/grandes/idf_ne.png HTTP/1.1"
|
|
|
|
4.2.7) Exemples de logs
|
|
-----------------------
|
|
- haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 6559/0/7/147/6723 200 243 - - ---- 1/3/5 0/0"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[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 6559/1230/7/147/6870 200 243 - - ---- 99/239/324 0/9 "HEAD / HTTP/1.0"
|
|
=> Idem, mais la requête a été mise en attente dans la file globale derrière
|
|
9 autres requêtes déjà présentes, et y a attendu 1230 ms.
|
|
|
|
- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/0/7/14/+30 200 +243 - - ---- 1/3/3 0/0 "GET /image.iso HTTP/1.0"
|
|
=> requête pour un long transfert. L'option 'logasap' était spécifiée donc le
|
|
log a été généré juste avant le transfert de données. Le serveur a répondu
|
|
en 14 ms, 243 octets d'en-têtes ont été transférés au client, et le temps
|
|
total entre l'accept() et le premier octet de donnée est de 30 ms.
|
|
|
|
- haproxy[674]: 127.0.0.1:33320 [15/Oct/2003:08:32:17] relais-http Srv1 9/0/7/14/30 502 243 - - PH-- 0/2/3 0/0 "GET /cgi-bin/bug.cgi? HTTP/1.0"
|
|
=> le proxy a bloqué une réponse du serveur soit à cause d'un filtre 'rspdeny'
|
|
ou 'rspideny', soit parce qu'il a détecté un risque de fuite sensible
|
|
d'informations risquant d'être cachées. Dans ce cas, la réponse est
|
|
remplacée par '502 bad gateway'.
|
|
|
|
- haproxy[18113]: 127.0.0.1:34548 [15/Oct/2003:15:18:55] relais-http <NOSRV> -1/-1/-1/-1/8490 -1 0 - - CR-- 0/2/2 0/0 ""
|
|
=> 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'en-tê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/-1/50001 408 0 - - cR-- 0/2/2 0/0 ""
|
|
=> 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'en-tê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 ('cD') au bout de
|
|
5s.
|
|
|
|
- haproxy[18989]: 10.0.0.1:34552 [15/Oct/2003:15:26:31] relais-http Srv1 3183/-1/-1/-1/11215 503 0 - - SC-- 115/202/205 0/0 "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. Il y avait 115 connexions sur ce serveur, 202 connexions sur cette
|
|
instance, et 205 sur l'ensemble des instances pour ce processus. Il est
|
|
possible que le serveur ait refusé la connexion parce qu'il y en avait
|
|
déjà trop d'établies.
|
|
|
|
|
|
4.3) Modification des en-tê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 en-tête valide <search>
|
|
reqiallow <search> idem sans distinction majuscules/minuscules
|
|
reqdeny <search> interdire la requête si un en-tête valide <search>
|
|
reqideny <search> idem sans distinction majuscules/minuscules
|
|
reqpass <search> inhibe ces actions sur les en-têtes validant <search>
|
|
reqipass <search> idem sans distinction majuscules/minuscules
|
|
reqtarpit <search> bloquer et maintenir une request validant <search>
|
|
reqitarpit <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
|
|
rspdeny <search> remplace la réponse par un HTTP 502 si un
|
|
en-tête valide <search>
|
|
rspideny <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 0 à 9, et sont codées par un '\'
|
|
suivi du chiffre désiré (0 désignant la ligne complète). 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
|
|
en-têtes inutiles avant les ajouts.
|
|
- une requête bloquée produira une réponse "HTTP 403 forbidden" tandis qu'une
|
|
réponse bloquée produira une réponse "HTTP 502 Bad gateway".
|
|
- une requête bloquée par 'reqtarpit' sera maintenue pendant une durée égale
|
|
au paramètre 'contimeout', ou jusqu'à l'abandon du client. Rien ne sera
|
|
envoyé au serveur. Lorsque le temps alloué expire, le proxy répondra avec
|
|
une réponse "500 server error" de sorte que l'attaquant ne suspecte pas
|
|
qu'il ait été bloqué. Les logs rapporteront aussi ce code 500, mais les
|
|
flags de terminaison indiqueront "PT".
|
|
|
|
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\?)
|
|
|
|
# tarpit attacks on the login page.
|
|
reqtarpit ^[^:\ ]*\ .*\.php?login=[^0-9]
|
|
|
|
# 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
|
|
option httpclos
|
|
|
|
# change the server name
|
|
rspidel ^Server:\
|
|
rspadd Server:\ Formilux/0.1.8
|
|
|
|
|
|
De plus, 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. Depuis la version 1.3.8, il est
|
|
possible de préciser le mot-clé "except" suivi d'une adresse ou un réseau
|
|
IP source pour lequel l'entête ne sera pas ajouté. C'est très pratique dans le
|
|
cas où un autre reverse-proxy ajoutant déjà l'entête est installé sur la même
|
|
machine ou dans une DMZ connue. Le cas le plus fréquent est lié à l'utilisation
|
|
de stunnel en local.
|
|
|
|
Enfin, l'option 'httpclose' apparue dans la version 1.1.28/1.2.1 supprime tout
|
|
en-tête de type 'Connection:' et ajoute 'Connection: close' dans les deux sens.
|
|
Ceci simplifie la désactivation du keep-alive HTTP par rapport à l'ancienne
|
|
méthode impliquant 4 règles.
|
|
|
|
Exemple :
|
|
---------
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
log global
|
|
option httplog
|
|
option dontlognull
|
|
option forwardfor except 127.0.0.1/8
|
|
option httpclose
|
|
|
|
Notons que certains serveurs HTTP ne referment pas nécessairement la session
|
|
TCP en fin de traitement lorsqu'ils reçoivent un entête 'Connection: close',
|
|
ce qui se traduit par des grands nombres de sessions établies et des temps
|
|
globaux très longs sur les requêtes. Pour contourner ce problème, la version
|
|
1.2.9 apporte une nouvelle option 'forceclose' qui referme la connexion sortant
|
|
vers le serveur dès qu'il commence à répondre et seulement si le tampon de
|
|
requête est vide. Attention toutefois à ne PAS utiliser cette option si des
|
|
méthodes CONNECT sont attendues entre le client et le serveur. L'option
|
|
'forceclose' implique l'option 'httpclose'.
|
|
|
|
Exemple :
|
|
---------
|
|
listen http_proxy 0.0.0.0:80
|
|
mode http
|
|
log global
|
|
option httplog
|
|
option dontlognull
|
|
option forwardfor
|
|
option forceclose
|
|
|
|
|
|
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 srv1 192.168.1.1:80 cookie server01 check
|
|
server srv2 192.168.1.2:80 cookie server02 check
|
|
|
|
L'autre solution apportée par les versions 1.1.30 et 1.2.3 est de réutiliser un
|
|
cookie en provenance du serveur et de lui préfixer l'identifiant du serveur.
|
|
Dans ce cas, ne pas oublier de forcer le mode "httpclose" pour empêcher le
|
|
client et le serveur de travailler en mode "keep-alive" afin que le proxy
|
|
puisse corriger le nom du cookie dans toutes les futures requêtes.
|
|
|
|
listen application 0.0.0.0:80
|
|
mode http
|
|
cookie JSESSIONID prefix
|
|
balance roundrobin
|
|
server srv1 192.168.1.1:80 cookie srv1 check
|
|
server srv2 192.168.1.2:80 cookie srv2 check
|
|
option httpclose
|
|
|
|
|
|
4.5) Protection contre les fuites d'informations du serveur
|
|
-----------------------------------------------------------
|
|
Dans les versions 1.1.28 et 1.2.1, une nouvelle option 'checkcache' a été
|
|
créée. Elle sert à inspecter minutieusement les en-têtes 'Cache-control',
|
|
'Pragma', et 'Set-cookie' dans les réponses serveur pour déterminer s'il y a
|
|
un risque de cacher un cookie sur un proxy côté client. Quand cette option est
|
|
activée, les seules réponses qui peuvent être retournées au client sont :
|
|
- toutes celles qui n'ont pas d'en-tête 'Set-cookie' ;
|
|
- toutes celles qui ont un code de retour autre que 200, 203, 206, 300, 301,
|
|
410, sauf si le serveur a positionné un en-tête 'Cache-control: public' ;
|
|
- celles qui font suite à une requête POST, sauf si le serveur a positionné
|
|
un en-tête 'Cache-control: public' ;
|
|
- celles qui ont un en-tête 'Pragma: no-cache' ;
|
|
- celles qui ont un en-tête 'Cache-control: private' ;
|
|
- celles qui ont un en-tête 'Cache-control: no-store' ;
|
|
- celles qui ont un en-tête 'Cache-control: max-age=0' ;
|
|
- celles qui ont un en-tête 'Cache-control: s-maxage=0' ;
|
|
- celles qui ont un en-tête 'Cache-control: no-cache' ;
|
|
- celles qui ont un en-tête 'Cache-control: no-cache="set-cookie"' ;
|
|
- celles qui ont un en-tête 'Cache-control: no-cache="set-cookie,'
|
|
(autorisant d'autres champs après set-cookie).
|
|
|
|
Si une réponse ne respecte pas ces pré-requis, alors elle sera bloquée de la
|
|
même manière que s'il s'agissait d'un filtre 'rspdeny', avec en retour un
|
|
message "HTTP 502 bad gateway". L'état de session montre "PH--" ce qui veut
|
|
dire que c'est le proxy qui a bloqué la réponse durant le traitement des
|
|
en-têtes. De plus, un message d'alerte sera envoyé dans les logs de sorte que
|
|
l'administrateur sache qu'il y a une action correctrice à entreprendre.
|
|
|
|
4.6) 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 de deux manières, l'une reposant sur
|
|
une redirection vers un serveur connu, et l'autre consistant à retourner un
|
|
fichier local.
|
|
|
|
4.6.1) Redirection
|
|
------------------
|
|
Une redirection d'erreur est assurée 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
|
|
|
|
Note: la RFC2616 stipule qu'un client doit réutiliser la même méthode pour
|
|
accéder à l'URL de redirection que celle qui l'a retournée, ce qui pose des
|
|
problèmes avec les requêtes POST. Le code de retour 303 a été créé exprès pour
|
|
régler ce problème, indiquant au client qu'il doit accéder à l'URL retournée
|
|
dans le champ Location avec la méthode GET uniquement. Seulement, certains
|
|
navigateurs antérieurs à HTTP/1.1 ne connaissent pas ce code de retour. De
|
|
plus, la plupart des navigateurs se comportent déjà avec le code 302 comme ils
|
|
devraient le faire avec le 303. Donc, dans le but de laisser le choix à
|
|
l'utilisateur, les versions 1.1.31 et 1.2.5 apportent deux nouvelles commandes
|
|
visant à remplacer 'errorloc' : 'errorloc302' et 'errorloc303'.
|
|
|
|
Leur usage non ambigü est recommandé à la place de la commande 'errorloc' (qui
|
|
utilise toujours 302). Dans le doute, préférez l'utilisation de 'errorloc303'
|
|
dès que vous savez que vos clients supportent le code de retour HTTP 303.
|
|
|
|
4.6.2) Fichiers locaux
|
|
----------------------
|
|
Parfois il est souhaitable de changer l'erreur retournée sans recourir à des
|
|
redirections. La seconde méthode consiste à charger des fichiers locaux lors
|
|
du démarrage et à les envoyer en guise de pur contenu HTTP en cas d'erreur.
|
|
C'est ce que fait le mot clé 'errorfile'.
|
|
|
|
Attention, il y a des pièges à prendre en compte :
|
|
- les fichiers sont chargés durant l'analyse de la configuration, avant de
|
|
faire le chroot(). Donc ils sont relatifs au système de fichiers réel. Pour
|
|
cette raison, il est recommandé de toujours passer un chemin absolu vers ces
|
|
fichiers.
|
|
|
|
- le contenu de ces fichiers n'est pas du HTML mais vraiment du protocole HTTP
|
|
avec potentiellement un corps HTML. Donc la première ligne et les en-têtes
|
|
sont obligatoires. Idéalement, chaque ligne dans la partie HTTP devrait se
|
|
terminer par un CR-LF pour un maximum de compatibilité.
|
|
|
|
- les réponses sont limitées à une taille de buffer (BUFSIZE), généralement 8
|
|
ou 16 ko.
|
|
|
|
- les réponses ne devraient pas inclure de références aux serveurs locaux,
|
|
afin de ne pas risquer de créer des boucles infinies sur le navigateur dans
|
|
le cas d'une panne locale.
|
|
|
|
Exemple :
|
|
---------
|
|
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
|
|
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
|
|
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
|
|
|
|
|
|
4.7) 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.28/1.2.1, 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, logasap, httpclose,
|
|
checkcache, httplog, tcplog, 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.
|
|
|
|
|
|
4.8) Rapport d'état sous forme de page HTML
|
|
-------------------------------------------
|
|
Avec la version 1.2.14, il devient possible pour haproxy d'interceptre des
|
|
requêtes pour une URI particulière et de retourner un rapport complet d'état de
|
|
l'activité du proxy, et des statistiques sur les serveurs. Ceci est disponible
|
|
via le mot clé "stats" associé à n'importe laquelle de ces options :
|
|
|
|
- stats enable
|
|
- stats uri <uri prefix>
|
|
- stats realm <authentication realm>
|
|
- stats auth <user:password>
|
|
- stats scope <proxy_id> | '.'
|
|
|
|
|
|
Par défaut, le rapport est désactivé. Le fait de spécifier une des combinaision
|
|
ci-dessus active le rapport pour l'instance de proxy qui le référence. La
|
|
solution la plus simple est d'utiliser "stats enable" qui activera le rapport
|
|
avec les paramètres par défaut suivant :
|
|
|
|
- default URI : "/haproxy?stats" (CONFIG_STATS_DEFAULT_URI)
|
|
- default auth : non spécifié (pas d'authentication)
|
|
- default realm : "HAProxy Statistics" (CONFIG_STATS_DEFAULT_REALM)
|
|
- default scope : non specifié (accès à toutes les instances)
|
|
|
|
L'option "stats uri <uri_prefix>" permet d'intercepter un autre préfixe d'URI
|
|
que celui par défaut. Noter que n'importe quelle URI qui COMMENCE avec cette
|
|
chaîne sera validée. Par exemple, une instance pourrait être dédiée à la page
|
|
d'état seulement et répondre à toute URI.
|
|
|
|
Example :
|
|
---------
|
|
# intercepte n'importe quelle URI et retourne la page d'état.
|
|
listen stats :8080
|
|
mode http
|
|
stats uri /
|
|
|
|
|
|
L'option "stats auth <user:password>" active l'authentification "Basic" et
|
|
ajoute un couple "user:password" valide à la liste des comptes autorisés.
|
|
L'utilisateur <user> et le mot de passe <password> doivent être précisés
|
|
en clair dans le fichier de configuration, et comme ceci est de
|
|
l'authentification HTTP "Basic", il faut être conscient qu'ils transitent en
|
|
clair sur le réseau, donc il ne faut pas utiliser de compte sensible. La liste
|
|
est illimitée dans le but de pouvoir fournir des accès facilement à des
|
|
développeurs ou à des clients.
|
|
|
|
L'option "stats realm <realm>" définit le "domaine" ("realm") de validité du
|
|
mot de passe qui sera présenté dans la boîte de dialogue du navigateur
|
|
lorsqu'il demandera un compte utilisateur et un mot de passe. Il est important
|
|
de s'assurer que celui-ci soit différent de ceux utilisés par l'application,
|
|
autrement le navigateur tentera d'en utiliser un caché depuis l'application.
|
|
Noter que les espaces dans le nom de "realm" doivent être protégés par un
|
|
backslash ('\').
|
|
|
|
L'option "stats scope <proxy_id>" limite la portée du rapport d'état. Par
|
|
défaut, toutes les instances proxy sont listées. Mais dans certaines
|
|
circonstances, il serait préférable de ne lister que certains proxies ou
|
|
simplement le proxy courant. C'est ce que fait cette option. Le nom spécial "."
|
|
(un simple point) référence le proxy courant. Cette option peut être répétée
|
|
autant de fois que nécessaire pour autoriser d'autres proxies, même pour des
|
|
noms référencés plus loin dans la configuration ou bien des noms qui n'existent
|
|
pas encore. Le nom précisé est celui qui apparait après le mot clé "listen".
|
|
|
|
Exemple :
|
|
---------
|
|
# simple application embarquant la page d'état authentifiée
|
|
listen app1 192.168.1.100:80
|
|
mode http
|
|
option httpclose
|
|
balance roundrobin
|
|
cookie SERVERID postonly insert indirect
|
|
server srv1 192.168.1.1:8080 cookie srv1 check inter 1000
|
|
server srv1 192.168.1.2:8080 cookie srv2 check inter 1000
|
|
stats uri /my_stats
|
|
stats realm Statistics\ for\ MyApp1-2
|
|
stats auth guest:guest
|
|
stats auth admin:AdMiN123
|
|
stats scope .
|
|
stats scope app2
|
|
|
|
# simple application embarquant la page d'état sans authentification
|
|
listen app2 192.168.2.100:80
|
|
mode http
|
|
option httpclose
|
|
balance roundrobin
|
|
cookie SERVERID postonly insert indirect
|
|
server srv1 192.168.2.1:8080 cookie srv1 check inter 1000
|
|
server srv1 192.168.2.2:8080 cookie srv2 check inter 1000
|
|
stats uri /my_stats
|
|
stats realm Statistics\ for\ MyApp2
|
|
stats scope .
|
|
|
|
listen admin_page :8080
|
|
mode http
|
|
stats uri /my_stats
|
|
stats realm Global\ statistics
|
|
stats auth admin:AdMiN123
|
|
|
|
Notes :
|
|
-------
|
|
- les options "stats" peuvent aussi être spécifiées dans une section
|
|
"defaults", auquel cas la même configuration exactement sera fournie à
|
|
toutes les instances suivantes, d'où l'utilité du scope ".". Toutefois, si
|
|
une instance redéfinit n'importe quel paramètre "stats", alors les défauts
|
|
ne lui seront pas appliqués.
|
|
|
|
- l'authentification "Basic" est très simpliste et non sécurisée contre la
|
|
capture réseau. Aucun mot de passe sensible ne doit être utilisé, et il
|
|
est bon de savoir qu'il n'existe pas de moyen de le supprimer du navigateur
|
|
après usage, donc il sera envoyé tel quel à l'application au cours des
|
|
accès successifs.
|
|
|
|
- Il est très important de préciser l'option "httpclose", sinon le proxy ne
|
|
sera pas en mesure de détecter les URI dans les sessions keep-alive
|
|
maintenues entre le navigateur et les serveurs, donc les URI de stats
|
|
seront transmises telles quelles aux serveurs comme si l'option n'était
|
|
pas précisée.
|
|
|
|
|
|
5) Listes d'accès
|
|
=================
|
|
|
|
Avec la version 1.3.10, un nouveau concept de listes d'accès (ACL) a vu le
|
|
jour. Comme il n'était pas nécessaire de réinventer la roue, et du fait que
|
|
toutes les réflexions passées aboutissaient à des propositions non
|
|
satisfaisantes, il a finalement été décidé que quelque chose de proche de ce
|
|
que Squid offre serait un bon compromis entre une richesse fonctionnelle et une
|
|
facilité d'utilisation
|
|
|
|
Le principe est très simple : les ACLs sont déclarées avec un nom, un test et
|
|
une liste de valeurs valides à tester. Des conditions sont appliquées sur
|
|
diverses actions, et ces conditions effectuent un ET logique entre les ACLs. La
|
|
condition n'est donc validée que si toutes les ACLs sont vraies.
|
|
|
|
Il est également possible d'utiliser le mot réservé "OR" dans les conditions,
|
|
et il est possible pour une ACL d'être spécifiée plusieurs fois, même avec des
|
|
tests différents, auquel cas le premier test réussi validera l'ACL.
|
|
|
|
Au stade de la version 1.3.12, seuls les tests suivants ont été implémentés :
|
|
|
|
Niveaux 3/4 :
|
|
src <ipv4_address>[/mask] ... : match IPv4 source address
|
|
dst <ipv4_address>[/mask] ... : match IPv4 destination address
|
|
src_port <range> ... : match source port range
|
|
dst_port <range> ... : match destination port range
|
|
dst_conn <range> ... : match #connections on frontend
|
|
|
|
Niveau 7 :
|
|
method <HTTP method> ... : match HTTP method
|
|
req_ver <1.0|1.1> ... : match HTTP request version
|
|
resp_ver <1.0|1.1> ... : match HTTP response version
|
|
status <range> ... : match HTTP response status code in range
|
|
url <string> ... : exact string match on URI
|
|
url_reg <regex> ... : regex string match on URI
|
|
url_beg <string> ... : true if URI begins with <string>
|
|
url_end <string> ... : true if URI ends with <string>
|
|
url_sub <string> ... : true if URI contains <string>
|
|
url_dir <string> ... : true if URI contains <string> between slashes
|
|
url_dom <string> ... : true if URI contains <string> between slashes or dots
|
|
|
|
Une plage ('range') est constituée d'un ou deux entiers qui peuvent être
|
|
préfixés d'un opérateur. La syntaxe est :
|
|
|
|
[<op>] <min>[:<max>]
|
|
|
|
Avec <op> pouvant être :
|
|
'eq' : la valeur doit égaler <min> ou être comprise entre <min> et <max>
|
|
'le' : la valeur doit être inférieure ou égale à <min>
|
|
'lt' : la valeur doit être strictement inférieure à <min>
|
|
'ge' : la valeur doit être supérieure ou égale à <min>
|
|
'gt' : la valeur doit être strictement supérieure à <min>
|
|
|
|
Lorsqu'aucun opérateur n'est défini, 'eq' est employé. Noter que lorsqu'un
|
|
opérateur est spécifié, il s'applique à toutes les plages de valeurs suivantes
|
|
jusqu'à la fin de la ligne ou bien jusqu'à ce qu'un nouvel opérateur soit
|
|
précisé. Exemple :
|
|
|
|
acl status_error status 400:599
|
|
acl saturated_frt dst_conn ge 1000
|
|
acl invalid_ports src_port lt 512 ge 65535
|
|
|
|
D'autres tests arrivent (entêtes, cookies, heure, authentification), c'est
|
|
juste une question de temps. Il est aussi prévu de permettre de lire les
|
|
valeurs depuis un fichier, ainsi que d'ignorer la casse pour certains tests.
|
|
|
|
La seule commande supportant les conditions d'ACL à ce jour est la nouvelle
|
|
commande "block" qui bloque une requête et retourne un statut 403 si sa
|
|
condition est validée (cas du "if") ou invalidée (cas du "unless").
|
|
|
|
Exemple :
|
|
---------
|
|
|
|
acl options_uris url *
|
|
acl meth_option method OPTIONS
|
|
acl http_1.1 req_ver 1.1
|
|
acl allowed_meth method GET HEAD POST OPTIONS CONNECT
|
|
acl connect_meth method CONNECT
|
|
acl proxy_url url_beg http://
|
|
|
|
# block if reserved URI "*" used with a method other than "OPTIONS"
|
|
block if options_uris !meth_option
|
|
|
|
# block if the OPTIONS method is used with HTTP 1.0
|
|
block if meth_option !http_1.1
|
|
|
|
# allow non-proxy url with anything but the CONNECT method
|
|
block if !connect_meth !proxy_url
|
|
|
|
# block all unknown methods
|
|
block unless allowed_meth
|
|
|
|
Note: Cette documentation est embryonnaire mais doit permettre de démarrer et
|
|
surtout d'avancer sur le projet sans être trop ralenti par la documentation.
|
|
|
|
|
|
=======================
|
|
| 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 1 > /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 --
|