2892 lines
129 KiB
Plaintext
2892 lines
129 KiB
Plaintext
-------------------
|
|
HAProxy
|
|
Manuel de référence
|
|
-------------------
|
|
version 1.3.2
|
|
willy tarreau
|
|
2006/09/03
|
|
|
|
|
|
!!!! NOTE: CE DOCUMENT EST PERIME !!!!
|
|
|
|
Veuillez utiliser le fichier "configuration.txt" situé dans le même
|
|
répertoire, ou télécharger une version à jour à l'emplacement ci-dessous :
|
|
|
|
http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
|
|
|
|
|
|
================
|
|
| 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.
|
|
- A compter de la version 1.3.14, il est possible de spécifier les durées
|
|
d'expiration dans des unités de temps arbitraires à choisir parmi
|
|
{ us, ms, s, m, h, d }. Pour cela, la valeur entière doit être suffixée
|
|
de l'unité.
|
|
|
|
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
|
|
|
|
La version 1.3.14 a apporté une nouvelle méthode 'balance url_param'. Elle
|
|
consiste à se baser sur un paramètre passé dans l'URL pour effectuer un hachage
|
|
utilisé pour déterminer le serveur à utiliser. Ceci est principalement utile
|
|
pour des applications n'ayant pas une exigence stricte de persistance, mais
|
|
pour lesquelles elle procure un gain de performance notable dans des
|
|
environnements où il n'est pas toujours possible d'utiliser des cookies. En cas
|
|
d'absence du paramètre dans l'URL, alors une répartition de type 'round robin'
|
|
est effectuée.
|
|
|
|
Example :
|
|
---------
|
|
|
|
# hache le paramètre "basket_id" dans l'URL pour déterminer le serveur
|
|
|
|
listen http_proxy
|
|
bind :3128
|
|
mode http
|
|
balance url_param basket_id
|
|
server ebiz1 192.168.1.1
|
|
server ebiz2 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 --
|