TL;DR
Complete guide to deploying FastAPI on AWS EC2 with Uvicorn, Gunicorn, systemd, nginx, and SSL.
Key facts
- Topology
- FastAPI on AWS EC2
TL;DR
FastAPI on EC2 means running Uvicorn workers behind Gunicorn as the process manager, with systemd for service persistence, nginx for SSL termination, and AWS security groups as your network firewall. This guide covers the full production setup.
Prerequisites
- An AWS account with EC2 access
- A domain name with DNS configured
- An SSH key pair registered in EC2
Step 1 — Launch and configure the EC2 instance
Launch an Ubuntu 24.04 AMI. A t3.small (2 vCPU, 2 GB RAM) works for moderate API workloads. Configure the security group:
| Port | Protocol | Source | Purpose |
|---|---|---|---|
| 22 | TCP | Your IP | SSH |
| 80 | TCP | 0.0.0.0/0 | HTTP |
| 443 | TCP | 0.0.0.0/0 | HTTPS |
Attach an Elastic IP and point your domain's A record to it.
Step 2 — System preparation and Python
ssh -i ~/.ssh/mykey.pem ubuntu@your-elastic-ip
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3.12 python3.12-venv python3-pip build-essential
Verify Python:
python3.12 --version
Step 3 — Deploy the application
sudo mkdir -p /var/www/fastapiapp && sudo chown ubuntu:ubuntu /var/www/fastapiapp
cd /var/www/fastapiapp
git clone git@github.com:yourorg/fastapiapp.git .
python3.12 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install gunicorn uvicorn[standard]
Create .env with production values:
APP_ENV=production
DATABASE_URL=postgresql://user:pass@db-host/fastapidb
SECRET_KEY=your-secret-key
Verify the app starts:
uvicorn main:app --host 0.0.0.0 --port 8000
curl http://localhost:8000/health
Step 4 — Uvicorn with Gunicorn workers
Gunicorn manages multiple Uvicorn worker processes. Create gunicorn.conf.py:
import multiprocessing
bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'uvicorn.workers.UvicornWorker'
timeout = 120
graceful_timeout = 30
max_requests = 1000
max_requests_jitter = 50
accesslog = '/var/log/gunicorn/fastapi-access.log'
errorlog = '/var/log/gunicorn/fastapi-error.log'
loglevel = 'info'
sudo mkdir -p /var/log/gunicorn
Step 5 — systemd service
Create /etc/systemd/system/fastapiapp.service:
[Unit]
Description=FastAPI Application (Gunicorn + Uvicorn)
After=network.target
[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/var/www/fastapiapp
ExecStart=/var/www/fastapiapp/venv/bin/gunicorn -c gunicorn.conf.py main:app
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
EnvironmentFile=/var/www/fastapiapp/.env
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl start fastapiapp
sudo systemctl enable fastapiapp
sudo systemctl status fastapiapp
Step 6 — nginx reverse proxy
sudo apt install -y nginx
Create /etc/nginx/sites-available/fastapiapp:
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
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_read_timeout 60s;
proxy_connect_timeout 10s;
}
}
sudo ln -s /etc/nginx/sites-available/fastapiapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Step 7 — SSL
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.example.com
Monitoring
Use journalctl for service logs:
sudo journalctl -u fastapiapp -f
For deeper visibility, FastAPI's /docs endpoint exposes OpenAPI specs. Add a health check endpoint returning database connectivity and uptime metrics.
With Reflex
Reflex monitors your FastAPI deployment on EC2 end-to-end — tracking Gunicorn worker health, request latency percentiles, systemd service state, and EC2 system metrics. It orchestrates zero-downtime deployments with graceful Gunicorn HUP signals, verifies the health endpoint, and rolls back automatically on failure. See How it works.