Developer Stacks

How to Deploy FastAPI Python REST APIs on Ubuntu VPS with Uvicorn and Gunicorn

How to Deploy FastAPI Python REST APIs on Ubuntu VPS with Uvicorn and Gunicorn - CpanelFree Guide
Written by Blog

Why FastAPI is Dominating High-Performance Python Backend Development

Python has traditionally been considered slower than compiled languages for web servers. However, FastAPI revolutionized Python backend engineering by leveraging modern Python 3.10+ asynchronous type hints, Starlette ASGI routing, and Pydantic data validation. Benchmark tests routinely show FastAPI matching the raw throughput performance of Node.js and Go, while providing automated OpenAPI (Swagger) interactive documentation out of the box.

Running FastAPI in production requires an ASGI (Asynchronous Server Gateway Interface) web server. The industry standard architecture utilizes Gunicorn as a master process supervisor managing a pool of high-speed Uvicorn asynchronous worker processes, routed through an Nginx reverse proxy for SSL termination and static caching.

In this technical deployment guide, we will configure Python 3.12 virtual environments on Ubuntu, structure a production FastAPI application, daemonize Gunicorn via systemd, and configure Nginx with HTTP/2 and Let’s Encrypt SSL.

Step 1: Installing Python 3, Virtualenv, and Build Prerequisites

Install Python 3, pip, and virtual environment tools on Ubuntu 24.04/22.04 LTS:

# Update package list and install Python 3 tooling
sudo apt update && sudo apt install -y python3 python3-pip python3-venv python3-dev nginx certbot python3-certbot-nginx git

# Verify Python version
python3 --version

Step 2: Structuring the FastAPI Application and Virtual Environment

Create a dedicated production directory and isolate Python packages within a virtual environment:

# Create project directory
sudo mkdir -p /var/www/fastapi-app
sudo chown -R $USER:$USER /var/www/fastapi-app
cd /var/www/fastapi-app

# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate

# Install FastAPI, Uvicorn standard, Gunicorn, and Pydantic
pip install --upgrade pip
pip install fastapi "uvicorn[standard]" gunicorn pydantic httpx

Create the production application entrypoint at /var/www/fastapi-app/main.py:

from fastapi import FastAPI, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import time

app = FastAPI(
    title="Production High-Performance API",
    description="Enterprise REST API powered by FastAPI and Uvicorn",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

# CORS Middleware Configuration
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class HealthResponse(BaseModel):
    status: str
    timestamp: float
    service: str

@app.get("/health", response_model=HealthResponse, status_code=status.HTTP_200_OK)
async def health_check():
    return {
        "status": "healthy",
        "timestamp": time.time(),
        "service": "fastapi-production"
    }

@app.get("/api/v1/data")
async def get_sample_data():
    return {
        "message": "FastAPI asynchronous endpoint executing with sub-millisecond latency",
        "status": "success"
    }

Step 3: Creating Systemd Daemon Service for Gunicorn & Uvicorn

Create a robust systemd service file at /etc/systemd/system/fastapi.service to supervise the worker fleet:

[Unit]
Description=Gunicorn Uvicorn Supervisor for FastAPI
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/fastapi-app
Environment="PATH=/var/www/fastapi-app/venv/bin"
ExecStart=/var/www/fastapi-app/venv/bin/gunicorn     --workers 4     --worker-class uvicorn.workers.UvicornWorker     --bind 127.0.0.1:8000     --access-logfile /var/log/fastapi-access.log     --error-logfile /var/log/fastapi-error.log     --timeout 120     --keep-alive 5     main:app

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Assign proper permissions, enable, and start the systemd daemon:

sudo chown -R www-data:www-data /var/www/fastapi-app
sudo systemctl daemon-reload
sudo systemctl enable --now fastapi
sudo systemctl status fastapi --no-pager

Step 4: Nginx Reverse Proxy with Rate Limiting & SSL

Create the Nginx virtual host configuration at /etc/nginx/sites-available/api.example.com:

# Rate limiting zone (20 requests/sec per IP)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/s;

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

    location / {
        limit_req zone=api_limit burst=30 nodelay;
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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 90;
    }
}

Enable the site and issue an SSL certificate with Certbot:

sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d api.example.com

FastAPI Production Stack Architecture Matrix

Layer Tool / Component Function & Advantage
Edge Gateway Nginx Reverse Proxy SSL Termination, HTTP/2 multiplexing, DDoS rate limiting
Process Supervisor Gunicorn Master Spawns, monitors, and recycles worker processes automatically
ASGI Worker Engine Uvicorn (uvloop + httptools) Asynchronous event loop handling thousands of concurrent I/O requests

Integrating Pydantic Data Validation and OpenAPI Swagger UI

One of FastAPI’s greatest productivity advantages is automatic data validation and serialization powered by Pydantic. If an incoming JSON payload does not match the exact typed schema, FastAPI automatically responds with a descriptive 422 Unprocessable Entity response before your business logic executes:

from pydantic import BaseModel, Field, EmailStr
from typing import Optional, List

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    full_name: Optional[str] = None
    role: str = Field(default="developer", regex="^(developer|admin|billing)$")

@app.post("/api/v1/users", status_code=201)
async def create_user(user: UserCreate):
    # Data is guaranteed to be validated and sanitized
    return {"status": "created", "user": user.dict()}

Asynchronous Database Integration with SQLAlchemy 2.0 and Asyncpg

For maximum database I/O performance, connect FastAPI to PostgreSQL using asynchronous drivers:

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

DATABASE_URL = "postgresql+asyncpg://user:[email protected]:5432/fastapidb"
engine = create_async_engine(DATABASE_URL, echo=False, pool_size=20, max_overflow=10)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

async def get_db():
    async with AsyncSessionLocal() as session:
        yield session

FastAPI Production Tuning Best Practices

  • Worker Calculation Formula: Set Gunicorn workers to (2 * CPU cores) + 1. On a 2-core VPS, run 5 Uvicorn workers.
  • Enable Response Gzip: Add from fastapi.middleware.gzip import GZipMiddleware; app.add_middleware(GZipMiddleware, minimum_size=1000).
  • Set Keep-Alive Timeouts: Match Gunicorn’s keepalive with Nginx’s keepalive_timeout 65 to reuse TCP sockets.

Host High-Throughput Python APIs on CpanelFree Cloud VPS

Scale your asynchronous APIs and Python microservices with dedicated enterprise virtual CPU cores, ultra-low latency NVMe storage, and 100% free hosting options.

Get Free Cloud Hosting Today →

Deploy Fast, Reliable Web Hosting on CpanelFree

Get genuine cPanel control, unmetered NVMe SSD storage, and free AutoSSL at $0 cost forever.

Claim Free Hosting Account

About the author

Blog

DevOps architect and Linux sysadmin specializing in server hardening, OpenLiteSpeed performance optimization, and free cloud hosting infrastructure.

Leave a Comment