Start typing to search across invoices, services, domains, tickets, and more...
Las aplicaciones hechas con Node.js, Python (Flask, Django, FastAPI) o Go suelen escuchar en un puerto local como 127.0.0.1:3000 y no deberían exponerse directamente a Internet. Esta guía muestra cómo configurar un proxy inverso con Nginx que reenvíe su dominio a la aplicación backend, gestione las conexiones WebSocket, transmita la IP real del cliente, añada HTTPS gratuito con certbot y cómo solucionar el error 502 Bad Gateway. Los comandos cubren Debian/Ubuntu y Rocky Linux/AlmaLinux.
Primero confirme que la aplicación responde en local; si no lo hace, el proxy siempre devolverá 502. Mantenga la aplicación vinculada a 127.0.0.1 para que solo Nginx sea público, y ejecútela con systemd o pm2 para que se reinicie automáticamente tras un fallo.
# Debian / Ubuntu
apt update && apt install -y nginx
# Rocky Linux / AlmaLinux
dnf install -y nginx
systemctl enable --now nginx
# Compruebe que la app backend escucha en local (ejemplo: puerto 3000)
ss -lntp | grep 3000
curl -I http://127.0.0.1:3000
Apunte el DNS de su dominio a la IP del servidor y cree /etc/nginx/conf.d/app.conf. El bloque map deja pasar tanto las solicitudes normales como las de actualización a WebSocket; las cabeceras X-Forwarded-* transmiten la IP del cliente y el esquema original a la aplicación; un proxy_read_timeout más largo evita que se corten las solicitudes lentas o de larga duración. Aumente client_max_body_size si los usuarios suben archivos grandes.
# /etc/nginx/conf.d/app.conf (included on Debian/Ubuntu and Rocky/AlmaLinux)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name app.example.com;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
# Soporte de WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 10s;
proxy_read_timeout 300s;
}
}
Ejecute siempre nginx -t antes de recargar. En Rocky/AlmaLinux, SELinux impide que Nginx se conecte a los puertos del backend hasta que active httpd_can_network_connect. Permita los puertos 80 y 443 en el firewall (consulte nuestro tutorial de firewall en Linux para más reglas).
nginx -t && systemctl reload nginx
curl -I -H "Host: app.example.com" http://127.0.0.1
# Rocky/AlmaLinux (SELinux): permitir que Nginx se conecte a los puertos del backend
setsebool -P httpd_can_network_connect 1
# Abrir HTTP/HTTPS en el firewall
ufw allow 'Nginx Full' # Debian/Ubuntu with ufw
firewall-cmd --permanent --add-service=http --add-service=https
firewall-cmd --reload # Rocky/AlmaLinux
Detrás de un proxy inverso, todas las solicitudes parecen venir de 127.0.0.1. Nginx ya envía la dirección real en X-Real-IP y X-Forwarded-For; el framework solo tiene que confiar en el proxy local. Si delante de Nginx hay una CDN o un balanceador de carga, restaure la dirección en Nginx con el módulo real_ip y confíe solo en los rangos de la CDN para que la cabecera no pueda falsificarse.
// Node.js / Express: trust the proxy on localhost
app.set('trust proxy', 'loopback');
// req.ip now returns the real client IP
# Python Flask / cualquier app WSGI
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
# Gunicorn
gunicorn --bind 127.0.0.1:8000 --forwarded-allow-ips="127.0.0.1" app:app
# Solo si Nginx está detrás de una CDN o balanceador de carga (bloque http o server):
set_real_ip_from 203.0.113.0/24; # the CDN / LB address ranges
real_ip_header X-Forwarded-For;
real_ip_recursive on;
El plugin de Nginx de certbot obtiene un certificado de Let's Encrypt, añade un listener en el puerto 443 a su bloque server y, con --redirect, redirige a los visitantes de HTTP a HTTPS. El dominio ya debe resolver a este servidor y el puerto 80 debe ser accesible desde Internet. Los certificados duran 90 días y se renuevan automáticamente.
# Debian / Ubuntu
apt install -y certbot python3-certbot-nginx
# Rocky Linux / AlmaLinux (EPEL)
dnf install -y epel-release && dnf install -y certbot python3-certbot-nginx
certbot --nginx -d app.example.com --redirect -m [email protected] --agree-tos --no-eff-email
# La renovación se ejecuta con un temporizador de systemd; pruébela:
certbot renew --dry-run
systemctl list-timers | grep -i certbot
X-Forwarded-Proto. Configure la confianza en el proxy como se muestra en el paso 4.Un 502 significa que Nginx no recibió una respuesta válida del backend. Empiece por el log de errores de Nginx e identifique el mensaje: connection refused indica que la aplicación está detenida o en otro puerto; permission denied suele deberse a SELinux. Tenga en cuenta también que en Node 17+ «localhost» puede resolverse a la IPv6 ::1, de modo que la aplicación escucha en [::1]:3000 mientras Nginx se conecta a 127.0.0.1.
tail -n 50 /var/log/nginx/error.log
# connect() failed (111: Connection refused) -> app stopped or wrong port
# connect() ... (13: Permission denied) -> SELinux: setsebool -P httpd_can_network_connect 1
# upstream prematurely closed connection -> app crashed / restarted
# upstream timed out (110) -> app too slow: raise proxy_read_timeout or fix the app
systemctl status myapp
journalctl -u myapp -n 100 --no-pager
ss -lntp | grep -E ':3000|:8000' # 127.0.0.1:3000 vs [::1]:3000 ?
Asegúrese de que estén configurados proxy_http_version 1.1 y las cabeceras Upgrade y Connection. Si hay una CDN delante, active también allí el soporte de WebSocket. Las conexiones inactivas se cierran por defecto a los 60 segundos, así que aumente proxy_read_timeout o envíe heartbeats desde la aplicación.
Sí. Cree un bloque server por dominio apuntando a distintos puertos, o enrute distintas rutas location dentro de un mismo dominio. Si cada sitio necesita su propia dirección IP, consulte nuestro tutorial de Nginx con una IP dedicada por sitio.
Un 504 significa que el backend respondió demasiado lento. Optimice la solicitud lenta o aumente proxy_read_timeout, y revise en el log de la aplicación si hay bloqueos en la base de datos o en APIs externas.
¿Sigue con problemas después de seguir estos pasos? Abra un ticket de soporte y el equipo técnico de IMIDC, disponible 24/7, le ayudará. Incluya la IP del servidor, la versión del sistema operativo, los comandos que ejecutó y la salida completa del error para que podamos localizar el problema más rápido.