| |
| H A - P r o x y |
| --------------- |
| version 1.1.5 |
| willy tarreau |
| 2002/04/03 |
| |
| ================ |
| | Introduction | |
| ================ |
| |
| HA-Proxy est un relais TCP/HTTP offrant des facilités d'intégration en |
| environnement hautement disponible. En effet, il est capable de : |
| - assurer un aiguillage statique défini par des cookies ; |
| - assurer une répartition de charge avec création de cookies pour |
| assurer la persistence de session ; |
| - fournir une visibilité externe de son état de santé ; |
| - s'arrêter en douceur sans perte brutale de service. |
| - modifier/ajouter/supprimer des entêtes dans la requête et la réponse. |
| |
| Il requiert peu de ressources, et son architecture événementielle |
| mono-processus lui permet facilement de gérer plusieurs milliers de |
| connexions simultanées sur plusieurs relais sans effondrer le système. |
| |
| =========================== |
| | Paramètres de lancement | |
| =========================== |
| |
| Les options de lancement sont peu nombreuses : |
| |
| -f <fichier de configuration> |
| -n <nombre maximal total de connexions simultanées> |
| -N <nombre maximal de connexions simultanées par proxy> |
| -d active le mode debug |
| -D passe en daemon |
| -s affiche les statistiques (si option compilée) |
| -l ajoute des informations aux statistiques |
| |
| Le nombre maximal de connexion simultanées par proxy est le paramètre |
| par défaut pour les proxies pour lesquels ce paramètre n'est pas |
| précisé dans le fichier de configuration. |
| |
| Le nombre maximal total de connexions simultanées limite le nombre de |
| connexions TCP utilisables à un instant par le processus, tous proxies |
| confondus. |
| |
| ============================ |
| | Fichier de configuration | |
| ============================ |
| |
| |
| Commentaires |
| ============ |
| |
| 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. |
| |
| |
| Serveur |
| ======= |
| |
| Le fichier de configuration contient des sections repérées par le mot |
| clé "listen" : |
| |
| listen <nom_instance> <adresse_IP>:<port> |
| |
| <nom_instance> est le nom de l'instance décrite. Ce nom sera envoyé |
| dans les logs, donc il est souhaitable d'utiliser un nom relatif au |
| service relayé. Aucun test n'est effectué concernant l'unicité de ce |
| nom, qui n'est pas obligatoire, mais fortement recommandée. |
| |
| <adresse_IP> est l'adresse IP sur laquelle le relais attend ses |
| connexions. L'adresse 0.0.0.0 signifie que les connexions pourront |
| s'effectuer sur toutes les adresses de la machine. |
| |
| <port> est le numéro de port TCP sur lequel le relais attend ses |
| connexions. Le couple <adresse_IP>:<port> doit être unique pour toutes |
| les instances d'une même machine. L'attachement à un port inférieur à |
| 1024 nécessite un niveau de privilège particulier. |
| |
| Exemple : |
| --------- |
| listen http_proxy 127.0.0.1:80 |
| |
| |
| Inhibition |
| ========== |
| |
| Un serveur peut être désactivé pour des besoins de maintenance, sans |
| avoir à commenter toute une partie du fichier. Il suffit de |
| positionner le mot clé "disabled" dans sa section : |
| |
| listen smtp_proxy 0.0.0.0:25 |
| disabled |
| |
| Mode |
| ==== |
| |
| Un serveur peut fonctionner dans trois modes différents : |
| - TCP |
| - HTTP |
| - supervision |
| |
| Mode TCP |
| -------- |
| Dans ce mode, le service relaye, dès leur établissement, les |
| connexions TCP vers un ou plusieurs serveurs. Aucun traitement n'est |
| effectué sur le flux. Il s'agit simplement d'une association |
| <adresse_source:port_source> <adresse_destination:port_destination>. |
| Pour l'utiliser, préciser le mode TCP sous la déclaration du relais : |
| |
| listen smtp_proxy 0.0.0.0:25 |
| mode tcp |
| |
| Mode HTTP |
| --------- |
| Dans ce mode, le service relaye les connexions TCP vers un ou |
| plusieurs serveurs, une fois qu'il dispose d'assez d'informations pour |
| en prendre la décision. Les entêtes HTTP sont analysés pour y trouver |
| un éventuel cookie, et certains d'entre-eux peuvent être modifiés par |
| le biais d'expressions régulières. Pour activer ce mode, préciser le |
| mode HTTP sous la déclaration du relais : |
| |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| |
| Mode supervision |
| ---------------- |
| Il s'agit d'un mode offrant à un composant externe une visibilité de |
| l'état de santé du service. Il se contente de retourner "OK" à tout |
| client se connectant sur son port. Il peut être utilisé avec des |
| répartiteurs de charge évolués pour déterminer quels sont les services |
| utilisables. Pour activer ce mode, préciser le mode HEALTH sous la |
| déclaration du relais : |
| |
| listen health_check 0.0.0.0:60000 |
| mode health |
| |
| |
| 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: |
| |
| maxconn 16000 |
| |
| |
| Arrêt en douceur |
| ================ |
| |
| Il est possible d'arrêter les services en douceur en envoyant un |
| signal SIG_USR1 au processus relais. Tous les services seront alors |
| mis en phase d'arrêt, mais pourront continuer d'accepter des connexions |
| pendant un temps défini par le paramètre "grace" (en millisecondes). |
| Cela permet par exemple, de faire savoir rapidement à un répartiteur |
| de charge qu'il ne doit plus utiliser un relais, tout en continuant |
| d'assurer le service le temps qu'il s'en rende compte. Remarque : les |
| connexions actives ne sont jamais cassées. Dans le pire des cas, il |
| faudra attendre en plus leur expiration avant l'arrêt total du |
| processus. La valeur par défaut est 0 (pas de grâce). |
| |
| Exemple : |
| --------- |
| |
| # 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 |
| |
| listen health_check 0.0.0.0:60000 |
| mode health |
| grace 0 |
| |
| |
| 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 client à 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 3 secondes |
| contimeout 3000 |
| |
| Remarque: "contimeout" et "srvtimeout" n'ont pas d'utilité dans le cas |
| du serveur de type "health". |
| |
| 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" : |
| |
| # on essaie encore trois fois maxi |
| retries 3 |
| |
| Adresse du serveur |
| ================== |
| |
| Le serveur vers lequel sont redirigées les connexions est défini par |
| le paramètre "dispatch" sous la forme <adresse_ip>:<port> : |
| |
| # 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". |
| |
| 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" : |
| |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| |
| On peut modifier l'utilisation du cookie pour la rendre plus |
| intelligente vis-à-vis des applications relayées. Il est possible,notamment |
| de supprimer ou réécrire un cookie retourné par un serveur accédé en direct, |
| et d'insérer un cookie dans une réponse HTTP orientée vers un serveur |
| sélectionné en répartition de charge. |
| |
| Pour ne conserver le cookie qu'en accès indirect, donc à travers le |
| dispatcheur, et le supprimer lors des accès directs : |
| |
| cookie SERVERID indirect |
| |
| Pour réécrire le nom du serveur dans un cookie lors d'un accès direct : |
| |
| cookie SERVERID rewrite |
| |
| Pour créer un cookie comportant le nom du serveur lors d'un accès en |
| répartition de charge interne. Dans ce cas, il est indispensable que tous les |
| serveurs aient un cookie renseigné. |
| |
| cookie SERVERID insert |
| |
| Remarque: 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. |
| |
| Assignation d'un serveur à une valeur de cookie |
| =============================================== |
| |
| En mode HTTP, il est possible d'associer des serveurs à des valeurs de |
| cookie 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 (erreurs...). |
| <adresse_ip>:<port> le couple adresse-port sur lequel le serveur écoute. |
| <valeur> est la valeur trouvée dans le cookie, |
| |
| Exemple : le cookie SERVERID peut contenir server01 ou server02 |
| ------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| dispatch 192.168.1.100:80 |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| |
| Attention : la syntaxe a changé depuis la version 1.0. |
| --------- |
| |
| Répartiteur de charge interne |
| ============================= |
| |
| Le relais peut effectuer lui-même la répartition de charge entre les |
| différents serveurs décrits pour un service donné, en mode TCP comme |
| en mode HTTP. Pour cela, on précise le mot clé 'balance' dans la |
| définition du service, éventuellement suivi du nom d'un algorithme de |
| répartition. En version 1.1.0, seul 'roundrobin' est géré, et c'est |
| aussi la valeur implicite par défaut. Il est évident qu'en cas |
| d'utilisation du répartiteur interne, il ne faudra pas spécifier |
| d'adresse de dispatch, et qu'il faudra au moins un serveur. |
| |
| Exemple : même que précédemment en répartition interne |
| ------- |
| |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| cookie SERVERID |
| balance roundrobin |
| server web1 192.168.1.1:80 cookie server01 |
| server web2 192.168.1.2:80 cookie server02 |
| |
| |
| Surveillance des serveurs |
| ========================= |
| |
| A cette date, l'état des serveurs n'est testé que par établissement |
| de connexion TCP toutes les 2 secondes, avec 3 essais pour déclarer |
| un serveur en panne, 2 pour le déclarer utilisable. 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 |
| |
| Exemple : même que précédemment avec surveillance |
| ------- |
| |
| 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 |
| |
| |
| 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 serveur HS. |
| |
| 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 |
| |
| Journalisation des connexions |
| ============================= |
| |
| Les connexions TCP et HTTP peuvent donner lieu à une journalisation |
| sommaire indiquant, pour chaque connexion, la date, l'heure, les adresses |
| IP source et destination, et les ports source et destination qui la |
| caractérisent. Ultérieurement, les URLs seront loguées en mode HTTP, |
| tout comme les arrêts de service. Tous les messages sont envoyés en |
| syslog vers un ou deux serveurs. La syntaxe est la suivante : |
| |
| log <adresse_ip> <facility> |
| |
| Exemple : |
| --------- |
| listen http_proxy 0.0.0.0:80 |
| mode http |
| log 192.168.2.200 local3 |
| log 192.168.2.201 local4 |
| |
| Les connexions sont envoyées en niveau "info". Les démarrages de |
| service seront envoyés en "notice", les signaux d'arrêts en "warning" |
| et les arrêts définitifs en "alert". Ceci est valable aussi bien |
| pour les proxies que pour les serveurs testés au sein des proxies. |
| |
| 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 |
| |
| |
| Modification des entêtes HTTP |
| ============================= |
| |
| En mode HTTP uniquement, il est possible de remplacer certains entêtes |
| dans la requête et/ou la réponse à partir d'expressions régulières. Une |
| limitation cependant : les entêtes fournis au milieu de connexions |
| persistentes (keep-alive) ne sont pas vus. Les données ne sont pas |
| affectées, ceci ne s'applique qu'aux entêtes. |
| |
| La syntaxe est : |
| reqadd <string> pour ajouter un entête dans la requête |
| reqrep <search> <replace> pour modifier la requête |
| reqrep <search> pour supprimer un entête dans la requête |
| |
| rspadd <string> pour ajouter un entête dans la réponse |
| rsprep <search> <replace> pour modifier la réponse |
| rsprep <search> pour supprimer un entête dans la réponse |
| |
| |
| <search> est une expression régulière compatible GNU regexp supportant |
| le groupage par parenthèses (sans les '\'). Les espaces et autres |
| séparateurs doivent êtres précédés d'un '\' pour ne pas être confondus |
| avec la fin de la chaîne. De plus, certains caractères spéciaux peuvent |
| être précédés d'un backslach ('\') : |
| |
| \t pour une tabulation |
| \r pour un retour charriot |
| \n pour un saut de ligne |
| \ pour différencier un espace d'un séparateur |
| \# pour différencier un dièse d'un commentaire |
| \\ pour un backslash |
| \xXX pour un caractère spécifique XX (comme en C) |
| |
| |
| <replace> contient la chaîne remplaçant la portion vérifiée par l'expression. |
| Elle peut inclure les caractères spéciaux ci-dessus, faire référence à un |
| groupe délimité par des parenthèses dans l'expression régulière, par sa |
| position numérale. Les positions vont de 1 à 9, et sont codées par un '\' |
| suivi du chiffre désiré. Il est également possible d'insérer un caractère non |
| imprimable (utile pour le saut de ligne) inscrivant '\x' suivi du code |
| hexadécimal de ce caractère (comme en C). |
| |
| <string> représente une chaîne qui sera ajoutée systématiquement après la |
| dernière ligne d'entête. |
| |
| Remarques : |
| --------- |
| - la première ligne de la requête et celle de la réponse sont traitées comme |
| des entêtes, ce qui permet de réécrire des URL et des codes d'erreur. |
| - 'reqrep' est l'équivalent de 'cliexp' en version 1.0, et 'rsprep' celui de |
| 'srvexp'. Ces noms sont toujours supportés mais déconseillés. |
| - pour des raisons de performances, le nombre total de caractères ajoutés sur |
| une requête ou une réponse est limité à 4096 depuis la version 1.1.5 (cette |
| limite était à 256 auparavant). Cette valeur est modifiable dans le code. |
| Pour un usage temporaire, on peut gagner de la place en supprimant quelques |
| entêtes inutiles avant les ajouts. |
| |
| Exemples : |
| -------- |
| reqrep ^(GET.*)(.free.fr)(.*) \1.online.fr\3 |
| reqrep ^(POST.*)(.free.fr)(.*) \1.online.fr\3 |
| reqrep ^Proxy-Connection:.* Proxy-Connection:\ close |
| rsprep ^Server:.* Server:\ Tux-2.0 |
| rsprep ^(Location:\ )([^:]*://[^/]*)(.*) \1\3 |
| rspdel ^Connection:.* |
| rspadd Connection:\ close |
| |
| |
| 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 : |
| - assigner un cookie à chaque serveur |
| - effectuer une répartition interne |
| - insérer un cookie dans les réponses issues d'une répartition |
| |
| Exemple : |
| ------- |
| listen application 0.0.0.0:80 |
| mode http |
| cookie SERVERID insert indirect |
| balance roundrobin |
| server 192.168.1.1:80 cookie server01 check |
| server 192.168.1.2:80 cookie server02 check |
| |
| ======================= |
| | 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 32768 > /proc/sys/net/ipv4/ip_queue_maxlen |
| echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout |
| echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog |
| echo 262144 > /proc/sys/net/ipv4/tcp_max_tw_buckets |
| echo 262144 > /proc/sys/net/ipv4/tcp_max_orphans |
| echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time |
| echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle |
| echo 0 > /proc/sys/net/ipv4/tcp_timestamps |
| echo 0 > /proc/sys/net/ipv4/tcp_ecn |
| echo 0 > /proc/sys/net/ipv4/tcp_sack |
| echo 0 > /proc/sys/net/ipv4/tcp_dsack |
| |
| # auto-tuned on 2.4 |
| #echo 262143 > /proc/sys/net/core/rmem_max |
| #echo 262143 > /proc/sys/net/core/rmem_default |
| |
| echo 16384 65536 524288 > /proc/sys/net/ipv4/tcp_rmem |
| echo 16384 349520 699040 > /proc/sys/net/ipv4/tcp_wmem |
| |
| -- cut here -- |
| |
| -- fin -- |