Reverse proxy con Nginx para aplicaciones backend

Capítulo 6

Tiempo estimado de lectura: 6 minutos

+ Ejercicio

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:

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

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 en location. En laboratorios básicos, suele ser más simple mantenerlo sin barra final y usar location /.

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.js

Verifica directo al backend:

curl -s http://127.0.0.1:3000/ | head

Paso 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 reload

Prueba a través de Nginx:

curl -s http://127.0.0.1:8080/ | head

Variació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/ | head

Nota: 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 (o lsof -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_pass apunta a la IP/puerto correctos y que el backend está en HTTP (no HTTPS) si usas http://.

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.log mensajes como upstream timed out.
  • Si la lentitud es esperada (reportes, exportaciones), aumenta proxy_read_timeout para ese location o 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

ElementoQué revisarEjemplo
DestinoIP/puerto correctos y backend activoproxy_pass http://127.0.0.1:3000;
HostPreservar host originalproxy_set_header Host $host;
IP clienteCadena de proxiesproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Esquemahttp/https para URLs y redirectsproxy_set_header X-Forwarded-Proto $scheme;
TimeoutsEvitar 504 por respuestas lentasproxy_read_timeout 30s;
Tamaño cuerpoControl de uploadsclient_max_body_size 10m;

Ahora responde el ejercicio sobre el contenido:

Al configurar Nginx como reverse proxy, ¿qué situación describe mejor un error 504 Gateway Timeout?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

Un 504 ocurre cuando Nginx alcanza al backend, pero este no responde a tiempo según el proxy_read_timeout (u otro timeout). En cambio, problemas de backend caído suelen dar 502 y cuerpos grandes generan 413.

Siguiente capítulo

Balanceo de carga básico con Nginx

Arrow Right Icon
Portada de libro electrónico gratuitaNginx para Principiantes: Domina el Servidor Web Moderno desde Cero
60%

Nginx para Principiantes: Domina el Servidor Web Moderno desde Cero

Nuevo curso

10 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.