How to Deploy a Python Application with Gunicorn and Nginx

Gunicorn is a production-grade WSGI server for running Python web applications (Flask, FastAPI, Django), and pairing it with Nginx as a reverse proxy is the standard deployment pattern for Python apps on a VPS.

Why Not Just Run the Development Server

Frameworks' built-in development servers aren't designed for production traffic — they typically handle one request at a time and lack the robustness needed for real usage. Gunicorn runs multiple worker processes, handling concurrent requests properly.

Prerequisites

  • A working Python application (Flask, FastAPI, or similar)
  • Nginx installed

Step 1 — Install Gunicorn

pip install gunicorn --break-system-packages

Step 2 — Test Gunicorn Directly

gunicorn myapp:app --bind 127.0.0.1:8000

For FastAPI specifically, use the Uvicorn worker class instead:

gunicorn myapp:app -k uvicorn.workers.UvicornWorker --bind 127.0.0.1:8000

Step 3 — Determine the Right Number of Workers

gunicorn myapp:app --workers 4 --bind 127.0.0.1:8000

A common starting formula is (2 x CPU cores) + 1, adjusted based on actual observed performance and memory constraints.

Step 4 — Create a systemd Service

sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Python Application
After=network.target

[Service]
User=deploy
WorkingDirectory=/var/www/myapp
ExecStart=/var/www/myapp/venv/bin/gunicorn myapp:app --workers 4 --bind 127.0.0.1:8000
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now myapp

Step 5 — Configure Nginx as a Reverse Proxy

server {
    listen 80;
    server_name yourdomain.com;

    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;
    }
}
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 6 — Add HTTPS

sudo certbot --nginx -d yourdomain.com

Increasing Timeout for Long-Running Requests (Relevant for AI Workloads)

location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_read_timeout 300s;
}

AI inference or other long-running operations may exceed Nginx's default proxy timeout, causing premature connection drops — increase this value to match your application's realistic response times.

Viewing Application Logs

sudo journalctl -u myapp -f

Deploying Updates

cd /var/www/myapp
git pull
sudo systemctl restart myapp

Common Errors

502 Bad Gateway — verify Gunicorn is actually running (sudo systemctl status myapp) and bound to the port Nginx expects.

Worker timeout errors in Gunicorn logs — increase Gunicorn's own --timeout flag if requests legitimately take longer than the default 30 seconds (common with AI inference workloads).

Continue Reading

Browse more articles in AI & Machine Learning on a VPS.

  • gunicorn, python deployment, gunicorn nginx, wsgi server
  • 0 用戶發現這個有用
這篇文章有幫助嗎?

相關文章

VPS Requirements for Running AI and Machine Learning Workloads

Before installing any AI tooling, it's worth understanding what a VPS can and can't realistically...

How to Install Ollama and Run Local LLMs on a VPS

Ollama makes running open-source large language models locally straightforward — handling...

How to Set Up a Private ChatGPT-Style Interface with Open WebUI

Open WebUI provides a familiar, browser-based chat interface for locally-run language models...

How to Install LocalAI as an OpenAI-Compatible API Alternative

LocalAI provides a drop-in, OpenAI-API-compatible endpoint backed by open-source models running...

How to Run Stable Diffusion for AI Image Generation on a VPS

Stable Diffusion generates images from text prompts using an open-source diffusion model. This...