• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Configuring Uvicorn ASGI behind Nginx Reverse Proxy on Ubuntu 24.04 LTS for Medium Traffic Python FastAPI Apps

Configuring Uvicorn ASGI behind Nginx Reverse Proxy on Ubuntu 24.04 LTS for Medium Traffic Python FastAPI Apps

Prerequisites and Initial Setup

This guide assumes a fresh Ubuntu 24.04 LTS server instance with root or sudo privileges. We’ll be setting up a production-ready environment for a Python FastAPI application served by Uvicorn, with Nginx acting as a reverse proxy. Ensure you have Python 3.10+ and pip installed. If not, you can install them via:

  • sudo apt update && sudo apt upgrade -y
  • sudo apt install python3 python3-pip python3-venv -y

Next, create a dedicated user for your application to enhance security. Avoid running web applications as root.

  • sudo adduser --system --group --no-create-home appuser

Create a directory for your application and set appropriate ownership and permissions.

  • sudo mkdir -p /opt/my_fastapi_app
  • sudo chown appuser:appuser /opt/my_fastapi_app
  • sudo chmod 755 /opt/my_fastapi_app

FastAPI Application Structure and Uvicorn Configuration

Let’s assume a basic FastAPI application structure. Create a file named main.py within your application directory:

  • sudo nano /opt/my_fastapi_app/main.py

Populate main.py with a simple FastAPI app:

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello from FastAPI!"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}

# This part is for direct execution, not for production behind a proxy
# if __name__ == "__main__":
#     uvicorn.run(app, host="0.0.0.0", port=8000)

Create a requirements.txt file to list dependencies:

  • sudo nano /opt/my_fastapi_app/requirements.txt
fastapi
uvicorn[standard]

Now, switch to the appuser and set up a Python virtual environment. This isolates dependencies for your application.

  • sudo su - appuser
  • cd /opt/my_fastapi_app
  • python3 -m venv venv
  • source venv/bin/activate
  • pip install -r requirements.txt

To run Uvicorn as a service, we’ll use systemd. Create a service file:

  • sudo nano /etc/systemd/system/my_fastapi_app.service
[Unit]
Description=My FastAPI Application
After=network.target

[Service]
User=appuser
Group=appuser
WorkingDirectory=/opt/my_fastapi_app
# Ensure the path to the venv's python executable is correct
ExecStart=/opt/my_fastapi_app/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 4
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Explanation of the systemd service file:

  • User and Group: Specifies the user and group under which the service will run.
  • WorkingDirectory: Sets the current directory for the service.
  • ExecStart: The command to start the Uvicorn server. We bind it to 127.0.0.1 (localhost) because Nginx will be the public-facing interface. --workers 4 is a starting point; adjust based on your server’s CPU cores (a common recommendation is 2 * num_cores + 1, but for I/O bound apps, fewer might suffice).
  • Restart=always: Ensures the service restarts if it crashes.
  • RestartSec=10: Waits 10 seconds before attempting a restart.

Enable and start the service:

  • sudo systemctl daemon-reload
  • sudo systemctl enable my_fastapi_app
  • sudo systemctl start my_fastapi_app
  • sudo systemctl status my_fastapi_app

Verify that Uvicorn is running and accessible locally:

  • curl http://127.0.0.1:8000

You should see: {"message":"Hello from FastAPI!"}. If not, check the systemd journal for errors: sudo journalctl -u my_fastapi_app -f.

Nginx Installation and Configuration

Install Nginx if it’s not already present:

  • sudo apt update && sudo apt install nginx -y

Create a new Nginx server block configuration file for your application. Replace your_domain.com with your actual domain name or server IP address.

  • sudo nano /etc/nginx/sites-available/my_fastapi_app
server {
    listen 80;
    server_name your_domain.com www.your_domain.com; # Or your server's IP address

    location / {
        proxy_pass http://127.0.0.1:8000;
        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_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Optional: Serve static files directly if your FastAPI app doesn't handle them
    # location /static/ {
    #     alias /opt/my_fastapi_app/static/;
    #     expires 30d;
    #     add_header Cache-Control "public";
    # }

    # Optional: Error pages
    # error_page 500 502 503 504 /50x.html;
    # location = /50x.html {
    #     root /usr/share/nginx/html;
    # }
}

Explanation of the Nginx configuration:

  • listen 80;: Nginx listens on port 80 for incoming HTTP requests.
  • server_name: Specifies the domain names or IP addresses this server block should respond to.
  • location /: This block handles all requests.
  • proxy_pass http://127.0.0.1:8000;: This is the core directive. It forwards all incoming requests to the Uvicorn server running on localhost:8000.
  • proxy_set_header directives: These are crucial for passing information about the original client request to the backend application. Without them, your FastAPI app would see all requests originating from the Nginx server’s IP.
  • proxy_connect_timeout, proxy_send_timeout, proxy_read_timeout: These settings define how long Nginx will wait for a connection to the upstream server, and how long it will wait to send or receive data. Adjust these based on expected response times of your API endpoints.

Enable the new site by creating a symbolic link and test the Nginx configuration:

  • sudo ln -s /etc/nginx/sites-available/my_fastapi_app /etc/nginx/sites-enabled/
  • sudo nginx -t

If the test is successful, restart Nginx to apply the changes:

  • sudo systemctl restart nginx

Firewall Configuration (UFW)

If you are using UFW (Uncomplicated Firewall), you need to allow HTTP and HTTPS traffic. Assuming you have UFW enabled:

  • sudo ufw allow 'Nginx Full'
  • sudo ufw delete allow 'Nginx HTTP' (if you previously allowed only HTTP)
  • sudo ufw enable (if not already enabled)
  • sudo ufw status

This allows traffic on both port 80 (HTTP) and port 443 (HTTPS). For production, you should absolutely configure SSL/TLS with Let’s Encrypt.

SSL/TLS Configuration with Let’s Encrypt (Certbot)

Securing your application with HTTPS is non-negotiable for production environments. We’ll use Certbot to automate this process.

  • sudo apt install certbot python3-certbot-nginx -y

Run Certbot to obtain and install an SSL certificate. Ensure your DNS records for your_domain.com point to your server’s public IP address before running this.

  • sudo certbot --nginx -d your_domain.com -d www.your_domain.com

Certbot will prompt you to choose whether to redirect HTTP traffic to HTTPS. It’s highly recommended to choose the redirect option. Certbot automatically modifies your Nginx configuration file to include SSL directives and sets up automatic renewal.

Verify the automatic renewal is set up:

  • sudo systemctl status certbot.timer
  • sudo certbot renew --dry-run

Performance Tuning and Monitoring

For medium traffic, the default settings might suffice, but consider these points for optimization:

  • Uvicorn Workers: The --workers 4 in the systemd service is a starting point. Monitor CPU usage. If your application is CPU-bound, you might increase this. If it’s I/O-bound (e.g., heavy database queries, external API calls), fewer workers might be more efficient to avoid context-switching overhead. A common heuristic is (2 * number_of_cores) + 1, but empirical testing is key.
  • Nginx Worker Processes: Nginx’s worker_processes directive (usually set to auto in /etc/nginx/nginx.conf) should typically match the number of CPU cores.
  • Keep-Alive Connections: Ensure Nginx’s keepalive_timeout is set appropriately (e.g., 65s) to reuse TCP connections, reducing latency for subsequent requests from the same client.
  • Buffering: For large request/response bodies, tune Nginx’s client_body_buffer_size and proxy_buffer_size. However, for typical API traffic, defaults are often fine.
  • Logging: Configure Nginx and Uvicorn logging levels. For production, avoid verbose debug logging unless actively troubleshooting. Use tools like goaccess or ELK stack for log analysis.
  • Monitoring: Implement application performance monitoring (APM) tools (e.g., Sentry, Datadog, New Relic) and server-level monitoring (e.g., Prometheus/Grafana, Zabbix) to track response times, error rates, resource utilization, and identify bottlenecks.
  • Database Connections: If your FastAPI app uses a database, ensure you’re using a connection pool (e.g., SQLAlchemy’s pool) and that the pool size is configured appropriately, considering both your application’s needs and database server limits.

Troubleshooting Common Issues

  • 502 Bad Gateway: This usually means Nginx cannot reach the Uvicorn process. Check:
    • Is the my_fastapi_app.service running? (sudo systemctl status my_fastapi_app)
    • Are there errors in the Uvicorn logs? (sudo journalctl -u my_fastapi_app -f)
    • Is Uvicorn listening on the correct IP and port specified in Nginx’s proxy_pass? (sudo ss -tulnp | grep 8000)
    • Is the firewall blocking traffic between Nginx and Uvicorn (unlikely if both are on localhost)?
  • 404 Not Found: Ensure your FastAPI routes are correctly defined and that Nginx is proxying to the correct application. If serving static files, verify the alias and root directives in Nginx.
  • Application Errors: Check the Uvicorn logs (sudo journalctl -u my_fastapi_app -f) for Python tracebacks. Ensure your requirements.txt is up-to-date and all dependencies are installed in the virtual environment.
  • SSL Errors: Verify Certbot’s configuration and renewal status. Ensure your domain’s DNS records are correctly pointing to the server. Check Nginx error logs (/var/log/nginx/error.log) for SSL-related issues.

This setup provides a robust foundation for deploying medium-traffic FastAPI applications. Remember to adapt worker counts, timeouts, and monitoring strategies based on your specific application’s performance characteristics and traffic patterns.

Reader Interactions

Leave a Reply Cancel reply

You must be logged in to post a comment.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (662)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (5)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (647)
  • SEO & Growth (492)
  • Server (118)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (726)
  • WordPress Theme Development (357)

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala