Configuración de proxies inversos con Nginx para aplicaciones Node.js

El uso de Nginx como proxy inverso delante de aplicaciones Node.js es una práctica estándar para mejorar rendimiento, seguridad y escalabilidad. En esta guía técnica y práctica repasaremos la configuración básica y avanzada: SSL/TLS con Let’s Encrypt, soporte de WebSockets, balanceo de carga, optimizaciones de tiempo de respuesta y recomendaciones de seguridad.

Por qué usar Nginx delante de Node.js

Node.js es excelente manejando I/O asíncrono, pero delegar responsabilidades de transporte y cache a Nginx aporta beneficios claros:

  • Terminación SSL eficiente y gestión de certificados.
  • Soporte estable para conexiones estáticas y compresión (gzip).
  • Balanceo de carga y manejo de sesiones para múltiples instancias Node.
  • Protección frente a ataques de capa 7 mediante límites y cabeceras.
  • Compatibilidad con WebSockets y proxys HTTP/2.

Arquitectura típica

Diagrama simplificado:

  • Cliente <-> Nginx (SSL, HTTP/2, cache) <-> Node.js (pm2, systemd)
  • Para alta disponibilidad: varios Nginx frente a varios backends Node

Configuración mínima: bloque server

Ejemplo de bloque Nginx para servir una app Node.js en el puerto 3000. Coloca este archivo en /etc/nginx/sites-available/tu_app y crea el enlace simbólico a sites-enabled.

upstream app_node {
    server 127.0.0.1:3000;
    # server 127.0.0.1:3001;  # instancias adicionales para balanceo
}

server {
    listen 80;
    server_name ejemplo.com www.ejemplo.com;

    location / {
        proxy_pass http://app_node;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_read_timeout 90;
    }
}

Notas sobre la configuración

  • proxy_http_version 1.1 y cabeceras Upgrade/Connection son necesarias para WebSockets.
  • proxy_read_timeout evita timeouts en peticiones largas (subidas, SSE, etc.).
  • Usa upstream para facilitar el balanceo y la salud de instancias.

SSL/TLS: terminación con Let’s Encrypt

Es recomendable que Nginx maneje TLS. Let’s Encrypt permite certificados gratuitos y automatizados. El flujo típico:

  • Instalar Certbot y obtener certificados.
  • Configurar server blocks para redireccionar HTTP a HTTPS y usar certificados.

Ejemplo simplificado tras obtener certificados:

server {
    listen 80;
    server_name ejemplo.com www.ejemplo.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ejemplo.com www.ejemplo.com;

    ssl_certificate /etc/letsencrypt/live/ejemplo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ejemplo.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://app_node;
        # cabeceras y ajustes como antes
    }
}

Consulta la documentación oficial de Let’s Encrypt para automatizar renovaciones y opciones avanzadas.

Soporte para WebSockets y SSE

Las aplicaciones en tiempo real (Socket.io, ws) requieren proxys que mantengan la conexión. Los puntos clave ya vistos son:

  • proxy_http_version 1.1
  • proxy_set_header Upgrade $http_upgrade
  • proxy_set_header Connection ‘upgrade’
  • aumentar proxy_read_timeout para conexiones persistentes

Además, revisa compatibilidad de HTTP/2 si debes proxear WebSockets (HTTP/2 no soporta WebSockets nativamente; Nginx lo negocia correctamente si la conexión entre cliente y Nginx es HTTP/2 y la conexión Nginx-Node es HTTP/1.1).

Para conceptos de WebSockets consulta la referencia en MDN Web Docs.

Balanceo de carga y sticky sessions

Nginx ofrece varios métodos de balanceo: round-robin (por defecto), ip_hash o least_conn. Ejemplo con least_conn:

upstream app_node {
    least_conn;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
}

Si tu aplicación requiere afinidad de sesión, usa ip_hash o implementa sesiones compartidas en Redis para escalar sin sticky sessions.

Optimización de rendimiento y seguridad

  • client_max_body_size 10M para controlar subidas de archivos.
  • Gzip para respuestas estáticas: activar gzip con niveles moderados.
  • Desactivar proxy_buffering para respuestas en tiempo real cuando sea necesario.
  • Limitar conexiones por IP y peticiones por segundo para mitigar abusos.
  • Configurar cabeceras HSTS, X-Frame-Options y Content-Security-Policy desde Nginx.
server {
    # límites básicos
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;

    location / {
        limit_conn addr 10;
        limit_req zone=req burst=20 nodelay;
        proxy_pass http://app_node;
    }
}

Despliegue y gestión de procesos Node.js

Para producción, ejecuta Node.js con un gestor de procesos como pm2 o systemd. pm2 facilita la administración y reinicio automático:

# instalar pm2
npm install -g pm2

# arrancar la app
pm2 start app.js --name 'app'
pm2 startup
pm2 save

Si usas systemd, crea un servicio que arranque tu aplicación y permita logs y reinicios configurables.

Monitoreo y logging

  • Habilita access_log y error_log en Nginx con rotación (logrotate).
  • Centraliza logs de Node.js con herramientas como ELK o Prometheus + Grafana.
  • Monitorea métricas clave: latencia, conexiones activas, throughput y errores 5xx.

Buenas prácticas y checklist antes de producción

  • Probar comportamiento con cargas concurrentes y WebSockets.
  • Verificar renovación automática de certificados Let’s Encrypt.
  • Auditar cabeceras de seguridad y políticas CSP/HSTS.
  • Establecer límites de recursos y políticas de reintento en el cliente.
  • Hacer pruebas de failover para balanceo y recuperación de nodos.

Enlaces de referencia

Documentación oficial de Nginx sobre proxy y módulos: NGINX.org – ngx_http_proxy_module. Para gestión de certificados usa Let’s Encrypt. Para conceptos de WebSockets y APIs web, revisa MDN Web Docs.

Conclusión

Configurar Nginx como proxy inverso para aplicaciones Node.js es una solución madura y flexible que mejora seguridad, rendimiento y escalabilidad. Empieza con una configuración simple—terminación TLS, proxy_pass y cabeceras para WebSockets—y añade balanceo, límites y monitoreo según crezcan tus necesidades. Aplicando las prácticas descritas ahorrarás tiempo en operación y obtendrás una plataforma más robusta para despliegues en producción.