Install and configure Uvicorn ASGI server with systemd and reverse proxy for FastAPI applications

Intermediate 25 min Apr 03, 2026 27 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Deploy production-ready FastAPI applications using Uvicorn ASGI server with systemd process management and Nginx reverse proxy. Configure SSL termination, load balancing, and comprehensive monitoring for high-performance Python web applications.

Prerequisites

  • Root or sudo access
  • Basic knowledge of Python and web servers
  • Domain name for SSL setup (optional)

What this solves

Uvicorn is a lightning-fast ASGI server that powers FastAPI applications in production environments. This tutorial shows you how to deploy Uvicorn with systemd for automatic process management, Nginx reverse proxy for SSL termination and load balancing, and comprehensive monitoring with health checks. You'll learn to configure multiple Uvicorn workers, optimize performance settings, and implement security best practices for production deployments.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of all dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install Python and dependencies

Install Python 3.11+ and essential development tools needed for building Python packages and managing virtual environments.

sudo apt install -y python3.11 python3.11-venv python3.11-dev python3-pip build-essential nginx
sudo dnf install -y python3.11 python3.11-devel python3-pip gcc gcc-c++ make nginx

Create application user and directory

Create a dedicated system user for running your FastAPI application. This follows security best practices by avoiding root privileges.

sudo useradd --system --shell /bin/false --home-dir /opt/fastapi fastapi
sudo mkdir -p /opt/fastapi
sudo chown fastapi:fastapi /opt/fastapi

Create sample FastAPI application

Create a simple FastAPI application for testing your Uvicorn deployment. This includes health check endpoints for monitoring.

sudo -u fastapi python3.11 -m venv /opt/fastapi/venv
sudo -u fastapi /opt/fastapi/venv/bin/pip install fastapi uvicorn[standard] python-multipart
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
import uvicorn
import os
import psutil
from datetime import datetime

app = FastAPI(title="FastAPI with Uvicorn", version="1.0.0")

@app.get("/")
async def root():
    return {"message": "FastAPI with Uvicorn is running", "timestamp": datetime.now().isoformat()}

@app.get("/health")
async def health_check():
    return {
        "status": "healthy",
        "timestamp": datetime.now().isoformat(),
        "version": "1.0.0"
    }

@app.get("/metrics")
async def metrics():
    process = psutil.Process()
    return {
        "memory_usage": process.memory_info().rss / 1024 / 1024,  # MB
        "cpu_percent": process.cpu_percent(),
        "connections": len(process.connections()),
        "uptime": datetime.now().isoformat()
    }

@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
    if user_id < 1:
        raise HTTPException(status_code=400, detail="Invalid user ID")
    return {"user_id": user_id, "username": f"user{user_id}", "active": True}

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)
sudo chown fastapi:fastapi /opt/fastapi/app.py
sudo -u fastapi /opt/fastapi/venv/bin/pip install psutil

Create Uvicorn configuration file

Configure Uvicorn with production-optimized settings including multiple workers, proper logging, and performance tuning.

[application]
app = "app:app"
host = "127.0.0.1"
port = 8000
workers = 4
worker-class = "uvicorn.workers.UvicornWorker"

[logging]
level = "info"
access-log = true
use-colors = false

[performance]
max-requests = 1000
max-requests-jitter = 100
timeout = 30
keepalive = 5

[ssl]
ssl-keyfile = null
ssl-certfile = null
sudo chown fastapi:fastapi /opt/fastapi/uvicorn.toml

Create systemd service file

Configure systemd to manage Uvicorn processes with automatic restart, resource limits, and security hardening.

[Unit]
Description=FastAPI application with Uvicorn
After=network.target
Wants=network.target

[Service]
Type=exec
User=fastapi
Group=fastapi
WorkingDirectory=/opt/fastapi
Environment=PATH=/opt/fastapi/venv/bin
Environment=PYTHONPATH=/opt/fastapi
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/fastapi/venv/bin/uvicorn app:app --host 127.0.0.1 --port 8000 --workers 4 --log-level info --access-log
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
TimeoutStopSec=30

Security settings

NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ProtectHome=yes ReadWritePaths=/opt/fastapi SystemCallArchitectures=native

Resource limits

LimitNOFILE=65535 LimitNPROC=4096 [Install] WantedBy=multi-user.target

Create log directory and enable service

Set up proper logging directory with correct permissions and enable the systemd service for automatic startup.

sudo mkdir -p /var/log/fastapi
sudo chown fastapi:fastapi /var/log/fastapi
sudo chmod 755 /var/log/fastapi
Never use chmod 777. It gives every user on the system full access to your files. Instead, fix ownership with chown and use minimal permissions like 755 for directories.
sudo systemctl daemon-reload
sudo systemctl enable fastapi
sudo systemctl start fastapi

Configure Nginx reverse proxy

Set up Nginx as a reverse proxy with load balancing, security headers, and SSL termination support.

upstream fastapi_backend {
    server 127.0.0.1:8000;
    keepalive 32;
}

server {
    listen 80;
    server_name example.com www.example.com;
    
    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:" always;
    
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    
    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=health:10m rate=100r/s;
    
    location / {
        limit_req zone=api burst=20 nodelay;
        
        proxy_pass http://fastapi_backend;
        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_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
        
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }
    
    location /health {
        limit_req zone=health burst=50 nodelay;
        
        proxy_pass http://fastapi_backend;
        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;
        
        access_log off;
    }
    
    location /metrics {
        limit_req zone=api burst=10 nodelay;
        
        # Restrict metrics access
        allow 127.0.0.1;
        allow 10.0.0.0/8;
        allow 172.16.0.0/12;
        allow 192.168.0.0/16;
        deny all;
        
        proxy_pass http://fastapi_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    # Static files (if needed)
    location /static/ {
        alias /opt/fastapi/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    
    # Logging
    access_log /var/log/nginx/fastapi_access.log;
    error_log /var/log/nginx/fastapi_error.log;
}
sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Configure SSL with Let's Encrypt (optional)

Set up automatic SSL certificate management using Certbot for production deployments.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

Configure log rotation

Set up automatic log rotation to prevent disk space issues in production environments.

/var/log/fastapi/*.log {
    daily
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    copytruncate
    su fastapi fastapi
}

Create monitoring script

Implement health checking and monitoring script for automated alerting and service recovery.

#!/usr/bin/env python3
import requests
import subprocess
import sys
import json
from datetime import datetime

def check_health():
    try:
        response = requests.get('http://127.0.0.1:8000/health', timeout=5)
        if response.status_code == 200:
            data = response.json()
            print(f"Health check passed: {data['status']} at {data['timestamp']}")
            return True
        else:
            print(f"Health check failed: HTTP {response.status_code}")
            return False
    except requests.exceptions.RequestException as e:
        print(f"Health check failed: {e}")
        return False

def check_metrics():
    try:
        response = requests.get('http://127.0.0.1:8000/metrics', timeout=5)
        if response.status_code == 200:
            data = response.json()
            print(f"Memory usage: {data['memory_usage']:.1f}MB")
            print(f"CPU usage: {data['cpu_percent']:.1f}%")
            print(f"Connections: {data['connections']}")
            return True
        else:
            print(f"Metrics check failed: HTTP {response.status_code}")
            return False
    except requests.exceptions.RequestException as e:
        print(f"Metrics check failed: {e}")
        return False

def restart_service():
    try:
        subprocess.run(['sudo', 'systemctl', 'restart', 'fastapi'], check=True)
        print("Service restarted successfully")
        return True
    except subprocess.CalledProcessError as e:
        print(f"Failed to restart service: {e}")
        return False

if __name__ == "__main__":
    print(f"FastAPI monitoring check - {datetime.now().isoformat()}")
    
    if not check_health():
        print("Health check failed, attempting service restart...")
        if restart_service():
            # Wait and check again
            import time
            time.sleep(10)
            if check_health():
                print("Service recovered successfully")
                sys.exit(0)
            else:
                print("Service recovery failed")
                sys.exit(1)
        else:
            sys.exit(1)
    
    check_metrics()
    print("All checks passed")
sudo chown fastapi:fastapi /opt/fastapi/monitor.py
sudo chmod 755 /opt/fastapi/monitor.py
sudo -u fastapi /opt/fastapi/venv/bin/pip install requests

Set up monitoring cron job

Schedule regular health checks and monitoring to ensure your FastAPI application stays healthy.

sudo crontab -u fastapi -e

Add this line to run health checks every 5 minutes:

/5    * /opt/fastapi/venv/bin/python /opt/fastapi/monitor.py >> /var/log/fastapi/monitor.log 2>&1

Configure advanced performance tuning

Optimize kernel parameters for high connections

Configure system-level settings for handling high concurrent connections and network traffic.

# Network performance tuning
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 1024 65535

Memory settings

vm.overcommit_memory = 1 vm.swappiness = 1
sudo sysctl --system

For more detailed kernel optimization, see our guide on Linux kernel parameters for container workloads.

Configure systemd resource limits

Set appropriate resource limits to prevent resource exhaustion while allowing optimal performance.

[Service]

File descriptor limits

LimitNOFILE=65535

Process limits

LimitNPROC=4096

Memory limits (adjust based on your server capacity)

MemoryMax=2G MemoryHigh=1.5G

CPU limits (optional - remove for unlimited CPU)

CPUQuota=200%

I/O limits

IOWeight=200
sudo mkdir -p /etc/systemd/system/fastapi.service.d
sudo systemctl daemon-reload
sudo systemctl restart fastapi

Verify your setup

Test your Uvicorn FastAPI deployment to ensure all components are working correctly.

# Check service status
sudo systemctl status fastapi
sudo systemctl status nginx

Test direct Uvicorn connection

curl -f http://127.0.0.1:8000/health

Test through Nginx reverse proxy

curl -f http://localhost/health

Check application metrics

curl -f http://localhost/metrics

Test API endpoint

curl -f http://localhost/api/users/123

Check logs

sudo journalctl -u fastapi -f --lines 20 sudo tail -f /var/log/nginx/fastapi_access.log

Common issues

Symptom Cause Fix
Service won't start Python path or virtual environment issues sudo journalctl -u fastapi to check logs, verify paths in service file
502 Bad Gateway Uvicorn not listening or firewall blocking sudo netstat -tlnp | grep 8000 and check Nginx upstream configuration
Permission denied errors Incorrect file ownership or permissions sudo chown -R fastapi:fastapi /opt/fastapi and use chmod 755/644
High memory usage Too many workers or memory leaks Reduce workers in systemd service, monitor with /metrics endpoint
SSL certificate errors Certbot configuration or renewal issues sudo certbot renew --dry-run and check Nginx SSL configuration
Rate limiting blocking requests Nginx rate limits too restrictive Adjust limit_req settings in Nginx configuration

Next steps

Automated install script

Run this to automate the entire setup

#uvicorn #fastapi #asgi-server #systemd #nginx #python-production #reverse-proxy #ssl

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer