This guide describes all available deployment modes for the project. Choose the one that best fits your infrastructure.
For local development setup, see the Development Guide.
deploy/
├── compose/
│ ├── full-stack/ → Complete stack on a single VPS (Docker + Caddy HTTPS)
│ └── app-only/ → Application only (external databases, PaaS platforms)
└── native/ → Linux VPS without Docker (Nginx + Supervisor)
| Mode | Best For | Docker | HTTPS | DB Included |
|---|---|---|---|---|
| compose/full-stack | Single VPS, full control | ✅ | ✅ Caddy | ✅ |
| compose/app-only | PaaS, managed databases | ✅ | ❌ (platform) | ❌ |
| native | Linux VPS, no Docker | ❌ | ❌ Nginx (manual) | ❌ |
Full documentation: deploy/compose/full-stack/README.md
When to use: You want to run the entire stack (databases, API, workers, reverse proxy, TLS) on a single VPS with a single docker compose up command.
What's included:
| Service | Description |
|---|---|
caddy |
Reverse proxy with automatic Let's Encrypt HTTPS |
postgres |
PostgreSQL 17 with pgvector (internal network only) |
redis |
Redis Alpine (internal network only) |
migrate |
Runs alembic upgrade head once before API starts |
api |
FastAPI via Uvicorn |
celery_worker |
Celery Worker |
celery_beat |
Celery Beat scheduler |
celery_flower |
Flower UI (basic auth required, internal) |
Key features:
- PostgreSQL and Redis are not exposed to the host (no port binding).
- Healthchecks on Postgres and Redis prevent the API from starting before the databases are ready.
- Caddy automatically provisions TLS certificates. Edit
deploy/compose/full-stack/Caddyfilewith your domain to enable HTTPS.
Prerequisites:
- Docker and Docker Compose on the server.
backend/.envconfigured frombackend/.env.example.- Ports
80and443open in the firewall. - DNS A record pointing to the server's IP.
Run (from repository root):
Start main stack (Postgres, Redis, API, Caddy):
docker compose --env-file backend/.env \
-f deploy/compose/full-stack/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod up -dRun migration:
docker compose --env-file backend/.env \
-f deploy/compose/full-stack/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile migrate run --rm migrateStart Celery Worker:
docker compose --env-file backend/.env \
-f deploy/compose/full-stack/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile worker up -d celery_workerStart Celery Beat:
docker compose --env-file backend/.env \
-f deploy/compose/full-stack/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile scheduler up -d celery_beatStart Flower (Observability):
docker compose --env-file backend/.env \
-f deploy/compose/full-stack/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile observability up -d celery_flowerFull documentation: deploy/compose/app-only/README.md
When to use: Your databases are managed externally — by a PaaS platform or a cloud service — and you only want to deploy the application containers.
Compatible with:
- Self-managed: Dokploy, Coolify, CapRover, Portainer
- Cloud: AWS ECS, Railway, Render, Fly.io
- Managed databases: AWS RDS + ElastiCache, Supabase, Neon, Upstash
What's included:
| Service | Description |
|---|---|
migrate |
Runs alembic upgrade head once, then exits |
api |
FastAPI via Uvicorn |
celery_worker |
Celery Worker |
celery_beat |
Celery Beat scheduler |
celery_flower |
Flower UI (basic auth required) |
Key features:
- No Postgres, Redis, or reverse proxy containers.
- Uses an external Docker network (
app-network). Rename it to match your platform if needed (e.g.dokploy-network). - All connection variables must be set in
backend/.envor the platform's environment UI.
Run (from repository root):
Start main API:
docker compose --env-file backend/.env \
-f deploy/compose/app-only/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod up -d apiRun migration:
docker compose --env-file backend/.env \
-f deploy/compose/app-only/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile migrate run --rm migrateStart Celery Worker:
docker compose --env-file backend/.env \
-f deploy/compose/app-only/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile worker up -d celery_workerStart Celery Beat:
docker compose --env-file backend/.env \
-f deploy/compose/app-only/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile scheduler up -d celery_beatStart Flower (Observability):
docker compose --env-file backend/.env \
-f deploy/compose/app-only/docker-compose.yml \
--project-name fastapi-async-sqlmodel-boilerplate-prod \
--profile observability up -d celery_flowerFull documentation: deploy/native/README.md
When to use: You want to deploy on a Linux VPS without Docker, using Nginx as the reverse proxy and Supervisor to manage processes.
Based on: FastAPI with Nginx and Gunicorn
Directory structure:
deploy/native/
├── logs/ # Log output directory
├── nginx/
│ └── nginx.conf # Nginx reverse-proxy configuration
├── scripts/ # Bash wrapper scripts for each process
│ ├── backend-api
│ ├── backend-worker
│ └── backend-scheduler
└── supervisor/ # Supervisor program configurations
├── backend-api.conf
├── backend-worker.conf
└── backend-scheduler.conf
High-level steps:
- Install Nginx, Supervisor, Python 3.11, and Poetry on the server.
- Clone the repository and run
poetry installinsidebackend/. - Copy
backend/.env.example→backend/.envand fill in production values. - Run
alembic upgrade headto apply migrations. - Make the scripts in
deploy/native/scripts/executable. - Symlink Supervisor configs to
/etc/supervisor/conf.d/. - Symlink
deploy/native/nginx/nginx.confto/etc/nginx/sites-enabled/fastapi-appand remove the default site.
Important
See the full native README for the exact commands with paths.
All deployment modes read from backend/.env. This file is never committed to version control.
cp backend/.env.example backend/.env
# Edit backend/.env with your production valuesKey variables to configure before deploying:
| Variable | Description |
|---|---|
SECRET_KEY |
App secret key — generate with python -c "import secrets; print(secrets.token_urlsafe(32))" |
POSTGRES_SERVER |
Database host |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB |
Database credentials |
REDIS_CACHE_HOST / REDIS_CACHE_PASSWORD |
Redis connection |
REDIS_BROKER_HOST / REDIS_BROKER_PASSWORD |
Celery broker Redis |
FLOWER_BASIC_AUTH |
Flower UI auth (user:password) |
ENVIRONMENT |
Set to production for prod deployments |
See backend/.env.example for the full list.