Overview

In this guide, we’ll walk through the complete process of deploying a Django application on a VPS using Gunicorn as the application server and Nginx as the reverse proxy. You’ll learn how to configure your server, set up Gunicorn to serve your Django project, and use Nginx to handle client requests efficiently. By the end, you’ll have a production-ready setup that is secure, scalable, and optimized for performance.

Prequisities

  • Have your project pushed to GitHub/GitLab or any other version control platform. I will include GitHub for this post; the configuration is relevant for all of the platforms.

1. Install required packages

We will require Python to be installed on the server, along with pip to manage Python packages. The venv Python package is a virtual environment management tool that allows us to configure an isolated environment for our project.

sudo apt update
sudo apt install python3 python3-pip python3-venv nginx git

2. Clone Your Django Project using SSH

  • Generate SSH Key: This creates two files: ~/.ssh/github (private key) and ~/.ssh/github.pub (public key)

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/github
#It wil ask for passphrase: Enter a secure passphrase (optional but recommended)
  • Start the SSH Agent and Add the Key.

# Start the ssh-agent
eval "$(ssh-agent -s)"

# Add your custom-named SSH key to the agent
ssh-add ~/.ssh/github
  • Copy Your Public Key

cat ~/.ssh/github.pub
  • Add the Public key to GitHub: Go to the GitHub settings, find SSH and GPG keys in the sidebar, add a new SSH Key, and paste the public key. Ensure you paste without hitting Enter and save it.

  • Configure SSH for GitHub in VPS.

# Create/edit SSH config
nano ~/.ssh/config

Add this configuration to it.

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github
    IdentitiesOnly yes

Set Permissions to the SSH files

chmod 600 ~/.ssh/github
chmod 644 ~/.ssh/github.pub
chmod 600 ~/.ssh/config
  • Clone the project with GitHub SSH.

cd /var/www/
sudo git clone [email protected]:yourusername/yourproject.git

# Give ownership of the directory to the current user.
sudo chown -R $USER:$USER yourproject

3. Create a Virtual Environment & Install Dependencies

cd yourproject
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

4. Configure Django for Production

# In settings.py
DEBUG = False
ALLOWED_HOSTS = ['your_domain.com', 'www.your_domain.com']
# Migrate the migration files
python manage.py migrate
# Configure to serve the Static and Media files
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/yourproject/staticfiles'

MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/yourpoject/media'
# Collect static
python manage.py collectstatic

5. Install & Configure Gunicorn

pip install gunicorn
gunicorn --bind 0.0.0.0:8000 yourproject.wsgi

If it’s served successfully, check it on the browser ip:8000, then press Ctrl + C If it’s working properly.

6. Create Gunicorn Systemd Service

sudo nano /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon for a Django project
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/yourproject
ExecStart=/usr/bin/gunicorn --access-logfile - --workers 3 --bind unix:/var/www/yourproject/gunicorn.sock yourproject.wsgi:application

[Install]
WantedBy=multi-user.target

Enable and start service:

sudo systemctl enable gunicorn
sudo systemctl start gunicorn
sudo systemctl daemon-reload

7. Nginx Configuration

File: /etc/nginx/sites-available/your_domain.com

server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
   
    # Static files
    location /static/ {
        alias /var/www/youproject/collect_static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

# Media files
location /media/ {
    alias /var/www/yourproject/media/;
}
   
    location / {
        include proxy_params;
        proxy_pass http://unix:/var/www/yourproject/gunicorn.sock;
    }

8. Fix Socket Permissions

When running Gunicorn with Nginx, the correct user must have ownership and access to the project directory and the socket file it creates. By default, Nginx runs under the www-data user on Ubuntu/Debian systems.

sudo chown -R www-data:www-data /var/www/yourproject/
sudo chmod 770 /var/www/yourproject/

9. Enable the site and reload Nginx

sudo ln -s /etc/nginx/sites-available/your_domain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

10. Set Up SSL (HTTPS)

To enable HTTPS, you need to obtain an SSL certificate, which can be issued for free via Let’s Encrypt.

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d your_domain.com -d www.your_domain.com

Auto-renew certificate

sudo systemctl enable certbot.timer

11. Access the Site

Enter the domain your_domain.com in the browser and check if everything works perfectly.

For any issues that occur, check the error log of Nginx

sudo tail -n 30 /var/log/nginx/error.log

If static files are not working, ensure the permission that Nginx has permission to access the files.

sudo chown -R www-data:www-data /var/www/yourproject/staticfiles
sudo chmod -R 755 /var/www/yourproject/staticfiles

Happy Coding.