--- title: "Algoritmos de balanceo de carga en Nginx: guía práctica" description: "Compara round robin, least_conn, ip_hash, hash y random en Nginx con un laboratorio en Ubuntu 24.04 y configura pesos, respaldo, failover y keepalive." category: "Proxy y Equilibrio de Carga" language: es source: https://cubepath.com/es/docs/proxy-y-equilibrio-de-carga/algoritmos-de-equilibrio-de-carga-nginx updated: 2026-09-25 --- # Algoritmos de balanceo de carga en Nginx: guía práctica Nginx puede repartir las peticiones entre varios servidores backend agrupados en un bloque `upstream`. El algoritmo que elijas decide a qué servidor va cada petición, y eso afecta a la carga de cada máquina, a las sesiones de usuario y a las cachés locales. En esta guía montarás un pequeño laboratorio en Ubuntu 24.04 con tres backends de prueba, verás en la práctica cómo reparte cada algoritmo de Nginx de código abierto y terminarás con una configuración lista para producción con pesos, respaldo, detección de fallos y conexiones keepalive. ## 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 (sin Apache u otro servidor web escuchando). En producción los backends estarán en otras máquinas, normalmente en una red privada. En el laboratorio los tres backends son sitios de Nginx en `127.0.0.1`, lo que permite ver el reparto sin montar más servidores. Las directivas son las mismas. ## Resumen de algoritmos | Algoritmo | Directiva | Cómo elige servidor | Úsalo cuando | |---|---|---|---| | Round robin | (por defecto) | Por turnos, respetando los pesos | Backends iguales y peticiones similares | | Menos conexiones | `least_conn` | El que tiene menos conexiones activas (ponderado) | Peticiones de duración muy variable, WebSocket, descargas largas | | Hash de IP | `ip_hash` | Hash de la IP del cliente (los tres primeros octetos en IPv4) | Afinidad de sesión simple sin cookies | | Hash genérico | `hash clave [consistent]` | Hash de cualquier variable (URI, cabecera, argumento) | Cachés por URL, afinidad por usuario o por tenant | | Aleatorio | `random [two [least_conn]]` | Al azar, o el mejor de dos al azar | Varios balanceadores compartiendo los mismos backends | `least_time` y las comprobaciones de salud activas (`health_check`) solo existen en NGINX Plus, la versión comercial. Esta guía se centra en lo que incluye el paquete de Ubuntu. ## Paso 1: Instalar Nginx ```bash sudo apt update sudo apt install nginx ``` Desactiva el sitio por defecto, que también escucha en el puerto 80: ```bash sudo rm /etc/nginx/sites-enabled/default ``` Si usas UFW, permite HTTP: ```bash sudo ufw allow 'Nginx HTTP' ``` ## Paso 2: Crear tres backends de prueba Cada backend responde con su nombre, lo que permite ver a qué servidor ha ido cada petición. Crea el archivo: ```bash sudo nano /etc/nginx/conf.d/test-backends.conf ``` ```nginx server { listen 127.0.0.1:8081; default_type text/plain; location / { return 200 "backend-1\n"; } } server { listen 127.0.0.1:8082; default_type text/plain; location / { return 200 "backend-2\n"; } } server { listen 127.0.0.1:8083; default_type text/plain; location / { return 200 "backend-3\n"; } } ``` Comprueba la sintaxis, recarga y prueba uno de ellos: ```bash sudo nginx -t sudo systemctl reload nginx curl http://127.0.0.1:8082 ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful backend-2 ``` ## Paso 3: Configurar el balanceador con round robin Crea el sitio del balanceador: ```bash sudo nano /etc/nginx/sites-available/loadbalancer ``` ```nginx upstream app_backend { server 127.0.0.1:8081; server 127.0.0.1:8082; server 127.0.0.1:8083; } server { listen 80; server_name _; location / { proxy_pass http://app_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Sin ninguna directiva de algoritmo, Nginx usa round robin: cada petición va al siguiente servidor de la lista. Activa el sitio y recarga: ```bash sudo ln -s /etc/nginx/sites-available/loadbalancer /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` Lanza seis peticiones: ```bash for i in $(seq 1 6); do curl -s http://localhost/; done ``` ```output backend-1 backend-2 backend-3 backend-1 backend-2 backend-3 ``` Para el resto de la guía solo cambiarás el bloque `upstream` de `/etc/nginx/sites-available/loadbalancer`. Después de cada cambio, ejecuta `sudo nginx -t && sudo systemctl reload nginx`. La recarga no corta las conexiones en curso. ## Paso 4: Repartir por capacidad con pesos Si un servidor tiene el triple de CPU que los demás, dale más peso. El valor por defecto es `weight=1`: ```nginx upstream app_backend { server 127.0.0.1:8081 weight=3; server 127.0.0.1:8082; server 127.0.0.1:8083; } ``` Recarga y cuenta cómo se reparten 100 peticiones: ```bash for i in $(seq 1 100); do curl -s http://localhost/; done | sort | uniq -c ``` ```output 60 backend-1 20 backend-2 20 backend-3 ``` Nginx usa un round robin ponderado "suave": intercala los servidores (1, 2, 1, 3, 1...) en lugar de enviar tres peticiones seguidas al mismo. Los pesos también se aplican con `least_conn`, `ip_hash`, `hash` y `random`. ## Paso 5: Menos conexiones activas con least_conn Round robin asume que todas las peticiones cuestan lo mismo. Si unas tardan 20 ms y otras 20 segundos (informes, subidas de archivos, WebSocket), un servidor puede acumular muchas conexiones lentas mientras otro está libre. `least_conn` envía cada petición al servidor con menos conexiones activas en relación con su peso: ```nginx upstream app_backend { least_conn; server 127.0.0.1:8081; server 127.0.0.1:8082; server 127.0.0.1:8083; } ``` En el laboratorio las respuestas son instantáneas, así que el reparto se parecerá al de round robin (cuando hay empate, Nginx aplica round robin entre los empatados). La diferencia aparece con tráfico real de duración variable. Para aplicaciones con WebSocket, `least_conn` suele ser la mejor opción por defecto. ## Paso 6: Afinidad de sesión con ip_hash y hash Si la aplicación guarda la sesión en la memoria de cada servidor, el mismo usuario debe volver siempre al mismo backend. `ip_hash` lo consigue a partir de la IP del cliente: ```nginx upstream app_backend { ip_hash; server 127.0.0.1:8081; server 127.0.0.1:8082; server 127.0.0.1:8083; } ``` ```bash for i in $(seq 1 6); do curl -s http://localhost/; done | sort | uniq -c ``` ```output 6 backend-3 ``` Todas las peticiones desde la misma IP van al mismo servidor. Ten en cuenta dos limitaciones: en IPv4 solo se usan los tres primeros octetos, así que toda una red `/24` cae en el mismo backend, y los usuarios detrás de un mismo NAT corporativo también. Si Nginx está detrás de otro proxy o de una CDN, todas las peticiones llegarán desde la IP del proxy salvo que configures el módulo `realip`. Para marcar temporalmente un servidor como fuera de servicio sin alterar el reparto del resto de clientes, usa el parámetro `down` en lugar de borrar la línea: ```nginx server 127.0.0.1:8083 down; ``` La directiva `hash` es más flexible: calcula el hash sobre cualquier variable. Con `consistent` usa hash consistente (ketama), de modo que al añadir o quitar un servidor solo se reasigna una pequeña parte de las claves en lugar de casi todas. Es la opción adecuada para repartir por URL delante de servidores de caché, o por usuario: ```nginx upstream app_backend { hash $arg_user consistent; server 127.0.0.1:8081; server 127.0.0.1:8082; server 127.0.0.1:8083; } ``` ```bash for u in ana luis marta ana luis marta; do printf '%s -> ' "$u"; curl -s "http://localhost/?user=$u" done ``` ```output ana -> backend-3 luis -> backend-2 marta -> backend-2 ana -> backend-3 luis -> backend-2 marta -> backend-2 ``` Cada usuario siempre llega al mismo backend. Otras claves habituales son `$request_uri` (cachés), `$cookie_sessionid` o `$http_x_tenant_id`. ## Paso 7: Algoritmo aleatorio `random` elige un servidor al azar teniendo en cuenta los pesos. Con `two`, elige dos al azar y se queda con el que tiene menos conexiones: ```nginx upstream app_backend { random two least_conn; server 127.0.0.1:8081; server 127.0.0.1:8082; server 127.0.0.1:8083; } ``` Su ventaja aparece cuando hay varios balanceadores Nginx delante de los mismos backends: cada uno solo conoce sus propias conexiones, y con `least_conn` puro todos tenderían a enviar tráfico al mismo servidor a la vez. La elección aleatoria entre dos evita ese efecto manada. ## Paso 8: Detección de fallos y servidores de respaldo Nginx de código abierto detecta los fallos de forma pasiva: cuando una petición a un servidor falla, la reintenta en el siguiente y cuenta el fallo. Tras `max_fails` fallos dentro de `fail_timeout`, deja de usar ese servidor durante `fail_timeout` y después vuelve a probarlo con tráfico real. Vuelve a round robin y añade un servidor que no existe (nada escucha en el puerto 8084) y un servidor de respaldo: ```nginx upstream app_backend { server 127.0.0.1:8081 max_fails=3 fail_timeout=30s; server 127.0.0.1:8082 max_fails=3 fail_timeout=30s; server 127.0.0.1:8084 max_fails=1 fail_timeout=30s; server 127.0.0.1:8083 backup; } ``` Para que los fallos se detecten rápido, limita también el tiempo de conexión en el bloque `location /` del mismo archivo: ```nginx proxy_connect_timeout 2s; proxy_next_upstream error timeout http_502 http_503; proxy_next_upstream_tries 2; ``` `proxy_next_upstream` define qué se considera fallo y se reintenta en otro servidor. Por defecto solo son `error` y `timeout`; aquí se añaden las respuestas 502 y 503 del backend. Reintentar solo es seguro para peticiones idempotentes: Nginx no reintenta un `POST` que ya se envió al backend salvo que añadas `non_idempotent`, y no deberías hacerlo. Recarga y prueba: ```bash for i in $(seq 1 6); do curl -s http://localhost/; done ``` ```output backend-1 backend-2 backend-1 backend-2 backend-1 backend-2 ``` Ningún cliente ha recibido un error: la petición que tocó al puerto 8084 se reintentó en otro servidor y el servidor caído quedó fuera durante 30 segundos. El log de errores lo registra: ```bash sudo grep 8084 /var/log/nginx/error.log | tail -n 1 ``` ```output 2026/09/25 10:41:07 [error] 2412#2412: *31 connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1, server: _, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8084/", host: "localhost" ``` El servidor `backup` (backend-3) solo recibe tráfico cuando todos los servidores principales están no disponibles. `backup` no se puede combinar con `ip_hash`, `hash` ni `random`. Cuando termines la prueba, elimina la línea del puerto 8084. ## Paso 9: Reutilizar conexiones con keepalive Por defecto Nginx abre una conexión TCP nueva con el backend en cada petición. Con muchas peticiones por segundo, eso añade latencia y llena la tabla de conexiones con sockets en `TIME_WAIT`. La directiva `keepalive` mantiene un conjunto de conexiones inactivas abiertas por cada proceso worker: ```nginx upstream app_backend { least_conn; server 127.0.0.1:8081 max_fails=3 fail_timeout=30s; server 127.0.0.1:8082 max_fails=3 fail_timeout=30s; server 127.0.0.1:8083 backup; keepalive 32; } ``` Para que funcione, el bloque `location` debe usar HTTP/1.1 hacia el backend y no reenviar la cabecera `Connection: close`. La configuración completa de `/etc/nginx/sites-available/loadbalancer` queda así: ```nginx upstream app_backend { least_conn; server 127.0.0.1:8081 max_fails=3 fail_timeout=30s; server 127.0.0.1:8082 max_fails=3 fail_timeout=30s; server 127.0.0.1:8083 backup; keepalive 32; } server { listen 80; server_name _; location / { proxy_pass http://app_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 2s; proxy_next_upstream error timeout http_502 http_503; proxy_next_upstream_tries 2; } } ``` `keepalive 32` es el número máximo de conexiones inactivas que cada worker guarda; no limita las conexiones totales. Si necesitas proteger a un backend de un exceso de conexiones, usa el parámetro `max_conns` en su línea `server`. Si el backend es una aplicación con WebSocket, usa un `location` específico con `proxy_set_header Upgrade $http_upgrade;` y `proxy_set_header Connection "upgrade";` en lugar de la cabecera `Connection` vacía. ## Paso 10: Ver la actividad del balanceador El módulo `stub_status`, incluido en el paquete de Ubuntu, ofrece contadores básicos de conexiones. Publícalo solo en localhost: ```bash sudo nano /etc/nginx/conf.d/status.conf ``` ```nginx server { listen 127.0.0.1:8080; location = /nginx_status { stub_status; } } ``` ```bash sudo nginx -t && sudo systemctl reload nginx curl http://127.0.0.1:8080/nginx_status ``` ```output Active connections: 1 server accepts handled requests 214 214 229 Reading: 0 Writing: 1 Waiting: 0 ``` Para saber qué backend atendió cada petición y cuánto tardó, añade las variables `$upstream_addr` y `$upstream_response_time` a un formato de log propio en `/etc/nginx/nginx.conf`, dentro del bloque `http`: ```nginx log_format upstream '$remote_addr "$request" $status ' 'upstream=$upstream_addr rt=$upstream_response_time'; ``` Y úsalo en el `server` del balanceador con `access_log /var/log/nginx/lb.log upstream;`. Si una petición se reintentó, `$upstream_addr` muestra todos los servidores probados separados por comas. ## Qué algoritmo elegir - **Aplicación sin estado y backends iguales**: round robin, con pesos si las máquinas son distintas. - **Duración de las peticiones muy variable o WebSocket**: `least_conn`. - **Sesiones guardadas en memoria del servidor**: `hash $cookie_ consistent` si puedes identificar al usuario, o `ip_hash` como solución rápida. A largo plazo es mejor mover las sesiones a Redis o a la base de datos y usar round robin. - **Varios servidores de caché**: `hash $request_uri consistent`, para que cada URL se cachee en un solo servidor. - **Varios balanceadores Nginx en paralelo**: `random two least_conn`. ## Conclusión Has visto en funcionamiento los algoritmos de balanceo de Nginx de código abierto, cómo influyen los pesos, cómo se comporta el failover pasivo con `max_fails` y `backup`, y cómo reducir la latencia con conexiones keepalive hacia los backends. Como siguientes pasos, sustituye los backends de prueba por las IP privadas de tus servidores, añade HTTPS al balanceador con Certbot y, si necesitas comprobaciones de salud activas sin NGINX Plus, valora HAProxy como balanceador delante de tus aplicaciones.