green snake
Photo by Pixabay on Pexels.com

Guía completa para desplegar FastAPI en producción: Operaciones confiables con Uvicorn multi-workers, Docker y un proxy inverso


Objetivo y visión general

Esta guía te lleva un paso más allá del modo de desarrollo (uvicorn app.main:app --reload) y organiza el “camino que inevitablemente recorres” cuando expones una app FastAPI al mundo exterior:

  • Qué tener en cuenta en producción
  • Construir una configuración de servidor ASGI usando Uvicorn multi-workers
  • Desplegar con Docker
  • Poner Nginx (o similar) delante como proxy inverso (HTTPS, encabezados, etc.)

La documentación oficial de FastAPI también destaca conceptos de producción como HTTPS, método de arranque, reinicios, replicación (cantidad de procesos) y memoria. Aquí traducimos esas ideas a configuraciones y ejemplos concretos.


A quién beneficia (perfiles concretos)

Desarrolladores en solitario / estudiantes (VPS o nube pequeña)

  • Construiste una app FastAPI, pero no sabes cómo debería verse el “arranque en producción”.
  • Quieres acceso público estable para ti o para un número pequeño de usuarios.
  • Has tocado Docker, pero quieres la “forma FastAPI + Docker”.

→ Obtendrás una configuración mínima y práctica con Uvicorn multi-workers + Docker, incluyendo comandos y Dockerfiles.

Ingenieros backend de equipos pequeños

  • Tu equipo eligió FastAPI y quieres un flujo de despliegue repetible en producción.
  • Estás considerando un proxy inverso (Nginx/Traefik) delante de uno o más servidores.
  • Quieres un modelo mental claro para reload/restart, cantidad de procesos, health checks y operación.

→ Verás la separación de responsabilidades entre Uvicorn, el proxy y la orquestación.

Equipos SaaS / startups (escalado futuro)

  • Esperas escalar después con Kubernetes o servicios gestionados de contenedores.
  • Quieres empezar simple (un solo contenedor) manteniendo en mente “replicar más tarde”.
  • Prefieres evitar configuraciones complejas con Gunicorn salvo que sea necesario.

→ Uvicorn moderno incluye ejecución multiproceso integrada, así que puedes mantener la arquitectura base simple y escalar después.


Notas de accesibilidad (legibilidad y comprensión)

  • Estructura: “visión general → Uvicorn en producción → Docker → proxy inverso → ops/monitorización → hoja de ruta”
  • Términos: servidor ASGI / worker / proxy inverso se explican brevemente al primer uso y luego se reutilizan de forma consistente
  • Código: las configuraciones se dividen en bloques pequeños con comentarios mínimos para reducir la carga cognitiva
  • Lector asumido: ya terminaste el tutorial de FastAPI una vez, pero cada sección se puede leer de forma independiente

1. Conceptos de despliegue en producción (qué decidir)

Antes de los comandos, aclara qué estás optimizando.

1.1 Puntos clave a considerar

  • HTTPS

    • Cifra la comunicación con el cliente.
    • A menudo lo gestiona un proxy inverso como Nginx/Traefik con automatización de certificados.
  • Arranque y reinicio

    • La app debe volver a levantarse tras reiniciar el servidor.
    • Si el proceso muere, algo debería reiniciarlo (systemd / orquestación de contenedores).
  • Replicación (cantidad de procesos)

    • Usa múltiples procesos para aprovechar los núcleos de CPU.
    • Ya sea con --workers de Uvicorn o con “más contenedores/pods” a nivel de clúster.
  • Memoria y recursos

    • Cada worker consume memoria; el número de workers está limitado por la RAM.
    • Decide cuántos procesos puedes permitirte por host.

Un buen modelo mental son tres capas:

App FastAPI (Uvicorn) / Proxy inverso (Nginx, etc.) / SO u Orquestador

Esto mantiene claros los roles y evita “configuraciones misteriosas”.


2. Arrancar Uvicorn para producción: multi-workers y opciones

Antes, “Gunicorn + UvicornWorker” era común. Pero versiones recientes de Uvicorn (a menudo citadas alrededor de 0.30+) incluyen un supervisor multiproceso integrado, por lo que --workers puede ser suficiente.

2.1 Comando mínimo para producción

Comando típico de desarrollo:

uvicorn app.main:app --reload

Ejemplo simple orientado a producción:

uvicorn app.main:app \
  --host 0.0.0.0 \
  --port 8000 \
  --workers 4

Diferencias clave:

  • Quita --reload (vigilar archivos es innecesario y riesgoso en producción)
  • Usa --host 0.0.0.0 para que clientes externos (o contenedores) puedan acceder
  • Define --workers según los núcleos de CPU (a menudo “núcleos” a “2× núcleos” como punto de partida)

2.2 Opciones adicionales útiles

  • --limit-concurrency

    • Limita solicitudes concurrentes para evitar consumo descontrolado de CPU/memoria.
  • --limit-max-requests

    • Recicla workers tras cierto número de solicitudes para mitigar fugas de memoria con el tiempo.
  • --proxy-headers

    • Necesario detrás de un proxy inverso para que la app entienda la IP del cliente y el esquema original.

Ejemplo:

uvicorn app.main:app \
  --host 0.0.0.0 \
  --port 8000 \
  --workers 4 \
  --proxy-headers \
  --limit-max-requests 10000

3. Contenerizar FastAPI con Docker

Muchos despliegues en producción ejecutan FastAPI dentro de Docker. La documentación de FastAPI también ofrece plantillas Docker (“FastAPI in Containers – Docker”).

3.1 Un Dockerfile mínimo (estilo FastAPI CLI)

Ejemplo simple inspirado en la documentación, usando FastAPI CLI:

FROM python:3.11-slim

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

CMD ["fastapi", "run", "app/main.py", "--port", "80"]

Ejemplo de requirements.txt:

fastapi[standard]>=0.113.0,<0.114.0
uvicorn>=0.30.0,<0.31.0
sqlalchemy>=2.0.0,<3.0.0

Construir y ejecutar:

docker build -t my-fastapi-app .
docker run -d --name my-fastapi -p 8000:80 my-fastapi-app

Ahora puedes acceder a la app en http://localhost:8000.

3.2 Cambiar el contenedor para arrancar Uvicorn directamente

También puedes iniciar Uvicorn como comando del contenedor:

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4"]

Un principio operativo común es “un contenedor = un proceso”, y el escalado se hace ejecutando múltiples contenedores. En la práctica, muchos equipos siguen ejecutando algunos workers dentro de un contenedor con --workers y escalan contenedores/pods después con Kubernetes/ECS según sea necesario.


4. Combinar con un proxy inverso (Nginx / Traefik)

En muchos despliegues, FastAPI (Uvicorn) corre como backend HTTP y Nginx/Traefik delante maneja terminación HTTPS y enrutamiento.

4.1 ¿Por qué poner un proxy inverso delante?

  • Gestión de certificados HTTPS

    • Centraliza renovaciones de Let’s Encrypt y configuraciones TLS.
  • Entrega de archivos estáticos

    • Sirve imágenes/CSS/JS eficientemente con Nginx.
  • Balanceo de carga

    • Distribuye tráfico entre múltiples contenedores/hosts FastAPI.
  • Seguridad y límites

    • Listas blancas de IP, rate limits, basic auth, etc. en el borde.

4.2 Configuración simple de Nginx (un solo host)

Asumiendo que Uvicorn escucha en 127.0.0.1:8000:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

Ejecuta Uvicorn con --proxy-headers para que interprete correctamente estos encabezados reenviados.

4.3 Nginx + FastAPI en contenedores

Con Docker Compose, normalmente ejecutas Nginx y FastAPI en contenedores separados. Nginx puede reenviar a http://fastapi:8000 usando la resolución por nombre de servicio de Docker.


5. Variables de entorno y gestión de configuración

Los entornos de producción se sostienen (o se caen) por la higiene de configuración.

5.1 Qué varía por entorno

  • URL de base de datos
  • Claves/secretos de API
  • Flag de debug
  • Nivel de log

Mantenlo fuera del código: cárgalo desde variables de entorno.

5.2 Usar pydantic-settings

# app/core/settings.py
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "My FastAPI App"
    environment: str = "dev"
    database_url: str
    secret_key: str
    log_level: str = "info"

    class Config:
        env_file = ".env"

settings = Settings()

Patrón típico:

  • Producción: variables de entorno reales (sin archivo .env dentro de la imagen)
  • Desarrollo: .env por conveniencia

Ejemplo al ejecutar el contenedor:

docker run -d \
  -e ENVIRONMENT=prod \
  -e DATABASE_URL=postgresql+psycopg://... \
  -e SECRET_KEY=... \
  -p 8000:80 my-fastapi-app

6. Operación: monitorización y estrategia de reinicio

Después de “cómo arrancarlo”, la siguiente pregunta es “¿qué pasa cuando se rompe?”

6.1 Ejecutar directamente en un VPS: systemd

Si ejecutas Uvicorn en el host (sin Docker), systemd es un enfoque común:

[Unit]
Description=My FastAPI application
After=network.target

[Service]
User=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/local/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4 --proxy-headers
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Habilitar y arrancar:

systemctl enable my-fastapi
systemctl start my-fastapi

6.2 Orquestadores: reinicio, escalado, health checks

En Docker Compose / Kubernetes / ECS, configuras:

  • Reinicio automático al fallar
  • Cantidad de réplicas
  • Health checks (por ejemplo, endpoint /health)

Endpoint simple de health check:

# app/api/health.py
from fastapi import APIRouter

router = APIRouter()

@router.get("/health", tags=["health"])
def health_check():
    return {"status": "ok"}

7. Configuración mínima de referencia: Docker + Uvicorn + Nginx

Un ejemplo pequeño que combina todo.

7.1 Estructura de directorios

project/
  app/
    __init__.py
    main.py
    api/
      health.py
      ...
  requirements.txt
  docker-compose.yml
  Dockerfile
  nginx/
    default.conf

7.2 Dockerfile (contenedor FastAPI)

FROM python:3.11-slim

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4", "--proxy-headers"]

7.3 Configuración de Nginx

server {
    listen 80;
    server_name _;

    location / {
        proxy_pass         http://fastapi:8000;
        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;
    }
}

7.4 docker-compose.yml

version: "3.9"

services:
  fastapi:
    build: .
    container_name: fastapi-app
    environment:
      - ENVIRONMENT=prod
      - DATABASE_URL=sqlite:///./app.db
    expose:
      - "8000"

  nginx:
    image: nginx:1.27
    container_name: nginx-proxy
    ports:
      - "80:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - fastapi

Ejecutar:

docker-compose up -d --build

Flujo de tráfico:

  • http://localhost/ → Nginx
  • Nginx → fastapi:8000
  • FastAPI (Uvicorn) maneja la solicitud

8. Problemas comunes y soluciones

Síntoma Causa probable Solución
La IP del cliente siempre aparece como 127.0.0.1 No se interpretan los proxy headers Asegura que Nginx envíe encabezados y arranca Uvicorn con --proxy-headers
Enlaces HTTP/HTTPS mezclados Proxy y backend discrepan sobre el esquema Configura X-Forwarded-Proto en el proxy y asegúrate de que la app lo respete
Errores solo después de desplegar Variables de entorno o DB distintas Centraliza config (Settings + ENV) y prueba localmente en modo “similar a prod”
Caídas bajo carga Demasiados/pocos workers, presión de RAM Observa CPU/RAM/latencia; ajusta --workers y/o réplicas gradualmente
“¿Cuál arquitectura es correcta?” Demasiadas opciones Empieza con lo mínimo: Uvicorn multi-workers + Docker + proxy inverso simple

9. Hoja de ruta gradual (moverse hacia producción paso a paso)

  1. Desarrollo local

    • Usa --reload, construye funcionalidades, añade tests/logging.
  2. Probar Uvicorn “tipo producción” localmente

    • Quita --reload, prueba --workers y --limit-max-requests.
  3. Contenerizar con Docker

    • Construye una imagen reproducible; prueba Compose con DB si hace falta.
  4. Añadir un proxy inverso

    • Empieza con enrutamiento HTTP; añade terminación HTTPS y estáticos después.
  5. Desplegar en producción

    • VPS o nube (ECS/GKE/etc.), añade health checks, logs, métricas, pruebas de carga.
  6. Escalar más tarde

    • Pasa a Kubernetes cuando sea necesario, manteniendo el principio: “contenedor simple, escalar en la capa de plataforma”.

Resumen

  • El despliegue en producción trata sobre todo de HTTPS, comportamiento de arranque/reinicio, replicación y memoria.
  • Uvicorn moderno soporta multi-worker con --workers, permitiendo una base más simple (a menudo sin necesidad de Gunicorn).
  • Docker mejora la reproducibilidad y reduce el “drift” del entorno; un proxy inverso (Nginx/Traefik) facilita HTTPS, enrutamiento, archivos estáticos y seguridad en el borde.
  • No necesitas empezar con una arquitectura perfecta. Comienza con la forma mínima y estable—Uvicorn multi-workers + Docker—y añade proxy/orquestación a medida que crecen tus necesidades.

por greeden

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)