technical2 min read·Jun 25, 2026

Deploying FastAPI to Production: The Complete VPS Guide

Everything I learned deploying 3 FastAPI apps on a single Linux VPS — Nginx, Gunicorn, SSL, and the gotchas nobody tells you about.

FastAPIDevOpsNginxLinuxProductionDeployment
ShareLinkedInX / Twitter

Why VPS Over Serverless?

I choose VPS deployment for most of my projects because I need persistent WebSocket connections, background tasks, and full control over the runtime. Serverless has cold starts and connection limits that don't work for real-time systems.

My Stack

Ubuntu 22.04 LTS on a 2-core, 4GB VPS
Nginx as reverse proxy
Gunicorn with Uvicorn workers
systemd for process management
Certbot for SSL via Let's Encrypt

Step 1: Application Structure

/home/deploy/
├── attendance-system/
│   ├── app/
│   ├── venv/
│   └── gunicorn.conf.py
├── commandflow/
│   ├── app/
│   ├── venv/
│   └── gunicorn.conf.py
└── snapfix-api/
    ├── app/
    ├── venv/
    └── gunicorn.conf.py

Each app gets its own virtualenv and Gunicorn config. No shared dependencies.

Step 2: Gunicorn Configuration

python
# gunicorn.conf.py bind = 'unix:/tmp/attendance.sock' workers = 4 worker_class = 'uvicorn.workers.UvicornWorker' accesslog = '/var/log/attendance/access.log' errorlog = '/var/log/attendance/error.log'

Step 3: Nginx Reverse Proxy

nginx
server { server_name attendance-pro.online; location / { proxy_pass http://unix:/tmp/attendance.sock; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /ws { proxy_pass http://unix:/tmp/attendance.sock; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } }

The Gotchas

1. WebSocket Timeout

Nginx has a default 60-second timeout for WebSocket connections. For long-lived connections, you need proxy_read_timeout 3600;.

2. Worker Count

Don't set workers = 2 * cpu_count + 1 blindly. For WebSocket-heavy apps, fewer workers with more connections per worker is better.

3. SSL Certificate Renewal

Certbot's auto-renewal runs via cron, but if it fails silently, your site goes down. I set up monitoring with a simple health check script.

Key Takeaway

Production deployment is where most projects die. The gap between uvicorn --reload and a production server is massive. Invest time in understanding your deployment stack — it's as important as the application code.

AG

Written by Ansh Gautam

Full-stack engineer building production systems with FastAPI, React, and AI/LLM integrations. Currently looking for backend engineering & AI integration roles.