Python 3 min read

FastAPI Tutorial Part 16: Docker and Deployment

Deploy FastAPI applications to production. Learn Docker containerization, Docker Compose, cloud deployment, and production best practices.

MR

Moshiour Rahman

· Updated May 9, 2026

Introduction

Moving from localhost to production involves more than just running a script. We need stability, restart capability, and performance.

Production Architecture

We don’t expose FastAPI directly to the internet. Instead, we use a robust architecture:

FastAPI Production Architecture

This setup ensures:

  1. Nginx: Handles SSL, compression, and slow clients.
  2. Gunicorn: Manages processes (restarts them if they crash).
  3. Uvicorn: Runs your async FastAPI code at high speed.

Dockerfile

We use Multi-Stage Builds to keep our final image small and secure.

Production Dockerfile

# Stage 1: Builder (Compiles dependencies)
FROM python:3.11-slim as builder

WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

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

# Stage 2: Runtime (Minimal image)
FROM python:3.11-slim

WORKDIR /app
# Copy virtual env from builder stage
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

COPY ./app ./app

# Security: Don't run as root
RUN adduser --disabled-password --gecos "" appuser
USER appuser

EXPOSE 8000
CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]

Docker Compose

# docker-compose.yml
version: "3.8"

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/app
      - SECRET_KEY=${SECRET_KEY}
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=app
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:alpine

  celery:
    build: .
    command: celery -A app.celery_app worker --loglevel=info
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/app
    depends_on:
      - redis
      - db

volumes:
  postgres_data:

Deployment Workflow

Automation is key. Here is a typical conceptual pipeline:

graph LR
    Dev[Developer] -->|Push| Git[GitHub]
    Git -->|Trigger| CI[CI/CD Pipeline]
    
    subgraph CI Process
        CI --> Test[Run Tests]
        Test --> Build[Build Docker Image]
        Build --> Push[Push to Registry]
    end
    
    Push -->|Deploy| Server[Production Server]
    Server -->|Pull| Pull[Pull New Image]
    Pull -->|Restart| Restart[Restart Containers]
    
    style CI fill:#f9f,stroke:#333
    style Server fill:#bbf,stroke:#333

Running with Compose

Docker Compose orchestrates your API, Database, and Cache together.

# Build and run
docker-compose up --build

# Run in background
docker-compose up -d

# View logs
docker-compose logs -f api

# Stop
docker-compose down

Environment Configuration

# app/config.py
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    secret_key: str
    debug: bool = False
    allowed_hosts: list = ["*"]

    class Config:
        env_file = ".env"

settings = Settings()

Production Checklist

ItemAction
HTTPSUse reverse proxy (nginx)
SecretsEnvironment variables
LoggingStructured JSON logs
Health check/health endpoint
DatabaseConnection pooling
WorkersMultiple Gunicorn workers

Health Check Endpoint

@app.get("/health")
async def health_check():
    return {
        "status": "healthy",
        "database": await check_db_connection(),
        "redis": await check_redis_connection()
    }

Nginx Configuration

upstream api {
    server api:8000;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://api;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Summary

ComponentPurpose
DockerfileContainer definition
docker-composeMulti-service orchestration
GunicornProduction WSGI server
NginxReverse proxy, SSL

Next Steps

In Part 17, we’ll explore Performance and Caching - optimizing your FastAPI application.

Series Navigation:

  • Part 1-15: Previous parts
  • Part 16: Docker & Deployment (You are here)
  • Part 17: Performance & Caching
Is your AI API down right now? Check live status for OpenAI, Claude, Gemini, Groq, and more.
Check status →
MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.