How to Host a Django Project Using Gunicorn and Nginx

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 user samadmin (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

Leave a Reply

Your email address will not be published. Required fields are marked *

Loading...