Nginx configuration for Django: Production-ready setup

By Anurag Shankar Maurya • Published: 2026-01-19 • Category: DevOps & Deployment • 5 min read
Nginx configuration for Django: Production-ready setup

Configuring Nginx for Django Applications: Architecture and Optimization

In a production Django deployment, Nginx is a widely adopted web server that typically acts as a reverse proxy, load balancer, and static file server. Because Python application servers (like Gunicorn or Uvicorn) are optimized to run application code rather than manage raw network traffic, placing Nginx in front of them is standard practice. Unlike traditional process-per-connection web servers, Nginx uses an asynchronous, event-driven architecture. This allows it to manage thousands of concurrent connections with low memory consumption, serving as a buffer that protects the underlying Python workers from direct exposure to the public internet. ---

Production Server Block Configuration

Below is a standard production server configuration block for Nginx routing traffic to a Gunicorn WSGI or Uvicorn ASGI server. ``nginx

Define the upstream application server

upstream django_app { server 127.0.0.1:8000; # Points to Gunicorn/Uvicorn }

Redirect HTTP to HTTPS

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

HTTPS Server Block

server { listen 443 ssl http2; server_name example.com www.example.com; # SSL Certificates ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Optimized SSL Configurations ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; # Security Headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "1; mode=block" always; # Gzip Compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1000; gzip_comp_level 5; # Static Files (Served directly by Nginx) location /static/ { alias /var/www/django_project/static/; expires 30d; access_log off; } # Media Files (User uploads, served directly by Nginx) location /media/ { alias /var/www/django_project/media/; expires 30d; access_log off; } # Proxy request to Upstream Django App location / { proxy_pass http://django_app; # Pass essential headers to 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; # Buffer configurations proxy_connect_timeout 90s; proxy_read_timeout 90s; proxy_buffers 8 16k; proxy_buffer_size 32k; } }
` ---

Configuration Breakdown and Operational Logic

1. Static and Media File Handling

Routing requests for static images, CSS, and JavaScript through a Python runtime is highly inefficient. Nginx utilizes system-level optimizations like
sendfile to transfer files directly from the disk to the network interface. By configuring the /static/ and /media/ location blocks, Nginx intercepts these paths and serves files directly, completely bypassing the Django application server.

2. Reverse Proxy and Headers Injection

Because Nginx sits between the client and the application server, Gunicorn sees all requests as originating from local host interfaces (e.g.,
127.0.0.1).

3. SSL/TLS and Security Headers

Configuring SSL termination at the Nginx layer offloads cryptographic computations from the Python application layer.