Deploying Django to Production: Nginx and Gunicorn
AYou have built your Django app, pushed it to a Virtual Private Server (like AWS EC2 or DigitalOcean Droplet), and now you want the world to see it.
Warning: Do not run python manage.py runserver in production. It is single-threaded and insecure.
To serve Django professionally, we need two components:
1. Gunicorn (Green Unicorn): A WSGI HTTP Server that translates web requests into Python function calls.
2. Nginx: A high-performance Reverse Proxy that handles incoming traffic, static files, and SSL, then passes the request to Gunicorn.
Step 1: Gunicorn
First, install Gunicorn in your virtual environment:
pip install gunicorn
You can test it simply by running:
gunicorn --bind 0.0.0.0:8000 myproject.wsgi
However, if you close your SSH terminal, the site goes down. We need to keep it running in the background using Systemd.
Create a service file: /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/myproject
ExecStart=/home/ubuntu/myproject/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/home/ubuntu/myproject/myproject.sock \
myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Start and enable the service:
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
This creates a Unix Socket file. This is faster than using a network port (8000) because Nginx and Gunicorn communicate via a file on the disk.
Step 2: Nginx
Install Nginx:
sudo apt update
sudo apt install nginx
Create a configuration file for your site: /etc/nginx/sites-available/myproject
server {
listen 80;
server_name example.com www.example.com 203.0.113.1;
# Ignore favicon errors
location = /favicon.ico { access_log off; log_not_found off; }
# Serve Static Files Directly (Nginx is super fast at this)
location /static/ {
root /home/ubuntu/myproject;
}
# Serve Media Files
location /media/ {
root /home/ubuntu/myproject;
}
# Pass everything else to Gunicorn
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/myproject/myproject.sock;
}
}
Enable the site by creating a symbolic link:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
Step 3: Static Files
Django doesn't serve static files (CSS/Images) in production. You must run:
python manage.py collectstatic
This gathers all files into the folder Nginx is looking at.
Conclusion
This architecture is the gold standard for Python deployment. Nginx acts as the bouncer/security guard, handling SSL and buffering slow clients, while Gunicorn focuses purely on executing your Python code.