HxHippy

Django Application

Nginx configuration for Django applications with Gunicorn/uWSGI.

Last updated: 2025-01-15

Django with Gunicorn

upstream django {
    server unix:/run/gunicorn/socket fail_timeout=0;
    # Or TCP: server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

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

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

    # Logs
    access_log /var/log/nginx/django.access.log;
    error_log /var/log/nginx/django.error.log;

    # Max upload size
    client_max_body_size 10M;

    # Static files
    location /static/ {
        alias /var/www/django/staticfiles/;
        expires 30d;
        access_log off;
    }

    # Media files
    location /media/ {
        alias /var/www/django/media/;
        expires 30d;
    }

    # Django app
    location / {
        proxy_pass http://django;
        proxy_http_version 1.1;
        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;
        proxy_redirect off;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
    }
}

Django with uWSGI

upstream django {
    server unix:///var/run/uwsgi/django.sock;
}

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

    # Static files
    location /static/ {
        alias /var/www/django/staticfiles/;
    }

    # uWSGI
    location / {
        include uwsgi_params;
        uwsgi_pass django;

        uwsgi_param Host $host;
        uwsgi_param X-Real-IP $remote_addr;
        uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
        uwsgi_param X-Forwarded-Proto $scheme;
    }
}

Django Admin Protection

server {
    # ... SSL and basic config ...

    # Protect admin area
    location /admin/ {
        # IP whitelist
        allow 192.168.1.0/24;
        deny all;

        proxy_pass http://django;
        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;
    }

    location / {
        proxy_pass http://django;
        # ... headers ...
    }
}

Django REST Framework (API)

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # CORS headers
    add_header Access-Control-Allow-Origin * always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;

    # Handle preflight
    location / {
        if ($request_method = OPTIONS) {
            return 204;
        }

        proxy_pass http://django;
        proxy_http_version 1.1;
        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;
    }
}

Gunicorn Systemd Service

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

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/django
ExecStart=/var/www/django/venv/bin/gunicorn \
    --workers 3 \
    --bind unix:/run/gunicorn/socket \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log \
    myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Django Channels (WebSocket)

upstream channels {
    server 127.0.0.1:8001;
}

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

    # Regular HTTP
    location / {
        proxy_pass http://django;
        # ... standard headers ...
    }

    # WebSocket
    location /ws/ {
        proxy_pass http://channels;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}
intermediate Recipes Updated 2025-01-15
  • nginx
  • django
  • python
  • gunicorn
  • uwsgi