Módulo 3: Reverse Proxy & Load Balancing
Nginx fundamentals: configuración para FastAPI
Esta cápsula te muestra Nginx funcional para FastAPI. Configuration mínima, escalable, production-ready. No mastery — lo que necesitas como backend dev.
Anatomía de nginx.conf
# /etc/nginx/nginx.conf
# Configuración global
worker_processes auto;
events {
worker_connections 1024;
}
# HTTP block — toda config de HTTP
http {
# MIME types, defaults
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logs
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Servers
include /etc/nginx/conf.d/*.conf;
}
Lo importante para ti: el bloque http { ... } contiene servers. Cada server es un site/domain.
Server block para FastAPI
# /etc/nginx/conf.d/my-api.conf
upstream backend {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
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;
# Timeouts
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
Anatomy:
upstream backend: define backend(s). En este caso, un solo uvicorn en port 8000.server { ... }: configuración paraapi.example.com.listen 80: escuchar HTTP en puerto 80 (HTTPS lo veremos en cap 4).location /: matchear todas las URLs.proxy_pass http://backend: forward al upstream.proxy_set_header: headers críticos.- Timeouts: prevenir requests colgados.
location blocks: routing
server {
listen 80;
server_name api.example.com;
# API routes
location /api {
proxy_pass http://backend;
proxy_set_header Host $host;
# ... headers ...
}
# Static files
location /static {
alias /var/www/static;
expires 30d;
access_log off;
}
# Frontend (SPA)
location / {
root /var/www/frontend;
try_files $uri /index.html;
}
}
location blocks definen handling per-path:
/api/*→ forward a backend./static/*→ serve files from disk./*→ serve frontend SPA.
Headers para FastAPI
Set siempre estos headers al proxy_pass:
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;
Host: original host header. App lo necesita para generar URLs absolutas.
X-Real-IP: IP cliente directo (después del último proxy).
X-Forwarded-For: lista de IPs en el path (cliente, proxies intermedios). $proxy_add_x_forwarded_for agrega current IP a la lista existente.
X-Forwarded-Proto: protocolo original (http o https). Útil cuando proxy termina SSL.
En FastAPI:
from fastapi import Request
@app.middleware("http")
async def use_forwarded_headers(request: Request, call_next):
forwarded_proto = request.headers.get("x-forwarded-proto", "http")
if forwarded_proto == "https":
request.scope["scheme"] = "https"
return await call_next(request)
O usar proxy_headers_middleware de uvicorn:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*'
--proxy-headers hace que uvicorn read X-Forwarded-* headers correctamente.
Timeouts: prevenir colgados
location /api {
proxy_pass http://backend;
# Tiempo para conectar a backend
proxy_connect_timeout 30s;
# Tiempo para enviar request a backend
proxy_send_timeout 30s;
# Tiempo para recibir response
proxy_read_timeout 30s;
# Para uploads grandes
client_max_body_size 100M;
client_body_timeout 60s;
}
Sin timeouts, requests pueden quedar colgados forever, leaking workers.
Para endpoints específicos (e.g., uploads largos):
location /upload {
proxy_pass http://backend;
proxy_read_timeout 300s; # 5 minutes
client_max_body_size 1G;
}
Buffering
proxy_buffering on; # default
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_buffering on: Nginx buffer entire response from backend antes de enviar a client. Útil para clients lentos.
proxy_buffering off: streaming directo. Útil para Server-Sent Events o downloads grandes.
location /stream {
proxy_pass http://backend;
proxy_buffering off; # SSE necesita streaming
proxy_cache off;
}
Logging
Default access log:
192.168.1.100 - - [10/May/2026:14:32:11 +0000] "GET /api/posts HTTP/1.1" 200 1234 "-" "curl/7.68.0"
Custom format con info útil:
log_format custom '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log custom;
Agrega $request_time (total time) y $upstream_response_time (tiempo del backend). Útil para debuggear performance.
WebSocket support
FastAPI puede tener WebSocket endpoints. Nginx requiere config especial:
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# WebSockets pueden ser long-lived
proxy_read_timeout 86400; # 24h
}
Upgrade y Connection headers son lo que hace que WebSocket funcione.
Configuración completa para FastAPI
# /etc/nginx/conf.d/api.conf
upstream fastapi_backend {
server 127.0.0.1:8000;
# Si tienes múltiples instances:
# server 127.0.0.1:8001;
# server 127.0.0.1:8002;
keepalive 32; # connection pool
}
server {
listen 80;
server_name api.example.com;
# Logs
access_log /var/log/nginx/api-access.log;
error_log /var/log/nginx/api-error.log warn;
# Body size para uploads
client_max_body_size 50M;
# Health check público (Nginx maneja, no llega a backend)
location /nginx-health {
access_log off;
return 200 "ok\n";
}
# Static files
location /static/ {
alias /var/www/static/;
expires 30d;
access_log off;
}
# API
location / {
proxy_pass http://fastapi_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# WebSocket
location /ws {
proxy_pass http://fastapi_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Esto es production-ready. ~50 líneas. Cubre: routing, headers, timeouts, static files, WebSocket.
Setup local con Docker
Para experimentar sin tocar tu deploy real:
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "127.0.0.1:8000:8000" # solo accessible internamente
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
docker-compose up
curl http://localhost:8080/health
Tu app accessible solo via Nginx. Replicar production setup localmente.
Reload sin downtime
Cambias config:
# Test config (NO aplicar)
sudo nginx -t
# Si OK, reload (sin downtime)
sudo nginx -s reload
Nginx hace graceful reload: nuevos workers con config nueva, viejos terminan requests in-flight.
Trampas y errores comunes
1. Olvidar proxy_set_header Host $host.
Sin esto, FastAPI recibe Host: 127.0.0.1 (Nginx). Genera URLs absolutas raras.
2. client_max_body_size muy bajo.
Default Nginx: 1MB. Uploads >1MB fail con 413. Aumentar según necesidad.
3. Timeout muy bajo en endpoint largo.
proxy_read_timeout 30s;
Endpoint de export de 5min timeout. Aumentar para endpoints específicos.
4. Sin proxy_http_version 1.1.
Default es HTTP/1.0. No keep-alive con backend. Performance peor.
5. keepalive en upstream sin proxy_set_header Connection "".
Sin override, Nginx envía Connection: close con keepalive. Conflict.
proxy_http_version 1.1;
proxy_set_header Connection "";
6. Logs no rotated.
/var/log/nginx/access.log puede crecer infinitamente. Configurar logrotate:
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
postrotate
nginx -s reopen
endscript
}
7. Reload sin testing.
nginx -s reload con config inválida → server muere. Siempre nginx -t primero.
Ejercicio: setup Nginx local
Paso 1: crear nginx.conf mínimo.
upstream app_backend {
server app:8000;
}
server {
listen 80;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Paso 2: crear docker-compose.yml.
(Como ejemplo arriba.)
Paso 3: levantar.
docker-compose up
Paso 4: test.
curl http://localhost:8080/health
# Hit Nginx → proxies a uvicorn → returns response
Paso 5: test headers.
Endpoint en FastAPI:
@app.get("/headers")
async def show_headers(request: Request):
return dict(request.headers)
curl http://localhost:8080/headers
# Esperas: x-forwarded-for, x-real-ip, host, etc.
Paso 6: experimentar con proxy_pass.
Cambiar header:
proxy_set_header X-Custom-Header "test-value";
Reload:
docker-compose exec nginx nginx -t
docker-compose exec nginx nginx -s reload
Verificar que header llega.
Resumen y siguiente paso
Lo que aprendiste:
- Anatomy de Nginx config: http → server → location.
upstreampara definir backends.proxy_passpara forward.- Headers críticos:
Host,X-Forwarded-*. - Timeouts para prevenir colgados.
- WebSocket requiere
Upgradeheaders. nginx -tpara test,nginx -s reloadpara apply sin downtime.
En la siguiente cápsula vamos a SSL termination. HTTPS configurado en Nginx, comunicación interna HTTP. Concepto crítico.
Recursos
- Nginx —
proxy_pass— referencia. - Nginx Beginner's Guide — official.
- Nginx + WebSockets — específico.
- DigitalOcean — Nginx as reverse proxy — tutorial.
Cápsula 03 de 08 — Módulo 3 — Deployment & System Design Guide