uWSGI
High-performance and feature-rich Python WSGI/HTTP server. Detailed configuration with 120+ parameters. HTTPS support, dedicated uwsgi protocol, spooler functionality.
Application Server
uWSGI
Overview
uWSGI is a high-performance, multi-protocol application server designed to serve web applications and facilitate seamless communication between web servers and application code. Born from the need to optimize Python web application deployment, uWSGI has evolved into a comprehensive solution supporting multiple programming languages, protocols, and deployment scenarios. Built with performance and flexibility at its core, uWSGI employs a sophisticated hierarchical process model featuring master processes, worker processes, spoolers, and mules to handle diverse workloads efficiently. Its robust plugin architecture enables support for Python WSGI, Ruby Rack, PHP, Lua, and other language ecosystems, while its native protocol optimization ensures maximum throughput when paired with web servers like Nginx and Apache.
Details
uWSGI 2025 edition represents the pinnacle of application server technology, delivering enterprise-grade performance and reliability for modern web applications. The server architecture centers around a master process that supervises and coordinates multiple worker processes, each capable of handling concurrent requests through configurable threading models. Beyond basic request handling, uWSGI incorporates specialized process types including spoolers for asynchronous task processing and mules for background job execution. The server supports multiple protocols including HTTP, its optimized native uWSGI protocol, FastCGI, and SCGI, with automatic protocol detection and routing capabilities. Advanced features include a high-performance caching system, comprehensive metrics collection, dynamic application loading, and the innovative Emperor mode for managing multiple application instances with automatic scaling and monitoring.
Key Features
- Multi-Protocol Support: Native support for HTTP, uWSGI, FastCGI, SCGI protocols with optimized parsers
- Advanced Process Management: Master-worker architecture with spoolers and mules for specialized tasks
- High-Performance Caching: Built-in shared memory caching system for application data and responses
- Language Versatility: Plugin architecture supporting Python, Ruby, PHP, Lua, and other languages
- Dynamic Configuration: Flexible configuration through files, command-line, and environment variables
- Emperor Mode: Advanced deployment management with automatic scaling and process monitoring
Advantages and Disadvantages
Advantages
- Exceptional performance and throughput with optimized binary protocols and efficient memory management
- Comprehensive multi-language support through modular plugin architecture enabling diverse application stacks
- Advanced process management with master-worker model, spoolers, and mules for robust production deployments
- Flexible deployment options from standalone web server to integration with Nginx, Apache, and cloud platforms
- Rich feature set including caching, metrics, routing, and asynchronous processing capabilities
- Emperor mode providing sophisticated application lifecycle management and automatic scaling
- Extensive configuration flexibility supporting complex enterprise deployment scenarios
Disadvantages
- Steep learning curve due to extensive configuration options and advanced features requiring expertise
- Configuration complexity can be overwhelming for simple applications where lighter alternatives might suffice
- Resource consumption can be significant with multiple processes and plugins in high-traffic scenarios
- Debugging challenges in multi-process, multi-threaded environments with various plugins and protocols
- Documentation fragmentation across different features and deployment scenarios
- Overkill for simple applications that don't require advanced process management or multi-protocol support
- Potential compatibility issues when upgrading between major versions affecting existing configurations
Reference Links
Configuration Examples
Basic WSGI Application Setup
# app.py - Simple WSGI application
def application(environ, start_response):
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf-8')]
start_response(status, headers)
response_body = f"""
<html>
<head><title>uWSGI Application</title></head>
<body>
<h1>Hello from uWSGI!</h1>
<p>Request Method: {environ['REQUEST_METHOD']}</p>
<p>Path Info: {environ['PATH_INFO']}</p>
<p>Query String: {environ['QUERY_STRING']}</p>
<p>Server Name: {environ['SERVER_NAME']}</p>
<p>Server Port: {environ['SERVER_PORT']}</p>
</body>
</html>
"""
return [response_body.encode('utf-8')]
# Start uWSGI with command line
# uwsgi --http :8080 --wsgi-file app.py --master --processes 4 --threads 2
INI Configuration File
# uwsgi.ini - Comprehensive uWSGI configuration
[uwsgi]
# Basic settings
module = app:application
master = true
processes = 4
threads = 2
enable-threads = true
# Socket configuration
socket = 127.0.0.1:9001
protocol = uwsgi
http = :8080
# Process management
vacuum = true
die-on-term = true
harakiri = 30
harakiri-verbose = true
max-requests = 5000
max-requests-delta = 100
# Memory and performance
buffer-size = 32768
post-buffering = 8192
offload-threads = 2
thunder-lock = true
# Logging
logto = /var/log/uwsgi/app.log
log-maxsize = 20971520
log-backupname = /var/log/uwsgi/app.log.old
logformat = %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)" %(msecs)ms
# Security
chmod-socket = 666
uid = www-data
gid = www-data
no-orphans = true
# Performance monitoring
stats = 127.0.0.1:9191
stats-http = true
memory-report = true
# Python-specific settings
pythonpath = /var/www/myapp
virtualenv = /var/www/myapp/venv
lazy-apps = true
enable-threads = true
# Static file serving
static-map = /static=/var/www/myapp/static
static-expires-uri = /static/.* 3600
# Caching
cache2 = name=mycache,items=1000
Django Application Configuration
# django.ini - Django-specific uWSGI configuration
[uwsgi]
# Django settings
chdir = /var/www/myproject
module = myproject.wsgi:application
env = DJANGO_SETTINGS_MODULE=myproject.settings.production
# Process configuration
master = true
processes = 4
threads = 2
enable-threads = true
# Socket and networking
socket = /var/www/myproject/myproject.sock
chmod-socket = 666
vacuum = true
# Performance settings
harakiri = 60
max-requests = 5000
max-requests-delta = 50
buffer-size = 32768
# Python environment
home = /var/www/myproject/venv
pythonpath = /var/www/myproject
lazy-apps = true
# Logging
logto = /var/log/uwsgi/django.log
log-maxsize = 50000000
log-reopen = true
# Security
uid = www-data
gid = www-data
no-orphans = true
die-on-term = true
# Django static files
static-map = /static=/var/www/myproject/static
static-map = /media=/var/www/myproject/media
static-expires = /* 86400
# Health check
route = ^/health$ break:200 OK\n
# Stats and monitoring
stats = 127.0.0.1:9192
stats-http = true
memory-report = true
Flask Application with Advanced Features
# flask_app.py - Flask application with uWSGI integration
from flask import Flask, request, jsonify
import os
import time
app = Flask(__name__)
@app.route('/')
def hello():
return {
'message': 'Hello from Flask + uWSGI!',
'pid': os.getpid(),
'worker_id': os.environ.get('UWSGI_WORKER_ID', 'unknown'),
'timestamp': time.time()
}
@app.route('/health')
def health():
return {'status': 'healthy', 'pid': os.getpid()}
@app.route('/slow')
def slow_endpoint():
time.sleep(2) # Simulate slow processing
return {'message': 'Slow response completed', 'pid': os.getpid()}
@app.route('/info')
def info():
return {
'method': request.method,
'path': request.path,
'args': dict(request.args),
'headers': dict(request.headers),
'remote_addr': request.remote_addr
}
if __name__ == '__main__':
app.run(debug=True)
# flask.ini - Flask uWSGI configuration
[uwsgi]
# Flask settings
module = flask_app:app
callable = app
# Process configuration
master = true
processes = 4
threads = 4
enable-threads = true
# Socket configuration
http = :5000
socket = /tmp/flask-uwsgi.sock
chmod-socket = 666
# Performance settings
harakiri = 30
max-requests = 1000
buffer-size = 32768
post-buffering = 4096
# Python environment
virtualenv = ./venv
pythonpath = .
lazy-apps = true
# Logging and monitoring
logto = flask-uwsgi.log
stats = 127.0.0.1:9193
memory-report = true
# Development settings (remove in production)
python-autoreload = 1
py-auto-reload = 1
# Cache configuration
cache2 = name=flask_cache,items=1000,keysize=64,valuesize=1024
# Route optimization
route-run = addvar:SCRIPT_NAME=/api
route-run = remvar:PATH_INFO
# Static files
static-map = /static=./static
static-expires = /* 3600
Production Configuration with Nginx Integration
# production.ini - Production-ready uWSGI configuration
[uwsgi]
# Application settings
module = app:application
master = true
processes = 8
threads = 2
enable-threads = true
# High-performance socket configuration
socket = /var/run/uwsgi/app.sock
chmod-socket = 664
vacuum = true
# Process management
harakiri = 60
harakiri-verbose = true
max-requests = 10000
max-requests-delta = 500
worker-reload-mercy = 60
reload-mercy = 8
# Memory and performance optimization
buffer-size = 65536
post-buffering = 65536
offload-threads = 4
thunder-lock = true
disable-logging = false
# Security settings
uid = uwsgi
gid = uwsgi
no-orphans = true
die-on-term = true
# Logging configuration
logto = /var/log/uwsgi/app.log
log-maxsize = 100000000
log-backupname = /var/log/uwsgi/app.log.@(exec://date +%%Y-%%m-%%d)
logformat = %(ltime) [%(pid)] %(method) %(uri) => %(status) (%(rsize) bytes in %(msecs)ms)
# Stats and monitoring
stats = /var/run/uwsgi/stats.sock
stats-http = true
memory-report = true
# Python optimization
pythonpath = /var/www/app
virtualenv = /var/www/app/venv
lazy-apps = true
single-interpreter = true
# Caching
cache2 = name=appcache,items=10000,keysize=64,valuesize=8192,blocks=1000
# Static file handling
static-map = /static=/var/www/app/static
static-map = /media=/var/www/app/media
static-expires-uri = /static/.* 86400
static-expires-uri = /media/.* 86400
# Health monitoring
route = ^/health$ break:200 Server OK\n
route = ^/stats$ break-with-status:200 ${uwsgi[stats]}
# Graceful reloading
touch-reload = /var/www/app/reload.trigger
py-auto-reload = 1
Emperor Mode Configuration
# emperor.ini - Emperor mode configuration
[uwsgi]
# Emperor settings
emperor = /etc/uwsgi/apps-enabled
emperor-tyrant = true
emperor-stats = 127.0.0.1:9198
emperor-stats-server = 127.0.0.1:9199
# Emperor process settings
master = true
die-on-term = true
uid = root
gid = root
# Logging
logto = /var/log/uwsgi/emperor.log
log-maxsize = 50000000
# Emperor specific features
emperor-pidfile = /var/run/uwsgi-emperor.pid
emperor-reload-mercy = 8
emperor-worker-reload-mercy = 60
# Monitoring
memory-report = true
# vassal-app.ini - Individual vassal configuration
[uwsgi]
# Vassal identification
vassal-name = myapp
# Application settings
chdir = /var/www/myapp
module = app:application
virtualenv = /var/www/myapp/venv
# Process configuration
master = true
processes = 4
threads = 2
# Socket for this vassal
socket = /var/run/uwsgi/myapp.sock
chmod-socket = 666
# Vassal-specific settings
uid = myapp
gid = myapp
harakiri = 30
max-requests = 5000
# Logging
logto = /var/log/uwsgi/myapp.log
# Auto-reload on code changes
touch-reload = /var/www/myapp/reload.trigger
py-auto-reload = 1
# Vassal monitoring
memory-report = true
Advanced Features Configuration
# advanced.ini - Advanced uWSGI features
[uwsgi]
# Application
module = advanced_app:application
master = true
processes = 4
threads = 2
# Advanced socket configuration
socket = 127.0.0.1:9001
http = :8080
protocol = uwsgi
# Spooler configuration for async tasks
spooler = /var/spool/uwsgi
spooler-processes = 2
spooler-frequency = 30
# Mule processes for background tasks
mule = /var/www/app/mules/worker.py
mule = /var/www/app/mules/worker.py
mule = /var/www/app/mules/cleanup.py
# Cron-like functionality
cron = 0 2 -1 -1 -1 /var/www/app/scripts/daily_cleanup.py
cron = */5 -1 -1 -1 -1 /var/www/app/scripts/health_check.py
# Signal handling
hook-master-start = unix_signal:15 gracefully_kill_them_all
hook-as-user = exec:/var/www/app/scripts/setup.sh
# Route handling
route = ^/api/v1/ uwsgi:/var/run/uwsgi/api.sock
route = ^/legacy/ redirect-permanent:https://newsite.com${REQUEST_URI}
route = ^/static/ static
route-if-not = equal:${REQUEST_METHOD};GET break:405 Method Not Allowed
# Internal routing
internal-routing = true
route-run = addvar:REQUEST_ID_HEADER=X-Request-ID:${time}-${pid}-${wid}
# Metrics and monitoring
stats = 127.0.0.1:9194
carbon = 127.0.0.1:2003
carbon-name-resolve = true
carbon-id = uwsgi-app
# Memory limits
limit-as = 1024
reload-on-as = 512
reload-on-rss = 400
# Request/response transformation
response-route = ^/api/ addheader:Access-Control-Allow-Origin: *
response-route = ^/api/ addheader:Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Docker Configuration
# Dockerfile for uWSGI application
FROM python:3.11-slim
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create uwsgi user
RUN adduser --system --group uwsgi
# Create necessary directories
RUN mkdir -p /var/log/uwsgi /var/run/uwsgi && \
chown -R uwsgi:uwsgi /var/log/uwsgi /var/run/uwsgi /app
# Copy uWSGI configuration
COPY uwsgi.ini /etc/uwsgi/
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# Switch to uwsgi user
USER uwsgi
# Expose port
EXPOSE 8080
# Start uWSGI
CMD ["uwsgi", "--ini", "/etc/uwsgi/uwsgi.ini"]
# docker-compose.yml for uWSGI application stack
version: '3.8'
services:
uwsgi:
build: .
container_name: uwsgi-app
volumes:
- ./app:/app
- ./logs:/var/log/uwsgi
- uwsgi_socket:/var/run/uwsgi
environment:
- UWSGI_INI=/app/uwsgi.ini
- PYTHONPATH=/app
networks:
- app_network
restart: unless-stopped
nginx:
image: nginx:alpine
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./static:/var/www/static:ro
- uwsgi_socket:/var/run/uwsgi
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- uwsgi
networks:
- app_network
restart: unless-stopped
redis:
image: redis:alpine
container_name: redis-cache
networks:
- app_network
restart: unless-stopped
volumes:
uwsgi_socket:
networks:
app_network:
driver: bridge
Performance Monitoring and Management
# monitoring.py - uWSGI performance monitoring
import uwsgi
import json
import time
import psutil
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/uwsgi/stats')
def uwsgi_stats():
"""Get comprehensive uWSGI statistics"""
try:
# Get uWSGI stats
stats = {
'worker_id': uwsgi.worker_id(),
'masterpid': uwsgi.masterpid(),
'total_requests': uwsgi.total_requests(),
'workers': []
}
# Worker-specific information
for i in range(uwsgi.numproc):
worker_stats = {
'id': i,
'pid': uwsgi.worker_pid(i) if i < uwsgi.numproc else None,
'requests': uwsgi.worker_requests(i) if i < uwsgi.numproc else 0,
'memory': uwsgi.worker_memory(i) if i < uwsgi.numproc else 0,
'vsz': uwsgi.worker_vsz(i) if i < uwsgi.numproc else 0,
'status': 'active' if uwsgi.worker_pid(i) else 'inactive'
}
stats['workers'].append(worker_stats)
return jsonify(stats)
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/system/stats')
def system_stats():
"""Get system performance statistics"""
try:
cpu_percent = psutil.cpu_percent(interval=1)
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
stats = {
'cpu': {
'percent': cpu_percent,
'count': psutil.cpu_count()
},
'memory': {
'total': memory.total,
'available': memory.available,
'percent': memory.percent,
'used': memory.used
},
'disk': {
'total': disk.total,
'used': disk.used,
'free': disk.free,
'percent': (disk.used / disk.total) * 100
},
'timestamp': time.time()
}
return jsonify(stats)
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, port=5001)
#!/bin/bash
# uwsgi_management.sh - uWSGI management script
UWSGI_CONFIG="/etc/uwsgi/apps-enabled/myapp.ini"
UWSGI_PID="/var/run/uwsgi/myapp.pid"
UWSGI_SOCKET="/var/run/uwsgi/myapp.sock"
UWSGI_LOG="/var/log/uwsgi/myapp.log"
start_uwsgi() {
echo "Starting uWSGI application..."
uwsgi --ini $UWSGI_CONFIG --daemonize $UWSGI_LOG
echo "uWSGI started with PID: $(cat $UWSGI_PID)"
}
stop_uwsgi() {
echo "Stopping uWSGI application..."
if [ -f $UWSGI_PID ]; then
uwsgi --stop $UWSGI_PID
echo "uWSGI stopped"
else
echo "uWSGI PID file not found"
fi
}
reload_uwsgi() {
echo "Reloading uWSGI application..."
if [ -f $UWSGI_PID ]; then
uwsgi --reload $UWSGI_PID
echo "uWSGI reloaded"
else
echo "uWSGI PID file not found"
fi
}
status_uwsgi() {
if [ -f $UWSGI_PID ]; then
PID=$(cat $UWSGI_PID)
if ps -p $PID > /dev/null; then
echo "uWSGI is running (PID: $PID)"
# Show worker statistics
echo "Worker Statistics:"
uwsgi --connect-and-read $UWSGI_SOCKET | head -20
else
echo "uWSGI is not running (stale PID file)"
fi
else
echo "uWSGI is not running"
fi
}
logs_uwsgi() {
echo "Tailing uWSGI logs..."
tail -f $UWSGI_LOG
}
case "$1" in
start)
start_uwsgi
;;
stop)
stop_uwsgi
;;
restart)
stop_uwsgi
sleep 2
start_uwsgi
;;
reload)
reload_uwsgi
;;
status)
status_uwsgi
;;
logs)
logs_uwsgi
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status|logs}"
exit 1
;;
esac