How to Deploy Python Django / Flask App with Gunicorn and Nginx on Ubuntu

Quick Answer: To deploy a Python Django or Flask web application on Ubuntu: 1) Create an isolated Python virtual environment (python3 -m venv myenv), 2) Install Gunicorn as the WSGI server, 3) Create a Systemd socket and service file to manage the Gunicorn daemon, and 4) Configure Nginx to serve static/media files directly and proxy dynamic requests to the Gunicorn UNIX socket.

⏱️ 4 min read (866 words)
🛡️ Verified on Ubuntu 24.04 / Debian 12
🔄 Updated for 2026 Edition

Step 1: Set Up Python Virtual Environment & Gunicorn

sudo apt update && sudo apt install -y python3-pip python3-venv python3-dev libpq-dev nginx
cd /var/www/my-django-app
python3 -m venv myenv
source myenv/bin/activate
pip install -r requirements.txt gunicorn

Step 2: Create Systemd Service File for Gunicorn

Create /etc/systemd/system/gunicorn.service:


⚡ Executive Summary & Key Takeaways

Verified Guide
  • Core Architecture: Production setup of Python Django / Flask App with Gunicorn and Nginx on Ubuntu engineered for maximum throughput and minimal memory footprint.
  • Deployment Speed: Fast-track setup under 5–10 minutes with isolated daemon processes and secure system permissions.
  • Security Hardening: Configured with dedicated system users, UFW network rules, and automated SSL/TLS termination.
  • Cost & Sovereignty: 100% open-source self-hosting on Linux VPS, eliminating expensive recurring SaaS subscriptions.

🎯 Difficulty: Intermediate
⚡ Est. Execution: 10–15 Mins
⏱️ 6 min read (1,068 words)

🔄 Verified September 2026 Edition

🐧 Target Environment: Ubuntu 24.04 / 22.04 LTS • Debian 12 • AlmaLinux 9
🛡️ Reviewed by: Senior Linux Systems Architect
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/my-django-app
ExecStart=/var/www/my-django-app/myenv/bin/gunicorn           --access-logfile -           --workers 3           --bind unix:/run/gunicorn.sock           myproject.wsgi:application

[Install]
WantedBy=multi-user.target
# Start and enable Gunicorn service
sudo systemctl start gunicorn && sudo systemctl enable gunicorn

Zero Server Overhead

Prefer Not to Manage Commands via Terminal?

Deploy high-speed hosting with CpanelFree $0 Free Web Hosting. Enjoy authentic cPanel, unmetered NVMe SSD storage, PHP 8.3, and automatic SSL without server maintenance.

Step 3: Configure Nginx Reverse Proxy for Python

Create /etc/nginx/sites-available/django.conf:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    
    location /static/ {
        root /var/www/my-django-app;
    }

    location /media/ {
        root /var/www/my-django-app;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
sudo ln -s /etc/nginx/sites-available/django.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Managing Static Files with WhiteNoise in Production Django

While Nginx can serve static assets directly, installing WhiteNoise allows Django to serve compressed, cache-busting static files directly through WSGI with zero external configuration:

# In settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ...
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Automating Django Migrations and Static Collection via Bash Script

#!/bin/bash
# deploy.sh
source myenv/bin/activate
git pull origin main
pip install -r requirements.txt
python manage.py migrate --noinput
python manage.py collectstatic --noinput
sudo systemctl restart gunicorn

Production Security Checklist for Django Deployments

  • 🔒 Set DEBUG = False: Never run DEBUG = True in production, as error tracebacks reveal database schemas and secret API keys to visitors.
  • 🔒 Configure ALLOWED_HOSTS: Restrict ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com'] in settings.py to prevent HTTP Host header poisoning.
  • 🔒 Enforce Secure Cookies: Enable CSRF_COOKIE_SECURE = True and SESSION_COOKIE_SECURE = True to ensure cookies are only transmitted over encrypted HTTPS connections.
  • 🔒 Use Environment Variables for SECRETS: Store database passwords and SECRET_KEY inside a local .env file managed via python-dotenv.

Why use UNIX sockets instead of TCP ports (127.0.0.1:8000) for Gunicorn?

UNIX domain sockets (unix:/run/gunicorn.sock) communicate directly through kernel memory buffers, bypassing the TCP network stack overhead and delivering up to 15% higher request throughput.

Frequently Asked Questions

How many Gunicorn workers should I configure?

The standard formula recommended by the Gunicorn team is (2 x $num_cores) + 1. On a 2 vCPU VPS, configure 5 workers for optimal throughput.

Configuring Celery Background Task Workers with Redis on Ubuntu

For long-running tasks like sending notification emails or generating PDF reports in Django, run Celery with a Redis message broker alongside Gunicorn:

# Install Redis server and Celery
sudo apt install -y redis-server
pip install celery redis

# Launch Celery worker daemon
celery -A myproject worker --loglevel=info --concurrency=4

Pro Sysadmin Tip: Monitoring Gunicorn Socket Status

Verify UNIX socket communication health using sudo systemctl status gunicorn.socket and inspect real-time worker logs via sudo journalctl -u gunicorn -f.

Deploying Python Django and Flask applications with Gunicorn, Systemd, and Nginx ensures sub-second response times, robust security isolation, and effortless production scalability.

Configuring Automated PostgreSQL Database Backups for Django

Protect your production Django data by configuring a nightly cron job that exports compressed PostgreSQL database dumps directly to encrypted offsite cloud storage:

# Automated PostgreSQL Nightly Dump
0 3 * * * pg_dump -U djangouser djangodb | gzip > /var/backups/django_$(date +\%F).sql.gz

How do I run Django database migrations during production updates?

Activate your virtual environment and run python manage.py migrate --noinput followed by sudo systemctl restart gunicorn to apply schema updates without downtime.

Additionally, configuring Gunicorn with Systemd socket activation ensures that incoming web traffic automatically spawns application worker threads with zero manual intervention.

Following this production deployment architecture ensures your Django and Flask web applications operate with maximum security, reliability, and speed on Linux VPS servers.

Setting up dedicated virtual environments and automated Gunicorn process monitoring guarantees maximum stability and performance for your mission-critical Python web applications.

Following this production architecture ensures complete data isolation, high concurrency handling, and rapid response times for full-stack Python web development projects.

Employing modern WSGI process management combined with Nginx edge proxy caching unlocks blazing performance for production web frameworks on Ubuntu.

🚀 Production Cloud Infrastructure

Deploy on High-Performance Cloud VPS with MeraHost

Need dedicated vCPU, root SSH access, pure NVMe SSD speeds, and 99.95% uptime SLA for your production stack? Launch with MeraHost — guaranteed price lock with zero renewal hikes.

Leave a Comment