SyntaxStudy
Sign Up
Django Gunicorn and Nginx Configuration
Django Beginner 1 min read

Gunicorn and Nginx Configuration

Gunicorn (Green Unicorn) is the most commonly used WSGI server for Django in production. It is a pure Python HTTP server that spawns multiple worker processes to handle concurrent requests. Each worker is a separate Python process running your Django application. Gunicorn sits behind a reverse proxy (Nginx) which handles static files, SSL termination, and load balancing before passing dynamic requests to Gunicorn. The typical production stack is: Nginx (reverse proxy and static file server) -> Gunicorn (WSGI server) -> Django (application). Nginx listens on port 80/443, serves static and media files directly from the filesystem, and proxies all other requests to Gunicorn via a Unix socket. This architecture means Gunicorn workers are never busy serving static files, maximising throughput for dynamic requests. Gunicorn is started with the gunicorn command, specifying the WSGI application as module:callable (e.g. mysite.wsgi:application). Key options include --workers (number of worker processes — a common formula is 2 * CPU cores + 1), --bind (address and port or Unix socket path), --timeout (request timeout in seconds), and --log-level. In production, Gunicorn is managed by systemd or supervisor to ensure it restarts automatically after crashes.
Example
# Install Gunicorn
# pip install gunicorn

# Start Gunicorn (development test)
# gunicorn mysite.wsgi:application --bind 0.0.0.0:8000 --workers 3

# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon for mysite
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/mysite
ExecStart=/var/www/mysite/venv/bin/gunicorn \
    --workers 5 \
    --bind unix:/run/gunicorn/gunicorn.sock \
    --timeout 120 \
    --log-level warning \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile  /var/log/gunicorn/error.log \
    mysite.wsgi:application
Restart=on-failure

[Install]
WantedBy=multi-user.target

# /etc/nginx/sites-available/mysite
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location /static/ {
        alias /var/www/mysite/staticfiles/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location /media/ {
        alias /var/www/mysite/media/;
    }

    location / {
        proxy_pass         http://unix:/run/gunicorn/gunicorn.sock;
        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;
    }
}