Forum Linux.général [Tuto/HowTo] [Ubuntu/Debian] Load Balancing - redirection vers plusieurs vhost avec HaProxy

Posté par  . Licence CC By‑SA.
4
20
sept.
2017

Sommaire

musique d'ambiance : Les Choristes - Vois Sur Ton Chemin (Paraphonics Remix) LES RAMONEURS DE MENHIRS - Dans An Diaoul
Testé avec succès sur : Ubuntu Minimal 16.04 (ARM)
Difficulté : moyen

image schema repartiteur de charge HaProxy + serveur web

Mise en place HaProxy (load balancing)

Installez les pré-requis

apt-get update
apt-get install -y haproxy

Activez HaProxy

sed -i "s/ENABLED=0/ENABLED=1/g" /etc/default/haproxy
sed -i "s/ENABLED=0/ENABLED=1/g" /etc/init.d/haproxy

Créez le dossier qui va accueillir les certificats TLS (exSSL)

mkdir -p /etc/haproxy/certs/

Concaténez chaque certificat (clés publique) et sa clés privé (recommencez pour chaque certificat)

DOMAIN='cloud.linuxfr.org' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/certs/$DOMAIN.pem'
  • DOMAIN='cloud.linuxfr.org' => remplacez par votre nom de domaine
  • /etc/letsencrypt/live/ => le chemin d'accès (PATH) vers vos fichiers, ici c'est le dossier par défaut de Let's Encrypt.
    • Note : pas la peine de concaténer tout vos certificats/clés privé dans un seul gros fichiers, cela ne fonctionne pas.

Éditez /etc/haproxy/haproxy.cfg

sudo nano /etc/haproxy/haproxy.cfg

Ajoutez la partie traitant de l'écoute (frontend)
Note : dans cet exemple on défini deux noms de domaines (cloud.linuxfr.org et forum.linuxfr.org)

frontend https
    bind *:80
        bind *:443 ssl crt /etc/haproxy/certs/cloud.linuxfr.org.pem crt /etc/haproxy/certs/forum.linuxfr.org.pem
        mode http
        option httpclose
        option forwardfor
        reqadd X-Forwarded-Proto:\ https

                # gestion des logs
        log /dev/log local0 info
        http-request add-header X-CLIENT-IP %[src]

                #on force https (pas obligatoire)
        acl http      ssl_fc,not
        http-request redirect scheme https if http

        # si le visiteurs tentent de joindre depuis un hostname inconnu, on renvoie vers cette config serveur
        default_backend serveur_web

        # On défini les hostnames
        acl host_cloud.linuxfr.org hdr(host) -i cloud.linuxfr.org
        acl host_forum.linuxfr.org hdr(host) -i forum.linuxfr.org

        ## On associe quelle config serveur (backend) va avec quel hostname
        use_backend serveur_cloud if host_cloud.linuxfr.org
        use_backend serveur_web if host_forum.linuxfr.org
  • frontend https => On défini le bloc de configuration frontend. Format frontend nomUnique.
  • bind *:80 => on écoute sur le port 80 (utile ici afin de rediriger vers https)
  • bind *:443 ssl crt /etc/haproxy/certs/cloud.linuxfr.org.pem crt /etc/haproxy/certs/forum.linuxfr.org.pem => on écoute sur le port 443 et on lui associe deux certificats
  • default_backend serveur_web => on défini "serveur_web" comme config backend par défaut (en cas de visite via un hostname inconnu)
  • acl host_cloud.linuxfr.org hdr(host) -i cloud.linuxfr.org => on défini nos hostnames et l'identifiant qui y est lié. format acl nomUnique hdr(host) -i www.monHostname.com
  • use_backend serveur_cloud if host_cloud.linuxfr.org => on défini quelle config serveur est associé à l'identifiant unique créé précédemment.

Ajoutez la partie traitant des différents serveurs (backend)
Note : dans cet exemple on défini les serveurs pour les deux noms de domaines.

backend serveur_cloud
        mode http
        balance leastconn
        option forwardfor
        option httpchk HEAD /haproxytest.txt HTTP/1.0
        cookie SERVERID insert indirect nocache
        server serveurCloud serveurCloud:80 check cookie serveurCloud

backend serveur_web
        mode http
        balance roundrobin
        option forwardfor
        option httpchk HEAD /haproxytest.txt HTTP/1.0
        cookie SERVERID insert indirect nocache
        server superRaspberry superRaspberry:443 check cookie superRaspberry ssl verify none
  • backend serveur_web => On défini le bloc de configuration backend. Format backend nomUnique.
  • mode http => écoute en http
  • balance leastconn => on défini quel algorithme de sélection des serveurs à utiliser. Accepte : roundrobin , leastconn, source. (infos)
  • option forwardfor => on active la transmission des IPs des clients via l'header HTTP "X-Forwarded-For"
  • option httpchk HEAD /haproxytest.txt HTTP/1.0 => on défini un fichier sur les serveurs backend, HaProxy vérifiera l'existence de ce fichier sur chaque serveur toutes les deux secondes. Si le fichier n'est pas présent sur un serveur, HaProxy * considérera ce serveur comme inactif. Pour les applications PHP et les CMS, je vous conseil fortement de pointer le fichier index.php.
  • cookie SERVERID insert indirect nocache => option concernant les cookies
  • server superRaspberry superRaspberry:443 check cookie superRaspberry ssl verify none => Une ligne par serveur. server superRaspberry superRaspberry:443 on défini notre serveur (son nom puis sont hostname:port). check signifie qu'il faut tester l'existence du fichier de test (haproxytest.txt), cookie superRaspberry qu'il faut transférer les cookies valide pour superRaspberry et ssl verify none qu'il ne faut pas vérifier le certificat TLS du serveur backend.

Configurer apache2

Note : n'oubliez pas de redémarrer apache2 après avoir apporté une ou plusieurs modifications

Obligatoire

Créer le fichier vide sur tout vos serveurs apache2, il va servir à HaProxy pour vérifier la disponibilité des serveurs.

touch /var/www/html/haproxytest.txt
  • Adaptez éventuellement le PATH à votre configuration. Vous pouvez tout à fait vérifier l'existence d'un autre fichier (par exemple index.html, robot.txt, etc). Sachez toute fois que plus ce fichiers est gros et plus sa vérification va consommer de ressources/électricité.

Optionnel

Supprimer les checks de HaProxy des fichiers logs d'apache2

Éditez votre fichier vhost (/etc/apache2/sites-available/) Et ajoutez les lignes suivantes en adaptant éventuellement le PATH des fichiers logs à votre config

SetEnvIf Request_URI haproxytest.txt dontlog
#SetEnvIf Remote_Addr "10\.8\.0\.1" dontlog # si vous voulez aussi ban une ip
CustomLog /var/log/apache2/access.log combined env=!dontlog
  • Il va de soit que si votre HaProxy check un autre fichier que haproxytest.txt vous devez le mentionner.

Bonus

Transmettre les IP des clients de HaProxy (frontend) vers apache2 (backend)

Préambule

Avec ça les fichiers logs d'apache2 retrouvent une tronche normale mais par contre $_SERVER[’REMOTE_ADDR’] continue de renvoyer l'IP du frontend. Pour récupérer l'IP du client vous devez passer par $_SERVER["HTTP_X_FORWARDED_FOR"].
Toutes ces commandes sont à exécuter en admin (root).

Côté HaProxy

Éditez le fichier de configuration de HaProxy

nano /etc/haproxy/haproxy.cfg

Ajoutez option forwardfor dans les blocs de commandes dédié au frontend et au backend

Côté Apache2

Lancez les commandes suivantes

apt-get install libapache2-mod-rpaf
a2enmod rpaf
nano /etc/apache2/mods-enabled/rpaf.conf

Collez les lignes suivantes

</IfModule rpaf_module>
    RPAFenable On
    RPAFsethostname On
        # list your proxies IP address below
    RPAFproxy_ips 10.0.0.1 10.0.0.2
    RPAFheader X-Real-IP
</IfModule>
  • RPAFproxy_ips 10.0.0.1 10.0.0.2 => adaptez cette ligne pour indiquer la ou les IP de vos frontends

CTRL+X pour sauver et quitter

Redémarrez le serveur web

service apache2 restart

Activer les statistiques de HaProxy

Adaptez puis ajoutez les lignes suivantes dans /etc/haproxy/haproxy.cfg


listen stats
    bind *:1936
    mode http
    stats enable
    stats uri /
    stats hide-version
    stats auth login:password
  • bind *:1936 => le port sur lequel écouter pour joindre la WEBUI des statistiques de HaProxy
  • stats auth login:password => le couple login et password. Une ligne par couple login:password, vous pouvez ajouter autant de ligne que vous le souhaitez.
  • # Exemple de scripts

    Posté par  . Évalué à 1.

    Exemple de script en PHP permettant d'afficher l'adresse IP du client qu'il passe ou non par le frontend HaProxy

    <?php
    
    if ($_SERVER["HTTP_X_FORWARDED_FOR"] === NULL){
            // client lambda
        $myIP=$_SERVER["REMOTE_ADDR"];
    }else{
            // client derrière proxy / frontend
        $myIP=$_SERVER["HTTP_X_FORWARDED_FOR"];
    }
    
    echo $myIP;
    
    ?>
    

    Attention, ne l'utilisez pas dans un cadre de sécurité, en effet si votre serveur est directement exposé sur internet (pas derrière un frontend HaProxy), le client peut facilement envoyer une fausse valeur pour HTTP_X_FORWARDED_FOR (ainsi que pour REMOTE_ADDR, voir IP Spoofing)

    Si vous codez un logiciel sans une interface chatoyante, alors vous faites de la merde. Donation bitcoin : 1N8QGrhJGWdZNQNSspm3rSGjtXaXv9Ngat

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.