--- title: "Health checks y failover en HAProxy con Ubuntu 24.04" description: "Configura health checks HTTP y TCP en HAProxy sobre Ubuntu 24.04, con servidor de respaldo, página de mantenimiento y drenado de servidores sin cortes." category: "Proxy y Equilibrio de Carga" language: es source: https://cubepath.com/es/docs/proxy-y-equilibrio-de-carga/verificaciones-de-salud-de-haproxy-y-conmutacion-por-error updated: 2026-09-25 --- # Health checks y failover en HAProxy con Ubuntu 24.04 Un balanceador solo aporta alta disponibilidad si deja de enviar tráfico a los servidores que fallan. HAProxy lo hace con comprobaciones de salud activas: consulta periódicamente cada backend y lo saca de la rotación cuando no responde como se espera, sin esperar a que falle una petición real. En este tutorial configurarás en Ubuntu 24.04 comprobaciones HTTP con umbrales de caída y recuperación, un servidor de respaldo, una página de mantenimiento cuando no queda ningún backend y el drenado manual de servidores para hacer mantenimiento sin cortar conexiones. Todo se prueba con un laboratorio de tres backends en la misma máquina. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - El puerto 80 libre. En producción los backends estarán en otras máquinas, normalmente en una red privada; bastará con cambiar las direcciones de las líneas `server`. En el laboratorio son tres sitios de Nginx escuchando en `127.0.0.1`. ## Paso 1: Instalar HAProxy, Nginx y socat Ubuntu 24.04 incluye HAProxy 2.8 LTS. Nginx servirá los backends de prueba y `socat` permite hablar con el socket de administración de HAProxy: ```bash sudo apt update sudo apt install haproxy nginx socat ``` Desactiva el sitio por defecto de Nginx, que ocupa el puerto 80 que usará HAProxy: ```bash sudo rm /etc/nginx/sites-enabled/default sudo systemctl reload nginx ``` Si usas UFW, permite HTTP: ```bash sudo ufw allow 80/tcp ``` ## Paso 2: Crear backends con un endpoint de salud Una buena comprobación de salud no se limita a ver si el puerto responde: consulta una ruta que la propia aplicación controla. Así la aplicación puede declararse no disponible (por ejemplo, si pierde la conexión con la base de datos) y también puedes sacar un servidor de servicio a propósito. En el laboratorio, `/health` devuelve `200` mientras exista el archivo `/var/www/backendN/health` y `503` si se borra. Crea los archivos: ```bash for i in 1 2 3; do sudo mkdir -p /var/www/backend$i echo OK | sudo tee /var/www/backend$i/health > /dev/null done ``` Crea la configuración de los tres backends: ```bash sudo nano /etc/nginx/conf.d/test-backends.conf ``` ```nginx server { listen 127.0.0.1:8081; root /var/www/backend1; default_type text/plain; location = /health { try_files /health =503; } location / { return 200 "backend-1\n"; } } server { listen 127.0.0.1:8082; root /var/www/backend2; default_type text/plain; location = /health { try_files /health =503; } location / { return 200 "backend-2\n"; } } server { listen 127.0.0.1:8083; root /var/www/backend3; default_type text/plain; location = /health { try_files /health =503; } location / { return 200 "backend-3\n"; } } ``` Valida, recarga y prueba el endpoint: ```bash sudo nginx -t && sudo systemctl reload nginx curl -i http://127.0.0.1:8081/health ``` ```output HTTP/1.1 200 OK Content-Type: text/plain OK ``` ## Paso 3: Configurar HAProxy con comprobaciones HTTP Primero crea la página que HAProxy devolverá cuando no quede ningún servidor disponible. Un `errorfile` es una respuesta HTTP completa, cabeceras incluidas: ```bash sudo nano /etc/haproxy/errors/maintenance.http ``` ```text HTTP/1.1 503 Service Unavailable Content-Type: text/html; charset=utf-8 Cache-Control: no-store Connection: close
Vuelve a intentarlo en unos minutos.
``` Guarda una copia de la configuración original de HAProxy y ábrela: ```bash sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.orig sudo nano /etc/haproxy/haproxy.cfg ``` Sustituye su contenido por: ```haproxy global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon defaults log global mode http option httplog option dontlognull option redispatch retries 2 timeout connect 3s timeout client 30s timeout server 30s frontend web_in bind :80 default_backend web_servers backend web_servers balance roundrobin option httpchk http-check send meth GET uri /health ver HTTP/1.1 hdr Host localhost http-check expect status 200 default-server inter 2s fall 3 rise 2 on-marked-down shutdown-sessions errorfile 503 /etc/haproxy/errors/maintenance.http server web1 127.0.0.1:8081 check server web2 127.0.0.1:8082 check server web3 127.0.0.1:8083 check backup frontend stats bind 127.0.0.1:8404 stats enable stats uri /stats stats refresh 5s ``` Qué controla cada parte: | Directiva | Efecto | |---|---| | `option httpchk` + `http-check send` | Envía `GET /health` con cabecera `Host` a cada servidor. Sin `httpchk`, `check` solo comprueba que el puerto TCP acepta conexiones. | | `http-check expect status 200` | Solo un `200` cuenta como éxito. Sin esta línea, cualquier `2xx` o `3xx` vale. | | `inter 2s` | Intervalo entre comprobaciones. | | `fall 3` | Tres fallos seguidos marcan el servidor como `DOWN` (unos 6 segundos con `inter 2s`). | | `rise 2` | Dos éxitos seguidos lo devuelven a `UP`, para no meter en rotación un servidor que aún está arrancando. | | `on-marked-down shutdown-sessions` | Cierra las conexiones abiertas con un servidor cuando se marca como caído, en lugar de dejarlas colgadas. | | `backup` | `web3` solo recibe tráfico cuando no queda ningún servidor principal disponible. | | `option redispatch` + `retries 2` | Si falla la conexión con un servidor, la petición se reintenta en otro. | | `errorfile 503` | Página que se devuelve cuando el backend no tiene ningún servidor disponible. | `default-server` aplica esos parámetros a todas las líneas `server` del backend; puedes sobrescribirlos en una línea concreta. Valida y recarga: ```bash sudo haproxy -c -f /etc/haproxy/haproxy.cfg sudo systemctl reload haproxy ``` ```output Configuration file is valid ``` Comprueba que el tráfico se reparte entre los dos servidores principales: ```bash for i in $(seq 1 4); do curl -s http://localhost/; done ``` ```output backend-1 backend-2 backend-1 backend-2 ``` `backend-3` no aparece porque es de respaldo. ## Paso 4: Ver el estado de los servidores El socket de administración devuelve el estado de cada servidor. La salida de `show stat` es CSV; los campos 1, 2 y 18 son el backend, el servidor y su estado: ```bash echo "show stat" | sudo socat stdio /run/haproxy/admin.sock | cut -d, -f1,2,18 | grep web_servers ``` ```output web_servers,web1,UP web_servers,web2,UP web_servers,web3,UP web_servers,BACKEND,UP ``` Para ver la página de estadísticas en el navegador, abre un túnel SSH desde tu equipo con `ssh -L 8404:127.0.0.1:8404 your_user@your_server_ip` y visita `http://localhost:8404/stats`. Deja abierta una segunda terminal siguiendo el log de HAProxy para ver los cambios de estado en los pasos siguientes: ```bash sudo tail -f /var/log/haproxy.log ``` ## Paso 5: Probar la conmutación por error Simula que `web1` deja de estar sano borrando su archivo de salud: ```bash sudo rm /var/www/backend1/health ``` En unos 6 segundos (tres comprobaciones fallidas) aparece en el log: ```output Server web_servers/web1 is DOWN, reason: Layer7 wrong status, code: 503, info: "Service Temporarily Unavailable", check duration: 0ms. 1 active and 1 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. ``` Ahora todo el tráfico va a `web2`: ```bash for i in $(seq 1 3); do curl -s http://localhost/; done ``` ```output backend-2 backend-2 backend-2 ``` Haz caer también `web2`. Al no quedar servidores principales, entra el de respaldo: ```bash sudo rm /var/www/backend2/health sleep 8 for i in $(seq 1 2); do curl -s http://localhost/; done ``` ```output backend-3 backend-3 ``` El log lo indica con `0 active and 1 backup servers left. Running on backup.` Por último, haz caer `web3`: ```bash sudo rm /var/www/backend3/health sleep 8 curl -i http://localhost/ ``` ```output HTTP/1.1 503 Service Unavailable content-type: text/html; charset=utf-8 cache-control: no-store ...