Production FastAPI Stack
Production FastAPI with Nginx, Uvicorn, PostgreSQL, Redis, and Celery workers
Overview
FastAPI is a modern, high-performance web framework for building APIs with Python, designed around Python type hints and automatic API documentation generation. This production stack combines FastAPI with Uvicorn's ASGI server for async request handling, Nginx as a reverse proxy for load balancing and static file serving, PostgreSQL for reliable ACID-compliant data storage, and Redis powering both caching and Celery's distributed task queue system. The architecture creates a robust, scalable API platform capable of handling both synchronous web requests and asynchronous background processing. This stack addresses the common production challenges of API development: horizontal scaling through Uvicorn workers, request buffering and SSL termination via Nginx, data persistence with PostgreSQL's advanced features like JSONB support, and background job processing through Celery workers with Redis as the message broker. The inclusion of Flower provides real-time monitoring of Celery tasks, while Celery Beat enables scheduled job execution. This configuration is ideal for SaaS platforms, data processing APIs, and enterprise applications that require both immediate API responses and background task execution. The combination of FastAPI's automatic OpenAPI documentation, PostgreSQL's query optimization capabilities, and Celery's distributed processing makes this stack particularly valuable for teams building complex data-driven applications that need to scale beyond simple CRUD operations.
Key Features
- FastAPI's automatic OpenAPI and JSON Schema generation with interactive documentation at /docs endpoint
- Uvicorn ASGI server with configurable worker processes for handling concurrent async requests
- Nginx reverse proxy with event-driven architecture for high-throughput request handling and static file serving
- PostgreSQL JSONB support enabling hybrid relational-document data models within a single database
- Redis Pub/Sub messaging for real-time communication between API and Celery workers
- Celery distributed task queue with separate worker and beat scheduler containers for background processing
- Flower web-based monitoring dashboard for tracking Celery task execution, worker status, and queue metrics
- Database connection pooling through PostgreSQL with support for complex queries and transactions
Common Use Cases
- 1SaaS platforms requiring user authentication, subscription management, and background billing processes
- 2Data analytics APIs that need to process large datasets asynchronously while serving real-time query results
- 3E-commerce backends handling order processing, inventory updates, and automated email notifications
- 4Content management systems with media processing, thumbnail generation, and search indexing workflows
- 5IoT data collection platforms aggregating sensor data with scheduled reporting and alert systems
- 6Financial applications requiring transaction processing, compliance reporting, and automated reconciliation
- 7Multi-tenant applications needing isolated data processing and scheduled maintenance tasks per tenant
Prerequisites
- Docker Engine 20.10+ and Docker Compose V2 for container orchestration support
- Minimum 2GB RAM (1GB for PostgreSQL, 512MB for Redis, 512MB for application containers)
- Available ports 80 (Nginx), 5555 (Flower), and configurable ports for external access
- Basic understanding of Python async/await patterns and FastAPI route decorators
- Familiarity with PostgreSQL connection strings and Redis URL formats for environment configuration
- Knowledge of Celery task definition syntax and worker scaling concepts
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 nginx: 3 image: nginx:alpine4 container_name: fastapi-nginx5 restart: unless-stopped6 ports: 7 - "${NGINX_PORT:-80}:80"8 volumes: 9 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro10 depends_on: 11 - api1213 api: 14 build: 15 context: .16 dockerfile: Dockerfile17 container_name: fastapi-api18 restart: unless-stopped19 command: uvicorn main:app --host 0.0.0.0 --port 8000 --workers 420 volumes: 21 - ./app:/app22 environment: 23 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}24 - REDIS_URL=redis://redis:637925 - SECRET_KEY=${SECRET_KEY}26 - ALGORITHM=HS25627 depends_on: 28 - db29 - redis3031 celery-worker: 32 build: 33 context: .34 dockerfile: Dockerfile35 container_name: fastapi-celery-worker36 restart: unless-stopped37 command: celery -A worker worker -l info -c 438 volumes: 39 - ./app:/app40 environment: 41 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}42 - REDIS_URL=redis://redis:637943 depends_on: 44 - db45 - redis4647 celery-beat: 48 build: 49 context: .50 dockerfile: Dockerfile51 container_name: fastapi-celery-beat52 restart: unless-stopped53 command: celery -A worker beat -l info54 volumes: 55 - ./app:/app56 environment: 57 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}58 - REDIS_URL=redis://redis:637959 depends_on: 60 - celery-worker6162 flower: 63 image: mher/flower:latest64 container_name: fastapi-flower65 restart: unless-stopped66 ports: 67 - "${FLOWER_PORT:-5555}:5555"68 environment: 69 - CELERY_BROKER_URL=redis://redis:637970 depends_on: 71 - redis72 - celery-worker7374 db: 75 image: postgres:16-alpine76 container_name: fastapi-db77 restart: unless-stopped78 environment: 79 - POSTGRES_USER=${DB_USER}80 - POSTGRES_PASSWORD=${DB_PASSWORD}81 - POSTGRES_DB=${DB_NAME}82 volumes: 83 - postgres_data:/var/lib/postgresql/data8485 redis: 86 image: redis:7-alpine87 container_name: fastapi-redis88 restart: unless-stopped89 volumes: 90 - redis_data:/data9192volumes: 93 postgres_data: 94 redis_data: .env Template
.env
1# FastAPI Production Stack2NGINX_PORT=803FLOWER_PORT=555545# Security6SECRET_KEY=your-secret-key78# Database9DB_USER=fastapi10DB_PASSWORD=fastapi_password11DB_NAME=fastapi_dbUsage Notes
- 1FastAPI auto-generates OpenAPI docs at /docs
- 2Flower monitors Celery tasks at localhost:5555
- 3Uvicorn runs with multiple workers for concurrency
- 4Use Alembic for database migrations
- 5Redis serves as Celery broker and result backend
- 6Scale workers: docker compose up -d --scale celery-worker=4
Individual Services(7 services)
Copy individual services to mix and match with your existing compose files.
nginx
nginx:
image: nginx:alpine
container_name: fastapi-nginx
restart: unless-stopped
ports:
- ${NGINX_PORT:-80}:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- api
api
api:
build:
context: .
dockerfile: Dockerfile
container_name: fastapi-api
restart: unless-stopped
command: uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
volumes:
- ./app:/app
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379
- SECRET_KEY=${SECRET_KEY}
- ALGORITHM=HS256
depends_on:
- db
- redis
celery-worker
celery-worker:
build:
context: .
dockerfile: Dockerfile
container_name: fastapi-celery-worker
restart: unless-stopped
command: celery -A worker worker -l info -c 4
volumes:
- ./app:/app
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
celery-beat
celery-beat:
build:
context: .
dockerfile: Dockerfile
container_name: fastapi-celery-beat
restart: unless-stopped
command: celery -A worker beat -l info
volumes:
- ./app:/app
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379
depends_on:
- celery-worker
flower
flower:
image: mher/flower:latest
container_name: fastapi-flower
restart: unless-stopped
ports:
- ${FLOWER_PORT:-5555}:5555
environment:
- CELERY_BROKER_URL=redis://redis:6379
depends_on:
- redis
- celery-worker
db
db:
image: postgres:16-alpine
container_name: fastapi-db
restart: unless-stopped
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
volumes:
- postgres_data:/var/lib/postgresql/data
redis
redis:
image: redis:7-alpine
container_name: fastapi-redis
restart: unless-stopped
volumes:
- redis_data:/data
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 nginx:5 image: nginx:alpine6 container_name: fastapi-nginx7 restart: unless-stopped8 ports:9 - "${NGINX_PORT:-80}:80"10 volumes:11 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro12 depends_on:13 - api1415 api:16 build:17 context: .18 dockerfile: Dockerfile19 container_name: fastapi-api20 restart: unless-stopped21 command: uvicorn main:app --host 0.0.0.0 --port 8000 --workers 422 volumes:23 - ./app:/app24 environment:25 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}26 - REDIS_URL=redis://redis:637927 - SECRET_KEY=${SECRET_KEY}28 - ALGORITHM=HS25629 depends_on:30 - db31 - redis3233 celery-worker:34 build:35 context: .36 dockerfile: Dockerfile37 container_name: fastapi-celery-worker38 restart: unless-stopped39 command: celery -A worker worker -l info -c 440 volumes:41 - ./app:/app42 environment:43 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}44 - REDIS_URL=redis://redis:637945 depends_on:46 - db47 - redis4849 celery-beat:50 build:51 context: .52 dockerfile: Dockerfile53 container_name: fastapi-celery-beat54 restart: unless-stopped55 command: celery -A worker beat -l info56 volumes:57 - ./app:/app58 environment:59 - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}60 - REDIS_URL=redis://redis:637961 depends_on:62 - celery-worker6364 flower:65 image: mher/flower:latest66 container_name: fastapi-flower67 restart: unless-stopped68 ports:69 - "${FLOWER_PORT:-5555}:5555"70 environment:71 - CELERY_BROKER_URL=redis://redis:637972 depends_on:73 - redis74 - celery-worker7576 db:77 image: postgres:16-alpine78 container_name: fastapi-db79 restart: unless-stopped80 environment:81 - POSTGRES_USER=${DB_USER}82 - POSTGRES_PASSWORD=${DB_PASSWORD}83 - POSTGRES_DB=${DB_NAME}84 volumes:85 - postgres_data:/var/lib/postgresql/data8687 redis:88 image: redis:7-alpine89 container_name: fastapi-redis90 restart: unless-stopped91 volumes:92 - redis_data:/data9394volumes:95 postgres_data:96 redis_data:97EOF9899# 2. Create the .env file100cat > .env << 'EOF'101# FastAPI Production Stack102NGINX_PORT=80103FLOWER_PORT=5555104105# Security106SECRET_KEY=your-secret-key107108# Database109DB_USER=fastapi110DB_PASSWORD=fastapi_password111DB_NAME=fastapi_db112EOF113114# 3. Start the services115docker compose up -d116117# 4. View logs118docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/production-fastapi-stack/run | bashTroubleshooting
- uvicorn.error - Application startup failed: Verify DATABASE_URL format and ensure PostgreSQL container is running before API container starts
- celery.exceptions.NotRegistered - Task not found: Check that task functions are properly imported in worker.py and decorated with @celery.task
- redis.exceptions.ConnectionError: Ensure Redis container is accessible and REDIS_URL environment variable matches the service name 'redis:6379'
- nginx: [emerg] host not found in upstream: Verify API service name matches upstream configuration in nginx.conf and API container is running
- psycopg2.OperationalError - connection limit exceeded: Increase PostgreSQL max_connections or implement connection pooling in FastAPI database configuration
- Flower shows no workers: Confirm celery-worker container is running and CELERY_BROKER_URL in Flower matches Redis service endpoint
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
nginxfastapiuvicornpostgresrediscelery
Tags
#fastapi#python#api#production#uvicorn#postgres#redis#celery
Category
Full Web StacksAd Space
Shortcuts: C CopyF FavoriteD Download