Qué es un reverse proxy (y por qué se usa)
Un reverse proxy es un servidor (Nginx) que recibe las solicitudes HTTP/HTTPS de los clientes y las reenvía a una o varias aplicaciones backend (por ejemplo Node.js, Python o Java). Para el cliente, Nginx “parece” ser el servidor final; internamente, Nginx actúa como intermediario.
Flujo típico:
- Cliente → Nginx: el navegador o cliente HTTP se conecta al puerto público (80/443 o 8080).
- Nginx → Aplicación: Nginx reenvía la solicitud a un puerto interno (por ejemplo 127.0.0.1:3000).
- Aplicación → Nginx: la app responde.
- Nginx → Cliente: Nginx devuelve la respuesta al cliente.
Ventajas prácticas: exponer un único punto de entrada, ocultar puertos internos, balancear tráfico, terminar TLS, aplicar límites (tamaño de cuerpo), y controlar timeouts para evitar conexiones colgadas.
Directiva clave: proxy_pass
La directiva proxy_pass indica a qué upstream (backend) se reenviará la solicitud. Ejemplo conceptual:
location / { proxy_pass http://127.0.0.1:3000; }Detalles importantes:
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
- Si usas
proxy_pass http://127.0.0.1:3000;(sin ruta), Nginx reenviará la URI tal cual. - Si usas
proxy_pass http://127.0.0.1:3000/;(con barra final), puede cambiar cómo se construye la ruta cuando hay prefijos enlocation. En laboratorios básicos, suele ser más simple mantenerlo sin barra final y usarlocation /.
Cabeceras imprescindibles al hacer proxy
Cuando Nginx reenvía una solicitud, conviene establecer cabeceras para que la aplicación sepa cuál fue el host original, el esquema (http/https) y la IP del cliente.
Host: preserva el host solicitado por el cliente (útil para apps multi-dominio o generación de URLs).X-Forwarded-For: cadena de IPs por las que pasó la solicitud; la app puede registrar la IP real del cliente.X-Forwarded-Proto: indica si el cliente llegó por http o https (muy importante si Nginx termina TLS).
Configuración típica:
proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;Opcional pero común: X-Real-IP para exponer una sola IP (la del cliente) a la app.
proxy_set_header X-Real-IP $remote_addr;Timeouts básicos y tamaño máximo de cuerpo
Los timeouts controlan cuánto espera Nginx en diferentes fases. Valores demasiado bajos pueden cortar respuestas lentas; valores demasiado altos pueden dejar conexiones ocupadas.
proxy_connect_timeout: tiempo para conectar al backend.proxy_send_timeout: tiempo para enviar la solicitud al backend.proxy_read_timeout: tiempo esperando la respuesta del backend (muy relevante para endpoints lentos).
Ejemplo razonable para empezar:
proxy_connect_timeout 5s;proxy_send_timeout 30s;proxy_read_timeout 30s;Para limitar el tamaño de uploads o cuerpos grandes (POST/PUT), usa:
client_max_body_size 10m;Si el cliente excede ese tamaño, Nginx responderá con 413 Request Entity Too Large.
Laboratorio reproducible: publicar una app local detrás de Nginx
Objetivo: levantar una app simple en 127.0.0.1:3000 y exponerla vía Nginx en http://localhost:8080 (o puerto 80 si lo prefieres).
Paso 1: levantar un backend de prueba (Node.js)
Crea un archivo app.js:
const http = require('http');const server = http.createServer((req, res) => { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ message: 'Hola desde el backend', method: req.method, url: req.url, headers: req.headers }, null, 2));});server.listen(3000, '127.0.0.1', () => { console.log('Backend escuchando en http://127.0.0.1:3000');});Ejecuta:
node app.jsVerifica directo al backend:
curl -s http://127.0.0.1:3000/ | headPaso 2: configurar Nginx como reverse proxy en 8080
Crea un archivo de configuración (por ejemplo /etc/nginx/conf.d/reverse-proxy-lab.conf o en el mecanismo de sitios de tu distro) con este servidor:
server { listen 8080; server_name _; client_max_body_size 10m; location / { proxy_pass http://127.0.0.1:3000; 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 5s; proxy_send_timeout 30s; proxy_read_timeout 30s; }}Valida y recarga Nginx:
sudo nginx -tsudo nginx -s reloadPrueba a través de Nginx:
curl -s http://127.0.0.1:8080/ | headVariación: exponer en puerto 80
Si quieres usar el puerto 80, cambia listen 8080; por listen 80; y prueba con:
curl -s http://127.0.0.1/ | headNota: en Linux, escuchar en 80 suele requerir permisos de root (Nginx normalmente ya corre con los permisos adecuados).
Verificación de cabeceras (Host, X-Forwarded-For, X-Forwarded-Proto)
Como el backend devuelve las cabeceras recibidas, puedes comprobar que Nginx está enviando lo esperado.
Comprobar Host
Envía un Host personalizado:
curl -s -H 'Host: miapp.local' http://127.0.0.1:8080/ | grep -i 'host'Deberías ver host con el valor miapp.local (o el host que uses).
Comprobar X-Forwarded-For y X-Real-IP
Ejecuta:
curl -s http://127.0.0.1:8080/ | egrep -i 'x-forwarded-for|x-real-ip'En local, normalmente verás 127.0.0.1. En un servidor real, verías la IP del cliente.
Comprobar X-Forwarded-Proto
En este laboratorio sin TLS, $scheme será http:
curl -s http://127.0.0.1:8080/ | grep -i 'x-forwarded-proto'Si más adelante terminas HTTPS en Nginx, este valor debería ser https.
Diagnóstico de errores comunes: 502 y 504
Error 502 Bad Gateway
Un 502 suele indicar que Nginx no pudo obtener una respuesta válida del backend (backend caído, puerto incorrecto, conexión rechazada, o error de protocolo).
Cómo reproducirlo: detén el backend Node (Ctrl+C) y vuelve a pedir:
curl -i http://127.0.0.1:8080/Acciones de diagnóstico:
- Verifica que el backend está escuchando:
ss -lntp | grep 3000(olsof -i :3000). - Prueba el backend directo:
curl -i http://127.0.0.1:3000/. - Revisa el log de errores de Nginx (ruta típica):
sudo tail -n 50 /var/log/nginx/error.log. - Confirma que
proxy_passapunta a la IP/puerto correctos y que el backend está en HTTP (no HTTPS) si usashttp://.
Error 504 Gateway Timeout
Un 504 significa que Nginx sí pudo conectar al backend, pero el backend tardó demasiado en responder (o Nginx esperó más de lo configurado en proxy_read_timeout).
Cómo reproducirlo: modifica temporalmente el backend para demorar la respuesta:
const http = require('http');const server = http.createServer((req, res) => { setTimeout(() => { res.setHeader('Content-Type', 'text/plain'); res.end('Respuesta lenta'); }, 35000);});server.listen(3000, '127.0.0.1');Con proxy_read_timeout 30s, esta respuesta debería provocar 504. Diagnóstico y solución:
- Confirma en
/var/log/nginx/error.logmensajes comoupstream timed out. - Si la lentitud es esperada (reportes, exportaciones), aumenta
proxy_read_timeoutpara eselocationo endpoint. - Si la lentitud no es esperada, perfila el backend (consultas lentas, bloqueos, falta de workers) y revisa recursos (CPU/RAM).
Checklist rápido de configuración de reverse proxy
| Elemento | Qué revisar | Ejemplo |
|---|---|---|
| Destino | IP/puerto correctos y backend activo | proxy_pass http://127.0.0.1:3000; |
| Host | Preservar host original | proxy_set_header Host $host; |
| IP cliente | Cadena de proxies | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| Esquema | http/https para URLs y redirects | proxy_set_header X-Forwarded-Proto $scheme; |
| Timeouts | Evitar 504 por respuestas lentas | proxy_read_timeout 30s; |
| Tamaño cuerpo | Control de uploads | client_max_body_size 10m; |