Reverse proxy
Un reverse proxy recibe el trafico externo y lo reenvia a uno o mas backends. El cliente solo habla con Nginx; las apps escuchan en localhost o en una red privada.
Por que usarlo
Internet -> :443 Nginx
|-- / -> 127.0.0.1:3000 (frontend SSR / API)
|-- /api/ -> 127.0.0.1:8080 (API)
+-- /static/ -> discoVentajas: un solo punto TLS, routing por path/host, ocultar puertos internos, centralizar logs y limites.
proxy_pass basico
Backend de ejemplo (cualquier app en 3000):
# ejemplo minimo: responder en 3000 (python)
python3 -m http.server 3000 --bind 127.0.0.1Config Nginx:
server {
listen 80;
server_name app.local;
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;
}
}sudo nginx -t && sudo systemctl reload nginx
curl -H 'Host: app.local' http://127.0.0.1/Barra final en proxy_pass
Comportamiento distinto segun la URI en proxy_pass:
| location | proxy_pass | Peticion | Upstream recibe |
|---|---|---|---|
/api/ | http://127.0.0.1:8080/ | /api/users | /users |
/api/ | http://127.0.0.1:8080 | /api/users | /api/users |
/api | http://127.0.0.1:8080 | /api/users | /api/users |
Si la app espera rutas sin el prefijo /api, usa URI con barra en proxy_pass para recortar el location.
location /api/ {
proxy_pass http://127.0.0.1:8080/;
}Cabeceras reenviadas
Sin Host y X-Forwarded-*, el backend ve Host: 127.0.0.1:8080 y genera URLs o redirects incorrectos.
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_set_header X-Forwarded-Host $host;La app debe confiar en estos headers solo desde Nginx (no exponer el puerto del backend a internet).
WebSockets
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}Sin Upgrade/Connection, el handshake WebSocket falla.
Timeouts y buffers
location / {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 16 8k;
}connect: tiempo para abrir TCP al backend.read/send: inactividad durante la transferencia.- Sube
proxy_read_timeouten uploads largos o SSE; bajaconnectpara fallar rapido si el backend esta muerto.
Errores del upstream
location / {
proxy_pass http://127.0.0.1:3000;
proxy_intercept_errors on;
error_page 502 503 504 /50x.html;
}
location = /50x.html {
root /var/www/errors;
internal;
}Pagina amigable cuando el backend no responde. internal evita que alguien pida /50x.html directamente como atajo.
Varios hosts
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
include /etc/nginx/proxy_params; # si la distro lo aporta
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Ejemplo: static + API
server {
listen 80;
server_name shop.local;
root /var/www/shop;
location /api/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
location / {
try_files $uri $uri/ /index.html;
}
}Comprobar el proxy
sudo nginx -t && sudo systemctl reload nginx
curl -v -H 'Host: app.local' http://127.0.0.1/api/health
sudo tail -f /var/log/nginx/access.logSi ves 502 Bad Gateway, el backend no escucha o el firewall local bloquea. Revisa:
ss -tlnp | grep 3000
sudo tail -n 50 /var/log/nginx/error.logBuenas practicas
- Backends solo en
127.0.0.1o red privada; nunca publicar el puerto de la app. - Siempre reenviar
HostyX-Forwarded-Proto. - Timeouts explicitos; no depender de defaults eternos.
- Un
locationpor prefijo claro (/api/,/ws/). - Paginas
error_pagepara 502/504 en produccion.
Errores habituales
- Barra final mal puesta en
proxy_pass(rutas 404 en el backend). - Olvidar headers: redirects absolutos a
http://127.0.0.1. - WebSockets sin
Upgrade/Connection. proxy_pass http://backendsin quebackendeste definido comoupstreamo IP.- 502 por app caida y no mirar
error.log(connect() failed).
Ejercicios
- Levanta un servidor en
127.0.0.1:3000y proxea/desde Nginx; verifica concurlel headerX-Forwarded-Foren logs del backend (o un echo server). - Configura
/api/con y sin barra enproxy_passy documenta que path llega al upstream. - Para el backend y confirma
502; anadeerror_pagey una pagina estatica de mantenimiento. - Anade un location
/ws/con headers de Upgrade (aunque no tengas WS real, validanginx -ty la config).
Siguiente paso
En el capitulo 4 anadiras certificados, redireccion HTTP->HTTPS, HTTP/2 y renovacion con Let's Encrypt.
