⚠️ PROJECT STATUS: MAINTENANCE MODE
uWSGI is in maintenance mode (announced 2024). Security patches may be slower than active projects. For new projects, consider Gunicorn, Uvicorn, or Granian.
uWSGI is an application server (not a web server) that runs Python web applications. It should always be deployed behind a reverse proxy like Nginx or Apache.
# TCP socket (localhost only)
socket = 127.0.0.1:8000
# Unix socket (recommended for local)
socket = /var/run/uwsgi/myapp.sock
chmod-socket = 660
Never expose uWSGI directly:
Internet → [Nginx/Apache] → [uWSGI (localhost only)]
# UFW - Block direct uWSGI access
sudo ufw deny 8000/tcp
# Allow only HTTP/HTTPS through proxy
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Comment out if not monitoring
# stats = 127.0.0.1:9191
# stats-http = true
harakiri = 30
harakiri-verbose = true
socket-timeout = 65
http-timeout = 65
reload-on-rss = 512
reload-on-as = 1024
max-requests = 5000
# Remove sample configurations
sudo rm -f /etc/uwsgi/*.sample
# Configuration
sudo chown root:root /etc/uwsgi/*.ini
sudo chmod 644 /etc/uwsgi/*.ini
# Socket
sudo chown www-data:www-data /var/run/uwsgi/myapp.sock
sudo chmod 660 /var/run/uwsgi/myapp.sock
[uwsgi]
uid = www-data
gid = www-data
# /etc/systemd/system/uwsgi.service
[Service]
User=www-data
Group=www-data
# Filesystem protection
ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=true
ReadWritePaths=/var/run/uwsgi /var/log/uwsgi
# Network restrictions
RestrictAddressFamilies=AF_INET AF_INET6
# Capability restrictions
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=
# System call filtering
SystemCallArchitectures=native
SystemCallFilter=@system-service
# Memory protection
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
# Restrict privileges
NoNewPrivileges=true
RestrictSUIDSGID=true
# Resource limits
LimitNOFILE=65535
CPUQuota=50%
MemoryLimit=512M
# Package update
sudo apt update && sudo apt upgrade uwsgi
# Or pip update
pip install --upgrade uwsgi
⚠️ Note: Due to maintenance mode, updates may be less frequent.
processes = 4
threads = 2
cheaper = 2
cheaper-initial = 2
cheaper-step = 1
buffer-size = 65535
post-buffering = 4096
limit-post = 10485760
logto = /var/log/uwsgi/myapp.log
log-maxsize = 52428800
log-backupname = /var/log/uwsgi/myapp.log.old
log-4xx = true
log-5xx = true
log-date = true
server {
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
# 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;
}
}
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
server {
location / {
limit_req zone=one burst=20 nodelay;
include uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
}
}
# Test configuration
uwsgi --ini /etc/uwsgi/myapp.ini
# Check syntax
uwsgi --ini /etc/uwsgi/myapp.ini --check-config
# Check running user
ps aux | grep uwsgi
# Check open ports
sudo netstat -tlnp | grep uwsgi
# Check file permissions
ls -la /etc/uwsgi/
ls -la /var/run/uwsgi/
# Check systemd hardening
systemctl show uwsgi | grep -E "Protect|Private|Restrict"