
How to Host a Django Project Using Gunicorn and Nginx
Deploying Django applications in a production environment requires setting up a robust server architecture. One of the most common and powerful ways to achieve this is by using Gunicorn (Green Unicorn) as the application server and Nginx as the reverse proxy server. Gunicorn serves the Django application, while Nginx handles static files, SSL termination, and acts as a reverse proxy, forwarding requests to Gunicorn.
In this guide, we will go over the steps to host a Django project using Gunicorn and Nginx, including troubleshooting common errors. Let's get started!
Prerequisites
-
Ubuntu 20.04 or later.
-
A Django project set up and ready to deploy.
-
A domain name (for example,
yourdomain.com
) or an IP address for your server. -
SSH access to your server.
-
Gunicorn, Nginx, and other necessary tools installed.
If you have a running Django project and the necessary tools installed, we can start from here.
Step 1: Install Gunicorn
Gunicorn is a Python WSGI HTTP server for UNIX that serves Django applications. To install Gunicorn within your Django project’s virtual environment, use the following command:
(.venv) pip install gunicorn
Step 2: Create Gunicorn Service File
In order to run Gunicorn as a service, we need to create a systemd service. This allows Gunicorn to automatically start on system boot and be easily managed.
Create the Gunicorn service file by running the following command:
sudo nano /etc/systemd/system/gunicorn.service
Here’s the content you should add to the file:
[Unit]
Description=Gunicorn daemon for Django project
After=network.target
[Service]
User=samadmin
Group=www-data
WorkingDirectory=/home/samadmin/blogforge/blogproject
ExecStart=/home/samadmin/blogforge/blogproject/.venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind 127.0.0.1:8001 \
blogproject.wsgi:application
[Install]
WantedBy=multi-user.target
Key Details:
-
User=samadmin
: Gunicorn will run as the usersamadmin
(adjust to your system’s user). -
WorkingDirectory
: Points to the Django project directory. -
ExecStart
: This is where we call Gunicorn and pass it the WSGI file to serve the app.
Save and exit by pressing CTRL+X
, then Y
, and Enter
.
Step 3: Start and Enable Gunicorn Service
Now, we need to reload the systemd configuration, start the Gunicorn service, and enable it to start at boot:
sudo systemctl daemon-reload
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
Check the status of the Gunicorn service to ensure it’s running:
sudo systemctl status gunicorn
If there’s any issue, check the error logs for Gunicorn by running:
sudo journalctl -u gunicorn
Step 4: Install Nginx
Next, we need to install Nginx, which will serve as a reverse proxy for the Django application:
sudo apt update
sudo apt install nginx
Step 5: Configure Nginx
Create a new configuration file for Nginx to proxy requests to Gunicorn. This will involve setting up a new file in the sites-available
directory.
sudo nano /etc/nginx/sites-available/cleanblog
Here is the basic configuration for Nginx:
# Redirect HTTP traffic (port 80) to HTTPS without www
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://yourdomain.com$request_uri;
}
# Redirect HTTPS www → non-www
server {
listen 443 ssl;
server_name www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
return 301 https://yourdomain.com$request_uri;
}
# Main server block: non-www HTTPS site
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Serve media files (uploaded files like images, docs, etc.)
location /media/ {
alias /home/samadmin/blogforge/blogproject/media/;
access_log off;
expires 30d;
}
# Serve static files (CSS, JS, etc.)
location /static/ {
alias /home/samadmin/blogforge/blogproject/static/;
}
# Main application (Django project)
location / {
proxy_pass http://127.0.0.1:8001; # Ensure this points to your Gunicorn app running on port 8001
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;
}
}
-
The first server block redirects HTTP traffic on port 80 to HTTPS.
-
The second server block handles the redirect from
www
to non-www
. -
The third server block handles all traffic for
yourdomain.com
, serving both static files (CSS, JS, etc.) and dynamic requests to the Django application via Gunicorn.
Once you’ve created the file, create a symbolic link in the sites-enabled
directory:
sudo ln -s /etc/nginx/sites-available/cleanblog /etc/nginx/sites-enabled/
Step 6: Check and Restart Nginx
Before restarting Nginx, test the configuration to ensure there are no syntax errors:
sudo nginx -t
If the test is successful, restart Nginx:
sudo systemctl restart nginx
Step 7: Handle Common Errors
1. 502 Bad Gateway Error
This is a common error that typically occurs when Nginx cannot communicate with Gunicorn. Here are some things to check:
-
Ensure that Gunicorn is running and listening on the correct address and port.
-
Check if Gunicorn is bound to
127.0.0.1:8001
(as specified in the Nginx configuration). -
Make sure there are no permission issues preventing Gunicorn from accessing your Django project files.
2. Permission Errors: Read-Only Database
If you encounter an error such as:
OperationalError: attempt to write a readonly database
Ensure that your SQLite database file has the correct file permissions:
sudo chown www-data:www-data /path/to/db.sqlite3
sudo chmod 664 /path/to/db.sqlite3
3. Gunicorn Crashes or Doesn't Start
If Gunicorn fails to start, you can check the logs using:
sudo journalctl -u gunicorn
Check for permission issues with the files or configurations. Make sure your user (in this case, samadmin
) has the necessary permissions.
Conclusion
By following this guide, you should be able to successfully deploy your Django project using Gunicorn and Nginx. The configuration provided ensures a production-ready environment where Nginx handles static files, SSL termination, and serves as a reverse proxy to Gunicorn, which runs your Django application.
Common errors like the "502 Bad Gateway" or database write issues can be fixed by checking service statuses, file permissions, and logs. With Gunicorn and Nginx set up, you can now enjoy a fast and secure Django deployment.
2 Comments
Vicky
Just deployed from https://blogforge.pythonanywhere.com/ to https://imvickykumar999.online/ using gunicorn and nginx, domain purchased from namecheap.
Vicky Kumar
Also deployed on Dark Web with custom vanity URL starts with my name at http://vickyme6ywivszfs6c2oekjxgatrl7xykwsc355llydysuj7eexokfyd.onion