Install and configure uWSGI application server with Nginx reverse proxy for Python web applications

Beginner 25 min Apr 17, 2026 11 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up a production-ready Python web application stack with uWSGI as the WSGI server and Nginx as a reverse proxy. Includes SSL certificate setup, systemd service configuration, and troubleshooting guide for Django and Flask deployments.

Prerequisites

  • Root or sudo access
  • Domain name pointing to your server
  • Basic Python knowledge

What this solves

uWSGI serves as the bridge between your Python web applications (Django, Flask, FastAPI) and a web server like Nginx. Unlike development servers, uWSGI handles multiple concurrent requests efficiently and provides production features like process management, memory monitoring, and graceful reloads. This setup gives you a scalable foundation for Python web applications with proper SSL termination and static file serving.

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, pip, and development tools

Install Python 3 and the development headers needed to compile uWSGI from source if required.

sudo apt install -y python3 python3-pip python3-dev python3-venv gcc libc6-dev
sudo dnf install -y python3 python3-pip python3-devel python3-venv gcc glibc-devel

Install Nginx web server

Nginx will handle SSL termination, static file serving, and proxy requests to uWSGI.

sudo apt install -y nginx
sudo dnf install -y nginx

Create application user and directory

Create a dedicated user for your Python application to improve security isolation.

sudo useradd --system --home /opt/myapp --create-home --shell /bin/bash myapp
sudo mkdir -p /opt/myapp/{app,logs,static}
sudo chown -R myapp:myapp /opt/myapp

Install uWSGI system-wide

Install uWSGI globally so it can be managed by systemd. This approach works better than virtual environment installations for production services.

sudo apt install -y uwsgi uwsgi-plugin-python3
sudo pip3 install uwsgi

Create sample Python application

Create a simple WSGI application to test the setup. This works with any WSGI-compliant framework.

def application(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/html; charset=utf-8')]
    start_response(status, headers)
    
    response_body = b'''
    
    
    uWSGI Test
    
        

uWSGI is working!

Your Python application server is running correctly.

Server: uWSGI + Nginx

''' return [response_body]

Configure uWSGI application settings

Create the uWSGI configuration file with production-ready settings including process management and logging.

[uwsgi]

Application settings

module = wsgi:application chdir = /opt/myapp/app home = /opt/myapp/venv

Process management

master = true processes = 4 threads = 2 max-requests = 1000 max-requests-delta = 100

Socket settings

socket = /opt/myapp/uwsgi.sock chmod-socket = 664 vacuum = true die-on-term = true

User and group

uid = myapp gid = myapp

Logging

logto = /opt/myapp/logs/uwsgi.log log-maxsize = 50000000 log-backupname = /opt/myapp/logs/uwsgi.log.old

Security

disable-logging = false ignore-sigpipe = true ignore-write-errors = true disable-write-exception = true

Performance

enable-threads = true single-interpreter = true lazy-apps = true preload-app = true

Set correct file permissions

Configure ownership and permissions for the application files and directories.

sudo chown -R myapp:myapp /opt/myapp
sudo chmod 755 /opt/myapp
sudo chmod 755 /opt/myapp/app
sudo chmod 644 /opt/myapp/app/wsgi.py
sudo chmod 644 /opt/myapp/uwsgi.ini
sudo chmod 755 /opt/myapp/logs
sudo chmod 755 /opt/myapp/static
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 shown above.

Create systemd service for uWSGI

Configure uWSGI as a systemd service for automatic startup and process management.

[Unit]
Description=uWSGI instance to serve myapp
After=network.target

[Service]
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/uwsgi --ini uwsgi.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
StandardError=syslog

[Install]
WantedBy=multi-user.target

Configure Nginx reverse proxy

Set up Nginx to proxy requests to uWSGI and serve static files directly.

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;
    
    # Static files
    location /static/ {
        alias /opt/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
    
    # Media files (uploads)
    location /media/ {
        alias /opt/myapp/media/;
        expires 7d;
    }
    
    # Main application
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/opt/myapp/uwsgi.sock;
        uwsgi_read_timeout 300;
        uwsgi_connect_timeout 300;
        uwsgi_send_timeout 300;
        
        # Forward real IP
        uwsgi_param HTTP_X_FORWARDED_FOR $remote_addr;
        uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
        uwsgi_param HTTP_HOST $server_name;
    }
    
    # Deny access to sensitive files
    location ~ /\.(ht|env|git) {
        deny all;
    }
    
    # Custom error pages
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

Enable Nginx site configuration

Activate the site configuration and test the Nginx syntax before restarting.

sudo ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t

Start and enable services

Start both uWSGI and Nginx services and configure them to start automatically on boot.

sudo systemctl daemon-reload
sudo systemctl enable --now myapp-uwsgi
sudo systemctl enable --now nginx
sudo systemctl status myapp-uwsgi
sudo systemctl status nginx

Install Certbot for SSL certificates

Set up Let's Encrypt SSL certificates for secure HTTPS connections. This uses the official Certbot from Let's Encrypt.

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

Obtain SSL certificate

Generate SSL certificates for your domain. Replace example.com with your actual domain name.

sudo certbot --nginx -d example.com -d www.example.com
Note: Certbot will automatically modify your Nginx configuration to include SSL settings and redirect HTTP to HTTPS.

Set up automatic certificate renewal

Configure automatic renewal of SSL certificates to prevent expiration.

sudo systemctl enable --now certbot.timer
sudo systemctl status certbot.timer

Configure for Django applications

For Django applications, you need to modify the uWSGI configuration to point to your Django project's WSGI module.

[uwsgi]

Django settings

module = myproject.wsgi:application chdir = /opt/myapp/app home = /opt/myapp/venv env = DJANGO_SETTINGS_MODULE=myproject.settings.production

Process management

master = true processes = 4 threads = 2 max-requests = 1000 max-requests-delta = 100

Socket settings

socket = /opt/myapp/uwsgi.sock chmod-socket = 664 vacuum = true die-on-term = true

User and group

uid = myapp gid = myapp

Django static files

static-map = /static=/opt/myapp/static static-expires-uri = /static/.* 3600

Logging

logto = /opt/myapp/logs/uwsgi.log log-maxsize = 50000000 log-backupname = /opt/myapp/logs/uwsgi.log.old

Performance

enable-threads = true single-interpreter = true lazy-apps = true preload-app = true

Configure for Flask applications

Flask applications require a simple WSGI configuration pointing to your Flask app instance.

from myflaskapp import create_app

Create Flask application instance

application = create_app() if __name__ == "__main__": application.run()
[uwsgi]

Flask settings

module = wsgi:application chdir = /opt/myapp/app home = /opt/myapp/venv callable = application

Process management

master = true processes = 2 threads = 4 max-requests = 1000

Socket and permissions

socket = /opt/myapp/uwsgi.sock chmod-socket = 664 vacuum = true die-on-term = true uid = myapp gid = myapp

Logging

logto = /opt/myapp/logs/uwsgi.log req-logger = file:/opt/myapp/logs/requests.log

Performance

enable-threads = true lazy-apps = true

Performance tuning

Optimize uWSGI performance based on your server resources and traffic patterns.

SettingPurposeRecommended Value
processesNumber of worker processesCPU cores × 2
threadsThreads per process2-4 for I/O heavy apps
max-requestsRequests before worker restart1000-5000
buffer-sizeRequest buffer size32768 for large headers
harakiriRequest timeout (seconds)30-300 depending on app
[uwsgi]

Your existing configuration...

Performance tuning

buffer-size = 32768 harakiri = 120 harakiri-verbose = true max-worker-lifetime = 3600 reload-on-rss = 512 worker-reload-mercy = 60

Memory reporting

memory-report = true

Cheaper scaling (dynamic workers)

cheaper = 2 cheaper-initial = 2 cheaper-step = 1 cheaper-algo = spare2 cheaper-overload = 30

Verify your setup

Test that your uWSGI and Nginx configuration is working correctly.

# Check service status
sudo systemctl status myapp-uwsgi
sudo systemctl status nginx

Test HTTP response

curl -I http://example.com

Test HTTPS response

curl -I https://example.com

Check uWSGI socket

ls -la /opt/myapp/uwsgi.sock

Monitor logs

sudo tail -f /opt/myapp/logs/uwsgi.log sudo tail -f /var/log/nginx/error.log

Common issues

SymptomCauseFix
502 Bad GatewayuWSGI socket not accessibleCheck socket permissions: chmod 664 /opt/myapp/uwsgi.sock
uWSGI won't startConfiguration syntax errorTest config: uwsgi --ini /opt/myapp/uwsgi.ini --check-static
Permission denied errorsWrong file ownershipFix ownership: sudo chown -R myapp:myapp /opt/myapp
Static files not loadingNginx can't read static directoryCheck permissions: sudo chmod 755 /opt/myapp/static
SSL certificate errorsCertbot couldn't verify domainCheck DNS and firewall: sudo certbot certificates
High memory usageMemory leaks in applicationEnable worker recycling: max-requests = 1000
Slow response timesInsufficient worker processesIncrease processes: processes = 4

Next steps

Running this in production?

Want this handled for you? This works for a single server. When you run multiple environments or need this available 24/7, keeping it healthy is a different job. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

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