Importante
Este artículo está obsoleto y puede contener información desactualizada. Por favor, consulta la documentación más reciente para obtener la información actualizada.
HAProxy es un software que nos permite balancear carga entre varios servidores. Se suele usar para balancear servicios web, pero puede balancear cualquier servicio que funcione bajo protocolo TCP. En este artículo os vamos a enseñar varias configuraciones de HAProxy incluso que tenga en cuenta las cookies, parece una tontería, pero puede provocar que fallen nuestra web. Imagínate que tienes 2 servidores web -en adelante frontales- cuando el usuario llega por primera vez a tu web lo hace en el frontal-01. Cuando el usuario se registra crea una cookie, el usuario siguen navegando y de repente HAProxy envía el tráfico al frontal-2, en ese servidor no existe la cookie y por tanto le cerrará la sesión :(, configurando adecuadamente HAProxy esto no sucederá.
Instalación HAProxy
La configuración mínima para poder balancear carga es de 3 servidores: HAProxy + 2 frontales webs. La ventaja de usar HAProxy es que en cualquier momento puedes añadir más frontales.
Otra de las ventajas de usar HAProxy es que podemos restringir el acceso a los frontales por la IP Pública con lo cual no estarán accesibles directamente. Con los siguientes comandos ya podemos instalar HAProxy.
# apt update
# apt upgrade
# apt install haproxy
# mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.org
Configuración base
Ahora ya podemos crear nuestro primer fichero de configuración ejecutaremos: vi /etc/haproxy/haproxy.cfg
global
daemon
maxconn 256
user haproxy
group haproxy
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option tcplog
option dontlognull
maxconn 8000
timeout connect 5s
timeout client 300s
timeout server 300s
retries 3
timeout check 10s
timeout queue 1m
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen test_kb
bind *:80
mode http
stats enable
stats auth cda:cda
balance roundrobin
server frontend-01 10.20.10.54:80 #IP Privada frontal-01
server frontend-02 10.20.10.56:80 #IP Privada frontal-02
Ahora que ya tenemos la configuración hecha, tenemos que reiniciar el servicio de HAProxy, esto lo haremos cada vez que cambiemos la configuración.
# systemctl restart haproxy
Ver estadísticas
Para ver estadísticas vía web, modificaremos la siguiente configuración vi /etc/haproxy/haproxy.cfg:
listen stats
bind *:8083
mode http
stats enable
stats uri /stats
stats realm HAProxy\ Statistics
stats auth haproxy:TestKB
Ahora iremos a nuestro navegador y abriremos la web http://IP_Publica_HAProxy:8083/stats, nos pedirá usuario y contraseña, indicaremos haproxy y TestKB.
Si queremos que la página de estadísticas se actualice sola cada 10 minutos podemos añadir la directiva
stats refresh 10s
Comprobar estado y controlar cookies
Podemos controlar que un usuario siempre acceda al mismo frontal, en nuestro ejemplo nos basaremos en una variable de PHP pero podemos usar cualquier variable.
Otra característica importante de HAProxy es que puede controlar si un frontal está caído o sobrecargado y desconectarlo temporalmente. Editaremos vi /etc/haproxy/haproxy.cfg
listen test_kb
bind *:80
mode http
stats enable
stats auth cda:cda
balance roundrobin
option httpchk GET /index.php HTTP/1.0
http-check expect rstatus (2|3)[0-9][0-9]|503
cookie PHPSESSID prefix indirect nocache
server frontend-01 10.20.10.54:80 check maxconn 4000 fall 3 cookie L1
server frontend-02 10.20.10.56:80 check maxconn 4000 fall 3 cookie L2
Añadir certificado SSL de Let's Encrypt para HAProxy
En este punto en que tenemos HAProxy funcionando, es el momento adecuado para realizar unas modificaciones para que nuestro sitio web balanceado esté protegido con un certificado. Algunos aspectos que hay que tener en cuenta son:
- HAProxy y Let's Encrypt no pueden utilizar los mismos puertos 80 y 443. Modificaremos Let's Encrypt y la auto-renovación para que utilice un puerto distinto.
- HAProxy no es capaz de leer el certificado SSL en diversos ficheros como se generan de forma automática. Modificaremos el certificado SSL para que lo pueda leer HAProxy.
- Crearemos una regla de filtrado en HAProxy para que las renovaciones de Let's Encrypt funcionen y el resto de peticiones se envíen al backend.
- Crearemos un script para la auto-renovación del certificado sea posible adaptándolo al uso junto a HAProxy.
Primero de todo instalaremos Let's Encrypt con los siguientes comandos:
# add-apt-repository -y ppa:certbot/certbot
# apt-get update
# apt-get install -y certbot
Ahora editaremos el siguiente fichero:
# vi /etc/haproxy/haproxy.cfg
Y lo dejaremos como a continuación:
global
daemon
maxconn 256
user haproxy
group haproxy
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option tcplog
option dontlognull
maxconn 8000
timeout connect 5s
timeout client 300s
timeout server 300s
retries 3
timeout check 10s
timeout queue 1m
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen test_kb
bind *:80
bind *:443 ssl crt /etc/ssl/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host.pem
# Forzamos a HAProxy para que redireccione a HTTPS
redirect scheme https code 301 if !{ ssl_fc }
# Indicamos que las peticiones de Lets Encrypt vayan al bloque banckend letsencrypt
acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt if letsencrypt-acl
#Indicamos que todo el resto de peticiones vayan al bloque servidoresBackend
default_backend servidoresBackend
#lets encrypt backend
backend letsencrypt
server letsencrypt 127.0.0.1:8888
#default backend
backend servidoresBackend
mode http
stats enable
stats auth cda:cda
balance roundrobin
option httpchk GET /index.php HTTP/1.0
http-check expect rstatus (2|3)[0-9][0-9]|503
cookie PHPSESSID prefix indirect nocache
server frontend-01 10.20.10.8:80 check maxconn 4000 fall 3 cookie L1
server frontend-02 10.20.10.9:80 check maxconn 4000 fall 3 cookie L2
#backend HaProxy Stats
listen stats
bind *:8083
mode http
stats enable
stats uri /stats
stats realm HAProxy\ Statistics
stats auth haproxy:TestKB
En este código el identificador "edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host" se tiene que sustituir por el nombre de dominio que se esté utilizando para la web y las IP de los servidores hay que modificarlas por las que tengáis configuradas en vuestros servidor.
El siguiente paso que vamos a realizar es generar el certificado SSL de Let's Encrypt para nuestro dominio y que posteriormente configuraremos en HAProxy. El comando a ejecutar es:
# certbot certonly --standalone -d edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host --non-interactive --agree-tos --email soporte@clouding.io --http-01-port=8888
Cómo podéis ver utilizamos el puerto 8888 para que no entre en conflicto con HAProxy.
Ahora tenemos que crear el directorio y el fichero dónde vamos a guardar el certificado SSL adaptado para que HAProxy lo pueda leer. Para ello ejecutaremos:
# mkdir -p /etc/ssl/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host
# cat /etc/letsencrypt/live/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/fullchain.pem /etc/letsencrypt/live/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/privkey.pem | tee /etc/ssl/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host.pem
Con esto ya tenemos el certificado adaptado y que en la configuración de HAProxy anterior lo utiliza en la linea:
bind *:443 ssl crt /etc/ssl/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host.pem
Para que el certificado de Let's Encrypt se renueve automáticamente tendremos que crear un pequeño script y añadirlo al crontab para que se ejecute una vez al mes:
# crontab -e
Y añadimos la siguiente linea:
0 0 1 * * root bash /opt/renovar-certificados.sh
Ahora creamos el script:
# vi /opt/renovar-certificados.sh
y añadimos el siguiente contenido:
#!/usr/bin/env bash
# Renovar certificado
certbot renew --force-renewal --tls-sni-01-port=8888
# Adaptamos el certificado para haproxy
bash -c "cat /etc/letsencrypt/live/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/fullchain.pem /etc/letsencrypt/live/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/privkey.pem | tee /etc/ssl/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host/edf10be0-f2c0-4cef-b38b-eee8e9577d6f.clouding.host.pem"
# Recargamos haproxy
service haproxy reload
Finalmente, deberíamos comprobar que Let's Encrypt será capaz de renovar el certificado ejecutando:
# certbot renew --tls-sni-01-port=8888