Django with Nginx
Introduction
When you're ready to deploy your Django application to a production environment, you'll need a robust web server to handle client requests efficiently. While Django comes with a built-in development server, it's not suitable for production use due to security and performance limitations. This is where Nginx comes in.
Nginx (pronounced "engine-x") is a powerful, open-source web server that can serve as a reverse proxy, load balancer, and HTTP cache for your Django applications. In this tutorial, we'll explore how to configure Nginx to work with Django and understand why this combination is the preferred setup for production environments.
Why Use Nginx with Django?
Before diving into configuration, let's understand why using Nginx with Django is beneficial:
- Performance: Nginx is designed to handle many concurrent connections efficiently
- Static Files: Nginx excels at serving static files (images, CSS, JavaScript)
- Security: Adds an additional layer of protection for your application
- SSL Termination: Handles HTTPS connections before passing requests to Django
- Load Balancing: Can distribute traffic across multiple Django instances
Architecture Overview
In a Django-Nginx setup, the typical architecture looks like this:
Client Request → Nginx → WSGI Server (Gunicorn/uWSGI) → Django Application
Nginx serves as the front-facing web server that handles all incoming HTTP(S) requests. It then forwards appropriate requests to a WSGI server like Gunicorn, which runs your Django application.
Prerequisites
Before configuring Nginx with Django, ensure you have:
- A Django project ready for deployment
- A server with Ubuntu/Debian (though instructions can be adapted for other systems)
- SSH access to your server
- Basic understanding of command line operations
- Domain name pointed to your server (optional but recommended)
Step 1: Install Nginx
First, let's install Nginx on your server:
# Update package lists
sudo apt update
# Install Nginx
sudo apt install nginx
# Start Nginx service
sudo systemctl start nginx
# Enable Nginx to start at boot
sudo systemctl enable nginx
To check if Nginx is running properly:
sudo systemctl status nginx
You should see output indicating that Nginx is active and running.
Step 2: Set Up a Django Project with Gunicorn
Before configuring Nginx, we need to set up our Django project with a WSGI server like Gunicorn. If you haven't installed Gunicorn yet:
pip install gunicorn
Add Gunicorn to your project's requirements:
echo "gunicorn" >> requirements.txt
Test if Gunicorn can serve your Django application:
cd /path/to/your/django/project
gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application
If everything is working correctly, you should be able to access your Django application at http://your-server-ip:8000.
Step 3: Configure Nginx for Django
Now, let's configure Nginx to work with our Django application. Create a new Nginx server block configuration:
sudo nano /etc/nginx/sites-available/myproject
Add the following configuration (replace placeholders with your specific details):
server {
listen 80;
server_name example.com www.example.com; # Replace with your domain or server IP
location = /favicon.ico {
access_log off;
log_not_found off;
}
location /static/ {
root /path/to/your/django/project; # Path to your Django project's static files
}
location /media/ {
root /path/to/your/django/project; # Path to your Django project's media files
}
location / {
include proxy_params;
proxy_pass http://127.0.0.1:8000; # Forward to Gunicorn
}
}
This configuration:
- Listens for HTTP requests on port 80
- Serves static and media files directly (more efficient than Django)
- Forwards all other requests to Gunicorn running on port 8000
Next, create a symbolic link to enable this configuration:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Test the Nginx configuration for syntax errors:
sudo nginx -t
If the test is successful, reload Nginx to apply the changes:
sudo systemctl reload nginx
Step 4: Setting Up Gunicorn as a System Service
To ensure Gunicorn runs automatically and restarts if it crashes, let's create a systemd service file:
sudo nano /etc/systemd/system/gunicorn.service
Add the following content:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=your_user # Replace with your system username
Group=www-data
WorkingDirectory=/path/to/your/django/project
ExecStart=/path/to/your/virtualenv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind 127.0.0.1:8000 \
myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Start and enable the Gunicorn service:
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
Check the status to ensure it's running correctly:
sudo systemctl status gunicorn
Step 5: Configuring SSL with Nginx (Optional but Recommended)
For a production site, you should enable HTTPS. Let's install Certbot to get free SSL certificates from Let's Encrypt:
sudo apt install certbot python3-certbot-nginx
Obtain and install SSL certificates:
sudo certbot --nginx -d example.com -d www.example.com
Follow the prompts to complete the certificate setup. Certbot will automatically modify your Nginx configuration to use the SSL certificates.
Step 6: Optimizing Nginx for Django
Here are some additional optimizations you can add to your Nginx configuration:
server {
# ... existing configuration ...
# Add gzip compression
gzip on;
gzip_vary on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "MSIE [1-6]\.";
# Cache static files
location /static/ {
root /path/to/your/django/project;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
# Increase client body size if you need to handle large file uploads
client_max_body_size 10M;
}
After making these changes, reload Nginx:
sudo systemctl reload nginx
Real-world Example: Complete Configuration
Here's a comprehensive example of a production-ready Nginx configuration for a Django application:
server {
listen 80;
server_name mydjangoapp.com www.mydjangoapp.com;
return 301 https://$host$request_uri; # Redirect all HTTP to HTTPS
}
server {
listen 443 ssl;
server_name mydjangoapp.com www.mydjangoapp.com;
ssl_certificate /etc/letsencrypt/live/mydjangoapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydjangoapp.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_session_cache shared:SSL:10m;
access_log /var/log/nginx/mydjangoapp.access.log;
error_log /var/log/nginx/mydjangoapp.error.log;
# Static files
location /static/ {
alias /var/www/mydjangoapp/static/;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
# Media files
location /media/ {
alias /var/www/mydjangoapp/media/;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
# Forward to Django/Gunicorn
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options SAMEORIGIN;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Deny access to .htaccess files
location ~ /\.ht {
deny all;
}
}
Troubleshooting Common Issues
1. 502 Bad Gateway
If you see a "502 Bad Gateway" error, it usually means Nginx can't connect to Gunicorn:
- Check if Gunicorn is running:
sudo systemctl status gunicorn
- Verify the socket or port in both Nginx configuration and Gunicorn service
- Check Gunicorn error logs:
journalctl -u gunicorn
- Ensure permissions are correct in your project directories
2. Static Files Not Loading
If static files aren't loading properly:
- Verify the path in your Nginx configuration
- Ensure you've run
python manage.py collectstatic
- Check directory permissions
- Verify the URL patterns in your Django settings (
STATIC_URL
,STATIC_ROOT
)
3. Permission Denied Errors
If you see permission errors in Nginx logs:
sudo chown -R www-data:www-data /path/to/your/django/project/static
sudo chown -R www-data:www-data /path/to/your/django/project/media
Summary
In this tutorial, we've covered:
- Why Nginx is essential for a production Django setup
- How to install and configure Nginx
- Setting up Gunicorn as a system service
- Configuring Nginx to work with Django
- Adding SSL for secure connections
- Optimizing Nginx for better performance
- Troubleshooting common issues
By following these steps, you've created a robust, production-ready Django deployment with Nginx handling client requests efficiently. This setup provides better security, performance, and reliability than using Django's development server alone.
Additional Resources
- Official Nginx Documentation
- Django Deployment Checklist
- Gunicorn Configuration
- Let's Encrypt Documentation
Exercises
- Configure Nginx to serve multiple Django applications on the same server using different domain names.
- Set up rate limiting in your Nginx configuration to prevent abuse.
- Configure Nginx to serve a maintenance page when your Django application is down for maintenance.
- Implement HTTP/2 in your Nginx configuration for improved performance.
- Set up Nginx to cache responses from your Django application to reduce load on your application server.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)