Despliegue de Aplicaciones FastAPI en Linux
FastAPI es un framework web moderno de Python para construir APIs de alto rendimiento, con soporte nativo para tipos estáticos, documentación automática y programación asíncrona. Desplegar FastAPI en producción en Linux implica configurar Uvicorn como servidor ASGI, Gunicorn como gestor de procesos, Nginx como proxy inverso y systemd para gestión del servicio. Esta guía cubre el despliegue completo de FastAPI, incluyendo SSL, optimización de rendimiento y despliegue con Docker.
Requisitos Previos
- Ubuntu 20.04+ o Rocky Linux 8+
- Python 3.8+ instalado
- Nginx instalado
- Acceso root o sudo
- Dominio configurado apuntando al servidor (para SSL)
# Verificar Python
python3 --version
# Instalar herramientas necesarias
apt update && apt install -y python3-pip python3-venv nginx certbot python3-certbot-nginx
# dnf install -y python3 python3-pip nginx certbot python3-certbot-nginx # Rocky Linux
Preparación del Entorno Python
# Crear usuario dedicado para la aplicación
useradd -r -s /bin/bash -d /opt/fastapi-app fastapi
mkdir -p /opt/fastapi-app
chown fastapi:fastapi /opt/fastapi-app
# Crear entorno virtual Python
su - fastapi -s /bin/bash
python3 -m venv /opt/fastapi-app/venv
source /opt/fastapi-app/venv/bin/activate
# Instalar FastAPI y sus dependencias de producción
pip install fastapi uvicorn[standard] gunicorn
# Instalar dependencias del proyecto
# pip install -r requirements.txt
# Crear aplicación FastAPI de ejemplo
cat > /opt/fastapi-app/main.py << 'EOF'
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
app = FastAPI(
title="Mi API",
description="API de producción con FastAPI",
version="1.0.0"
)
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
@app.get("/")
async def root():
return {"message": "API operativa", "status": "ok"}
@app.get("/health")
async def health_check():
return {"status": "healthy"}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id > 1000:
raise HTTPException(status_code=404, detail="Item no encontrado")
return {"item_id": item_id, "name": "Item de ejemplo"}
@app.post("/items/")
async def create_item(item: Item):
return {"item": item, "message": "Item creado"}
EOF
# Verificar que la app inicia correctamente
cd /opt/fastapi-app
venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --reload &
sleep 2
curl http://127.0.0.1:8000/health
kill %1
Configuración de Uvicorn y Gunicorn
# Crear archivo de configuración de Gunicorn
cat > /opt/fastapi-app/gunicorn.conf.py << 'EOF'
# Configuración de Gunicorn para FastAPI en producción
import multiprocessing
# Dirección y puerto de enlace
bind = "unix:/opt/fastapi-app/fastapi.sock"
# Alternativa TCP: bind = "127.0.0.1:8000"
# Número de workers (2-4 por núcleo de CPU)
workers = multiprocessing.cpu_count() * 2 + 1
# Clase de worker ASGI para FastAPI
worker_class = "uvicorn.workers.UvicornWorker"
# Hilos por worker
threads = 2
# Timeout en segundos
timeout = 120
keepalive = 5
# Logs
accesslog = "/var/log/fastapi/access.log"
errorlog = "/var/log/fastapi/error.log"
loglevel = "warning"
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
# Reiniciar workers periódicamente para evitar fugas de memoria
max_requests = 1000
max_requests_jitter = 50
# Directorio de trabajo
chdir = "/opt/fastapi-app"
# PID file
pidfile = "/opt/fastapi-app/gunicorn.pid"
EOF
# Crear directorio de logs
mkdir -p /var/log/fastapi
chown fastapi:fastapi /var/log/fastapi
# Probar la configuración de Gunicorn
su - fastapi -s /bin/bash -c "
source /opt/fastapi-app/venv/bin/activate
gunicorn -c /opt/fastapi-app/gunicorn.conf.py main:app
"
Servicio systemd para FastAPI
# Crear el servicio systemd
cat > /etc/systemd/system/fastapi.service << 'EOF'
[Unit]
Description=FastAPI Application con Gunicorn
After=network.target
Wants=network-online.target
[Service]
Type=notify
User=fastapi
Group=fastapi
WorkingDirectory=/opt/fastapi-app
RuntimeDirectory=fastapi
# Activar entorno virtual
Environment=PATH=/opt/fastapi-app/venv/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONDONTWRITEBYTECODE=1
Environment=PYTHONUNBUFFERED=1
# Cargar variables de entorno desde archivo .env
EnvironmentFile=-/opt/fastapi-app/.env
# Comando de inicio
ExecStart=/opt/fastapi-app/venv/bin/gunicorn \
-c /opt/fastapi-app/gunicorn.conf.py \
main:app
ExecReload=/bin/kill -s HUP $MAINPID
# Reinicio automático
Restart=on-failure
RestartSec=5s
# Seguridad
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/fastapi-app /var/log/fastapi
[Install]
WantedBy=multi-user.target
EOF
# Habilitar y arrancar el servicio
systemctl daemon-reload
systemctl enable --now fastapi.service
systemctl status fastapi.service
# Ver logs en tiempo real
journalctl -u fastapi.service -f
Nginx como Proxy Inverso
# Configurar Nginx para FastAPI
cat > /etc/nginx/sites-available/fastapi << 'EOF'
# Rate limiting para la API
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# Upstream FastAPI (socket Unix)
upstream fastapi_app {
server unix:/opt/fastapi-app/fastapi.sock fail_timeout=0;
}
server {
listen 80;
server_name api.midominio.com;
# Redirigir a HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name api.midominio.com;
# Certificados SSL (ver sección siguiente)
ssl_certificate /etc/letsencrypt/live/api.midominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.midominio.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Límite de tamaño del cuerpo de la solicitud
client_max_body_size 100M;
# Timeouts
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
# Headers de seguridad
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
# Proxy a Gunicorn
location / {
# Rate limiting
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://fastapi_app;
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_redirect off;
}
# Documentación OpenAPI (acceso restringido en producción)
location /docs {
# Permitir solo desde IPs internas
allow 10.0.0.0/8;
allow 192.168.0.0/16;
deny all;
proxy_pass http://fastapi_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /redoc {
allow 10.0.0.0/8;
deny all;
proxy_pass http://fastapi_app;
}
# Endpoint de health check (sin rate limit)
location /health {
proxy_pass http://fastapi_app;
proxy_set_header Host $host;
access_log off;
}
}
EOF
# Habilitar el sitio
ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
Configuración SSL con Let's Encrypt
# Obtener certificado SSL gratuito con Certbot
certbot --nginx -d api.midominio.com --email [email protected] --agree-tos --no-eff-email
# Verificar renovación automática
certbot renew --dry-run
# Verificar que el timer de renovación está activo
systemctl status certbot.timer
Despliegue con Docker
# Dockerfile para FastAPI
cat > /opt/fastapi-app/Dockerfile << 'EOF'
FROM python:3.11-slim
# Crear usuario no root
RUN useradd -r -s /bin/bash appuser
# Directorio de trabajo
WORKDIR /app
# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Instalar dependencias Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copiar código de la aplicación
COPY . .
RUN chown -R appuser:appuser /app
USER appuser
# Exponer puerto
EXPOSE 8000
# Comando de inicio
CMD ["gunicorn", "-c", "gunicorn.conf.py", "main:app"]
EOF
# Docker Compose para producción
cat > /opt/fastapi-app/docker-compose.yml << 'EOF'
version: '3.8'
services:
fastapi:
build: .
container_name: fastapi-app
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./logs:/var/log/fastapi
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/dbname
- SECRET_KEY=${SECRET_KEY}
env_file:
- .env
networks:
- api-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_DB: apidb
POSTGRES_USER: apiuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- api-network
volumes:
postgres_data:
networks:
api-network:
driver: bridge
EOF
# Construir y desplegar
docker-compose up -d --build
# Verificar estado
docker-compose ps
docker-compose logs fastapi
Optimización de Rendimiento
# Ajustar el número de workers según la carga
# Para aplicaciones IO-bound (más conexiones concurrentes)
# workers = (2 * cpu_count) + 1
# Para aplicaciones CPU-bound (cálculos intensivos)
# workers = cpu_count
# Ver número de CPUs disponibles
nproc
# Configurar límites del sistema para muchas conexiones
cat >> /etc/security/limits.conf << 'EOF'
fastapi soft nofile 65536
fastapi hard nofile 65536
EOF
cat >> /etc/sysctl.d/99-fastapi.conf << 'EOF'
# Optimizaciones para servidor API de alto tráfico
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 5000
EOF
sysctl -p /etc/sysctl.d/99-fastapi.conf
# Configurar rotación de logs de Nginx y FastAPI
cat > /etc/logrotate.d/fastapi << 'EOF'
/var/log/fastapi/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
systemctl reload fastapi
endscript
}
EOF
Solución de Problemas
El servicio FastAPI no inicia:
journalctl -u fastapi.service -n 50
# Ver errores de Python específicos
su - fastapi -s /bin/bash -c "source /opt/fastapi-app/venv/bin/activate && python main.py"
Error 502 Bad Gateway en Nginx:
# Verificar que el socket existe
ls -la /opt/fastapi-app/fastapi.sock
# Verificar permisos del socket
stat /opt/fastapi-app/fastapi.sock
# Gunicorn debe poder escribir en el socket y Nginx leer
ls -la /opt/fastapi-app/
# El usuario nginx debe tener acceso al directorio del socket
usermod -aG fastapi www-data
Aplicación lenta en producción:
# Verificar número de workers activos
ps aux | grep gunicorn | wc -l
# Ver métricas de tiempo de respuesta en logs de Nginx
tail -100 /var/log/nginx/access.log | awk '{print $NF}' | sort -n | tail -20
# Ajustar timeout y workers en gunicorn.conf.py
Errores de importación de módulos Python:
# Verificar que el entorno virtual está activado
source /opt/fastapi-app/venv/bin/activate
python -c "import fastapi; print(fastapi.__version__)"
# Reinstalar dependencias si hay conflictos
pip install -r requirements.txt --force-reinstall
Conclusión
Desplegar FastAPI en producción en Linux con Gunicorn, systemd y Nginx como proxy inverso proporciona una arquitectura robusta, escalable y fácil de mantener. La combinación de workers asíncronos de Uvicorn con la gestión de procesos de Gunicorn permite manejar alta concurrencia eficientemente, mientras que systemd garantiza la disponibilidad continua del servicio. Para aplicaciones de mayor escala, considera añadir Redis para caché, Celery para tareas asíncronas y un balanceador de carga delante de múltiples instancias.


