Difficulty: Advanced
Running FastAPI in production requires careful configuration of the ASGI server. Uvicorn is the recommended server, but production deployment differs significantly from development. You need multiple worker processes, proper logging, SSL/TLS configuration, and process management.
In development, you run uvicorn main:app --reload with a single worker process. In production, you remove --reload (it adds overhead and watches files unnecessarily) and add multiple workers with --workers N. The number of workers should be (2 * CPU cores) + 1 as a starting point. Each worker is an independent process that handles requests concurrently.
Gunicorn with UvicornWorker is the recommended production setup. Gunicorn provides robust process management: automatic worker restarts on crashes, graceful shutdown on SIGTERM, pre-forking for efficient memory usage, and signal handling. The command is: gunicorn main:app -k uvicorn.workers.UvicornWorker -w 4.
SSL/TLS can be terminated at Uvicorn or, more commonly, at a reverse proxy (Nginx, Traefik, or a cloud load balancer). If terminating at Uvicorn, use --ssl-certfile and --ssl-keyfile. In most production setups, a reverse proxy handles SSL and forwards plain HTTP to Uvicorn.
Logging configuration is important for monitoring and debugging. Uvicorn uses Python's logging module. In production, set the log level to 'info' or 'warning' (not 'debug'). Use structured logging (JSON format) for easy parsing by log aggregation tools like ELK or Datadog. Configure access logs to include request method, path, status code, and timing.
Performance tuning involves several factors: number of workers (CPU-bound), backlog size (connection queue), keep-alive timeout (connection reuse), and limit-concurrency (maximum simultaneous connections per worker). Monitor your application's metrics to find optimal values.
# Development
uvicorn main:app --reload
# Production (single process)
uvicorn main:app \
--host 0.0.0.0 \
--port 8000 \
--workers 4 \
--log-level info \
--access-log \
--no-server-header
# Production with Gunicorn (recommended)
gunicorn main:app \
--bind 0.0.0.0:8000 \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--timeout 120 \
--keep-alive 5 \
--access-logfile - \
--error-logfile - \
--graceful-timeout 30
# Workers formula: (2 * CPU_CORES) + 1
# 2 cores -> 5 workers
# 4 cores -> 9 workers
# 8 cores -> 17 workers
Production removes --reload and adds multiple workers. Gunicorn with UvicornWorker is preferred for process management. --access-logfile - sends logs to stdout (standard for containers). --graceful-timeout allows in-flight requests to complete during shutdown.
# config.py
import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# Server
host: str = "0.0.0.0"
port: int = 8000
workers: int = 4
reload: bool = False
# Database
database_url: str = "sqlite:///./app.db"
# Auth
secret_key: str = "change-me"
access_token_expire_minutes: int = 30
# CORS
allowed_origins: list[str] = ["http://localhost:3000"]
class Config:
env_file = ".env"
settings = Settings()
# main.py
import uvicorn
from fastapi import FastAPI
from config import settings
app = FastAPI()
if __name__ == "__main__":
uvicorn.run(
"main:app",
host=settings.host,
port=settings.port,
workers=settings.workers,
reload=settings.reload,
log_level="info",
)
# .env file:
# DATABASE_URL=postgresql://user:pass@db:5432/myapp
# SECRET_KEY=super-secret-production-key
# WORKERS=8
# ALLOWED_ORIGINS=["https://myapp.com"]
pydantic-settings provides type-safe configuration from environment variables and .env files. Settings are centralized and accessible throughout the app. Running with python main.py uses the programmatic configuration.
# nginx.conf
upstream fastapi_backend {
server api:8000;
}
server {
listen 80;
server_name myapp.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name myapp.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location / {
proxy_pass http://fastapi_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;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Serve static files directly
location /static/ {
alias /app/static/;
expires 30d;
}
}
Nginx sits in front of Uvicorn handling SSL termination, HTTP/2, security headers, and static file serving. It forwards API requests to the Uvicorn backend. X-Forwarded headers tell FastAPI the real client IP and protocol.
Uvicorn, Workers, Gunicorn, SSL, Logging, Performance