Deploying a Django application in a production environment requires more than just running the development server. For a scalable, secure, and reliable setup, Gunicorn (a WSGI HTTP server) and Nginx (a high-performance reverse proxy server) are the preferred choices. In this guide, we’ll walk you through every step of hosting your Django project using Gunicorn and Nginx on a Linux server.

Why Use Gunicorn and Nginx?

Before diving into the setup, here’s why this combo is popular:

  • Gunicorn efficiently runs your Django app by handling multiple requests concurrently.
  • Nginx serves static files, manages SSL, and forwards requests to Gunicorn.
  • Combined, they provide improved performance, security, and scalability.

Prerequisites

Before you begin, make sure you have:

  • A Linux-based server (Ubuntu 20.04 or later recommended)
  • Python 3.x installed
  • A Django project ready
  • Root or sudo access to the server
  • A domain name (optional, but recommended)

Step 1: Install Required Packages

SSH into your server and update it:

sudo apt update && sudo apt 

Step 2 – Install Nginx and required tools

Install Nginx using the command below:

sudo apt install python3-pip python3-dev nginx

Step 3 – Allow Nginx through the firewall

Allow Nginx through the firewall using the command below:

sudo ufw app list
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status  # Verify Nginx HTTP/HTTPS access

Step 4 – Install & Configure PostgreSQL

Let’s install PostgreSQL using the command below:

While you are logged into the server, run following commands to install, start, enable and see the status of postgresql database:

sudo apt-get install postgresql postgresql-contrib
sudo systemctl start postgresql.service
sudo systemctl enable postgresql.service
sudo systemctl status postgresql.service

Step 5 -Postgres Database & User Setup

sudo -u postgres psql

You should now be logged into the pg shell

Create a database

CREATE DATABASE dydevops_db;

Create user

CREATE USER dbmwshop WITH PASSWORD 'MaWbc1$23!';

Set default encoding, tansaction isolation scheme (Recommended from Django)
 

ALTER ROLE dbmwshop SET client_encoding TO 'utf8';
ALTER ROLE dbmwshop SET default_transaction_isolation TO 'read committed';
ALTER ROLE dbmwshop SET timezone TO 'UTC';

Give User access to database

GRANT ALL PRIVILEGES ON DATABASE dydevops_db TO dbmwshop;

Quit out of Postgres

\q

Step 6 – Creating a python virtual environment

sudo pip3 install virtualen

This will install a virtual environment package in python. Let’s create a project directory to host our Django application and create a virtual environment inside that directory.

cd /home/dydeops/
mkdir myproject
cd myproject
virtualenv env

A virtual environment named env will be created. Let’s activate this virtual environment:

source env/bin/activate

Step 7 – Installing Django and gunicorn

pip install django gunicorn

This installs Django and gunicorn in our virtual environment


Step 8 – Possible Deployment Issues

 

To avoid deployment errors, we will take following actions:

Add allowed host, release media folder, run collectstatic and create requirements.txt from the local project.
 

ALLOWED_HOSTS = ['SERVER_IP_ADDRESS', 'localhost', '127.0.0.1']
Remove 'media' from .gitignore file
python manage.py collectstatic
pip freeze > requirements.txt
  • Replace psycopg2 package with psycopg2-binary
  • Install backports.zoneinfo only if the server python version is less than 3.9
  • backports.zoneinfo==0.2.1;python_version<"3.9"
  • Add gunicorn to requirements.txt

Step 9 – Backup data from local machine and restore in to live database

python manage.py dumpdata > backup.json

Now check the remote directory, our project is pushed to the server. That’s all, we have set up Filezilla to upload the code from local machine to ftp server.

Open Django Project settings.py and check your project settings 

cd /home/dydevops/myproject

cd myproject
sudo nano mwcshop/settings.py

In the myproject folder, activate virtual environment 

source env/bin/activate

Install the packages from requirements.txt file

pip install -r requirements.txt

Run makemigrations and migrate commands

python manage.py migrate

Allow port 8000

sudo ufw allow 8000

Check status of ufw

sudo ufw status

Run the server

python manage.py runserver 0.0.0.0:8000

Remote server

python manage.py shell
from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()
python manage.py loaddata backup.json

Configuring Gunicorn


Install Gunicorn on our server
if you are not install Gunicorn then install ..

sudo apt install gunicorn

Other wise run tell gunicorn to bind to our Django application and start running

gunicorn --bind 0.0.0.0:8000 mwcshop.wsgi

Test the link and make sure the site is working


exit


Go to this location and paste below code:

sudo nano /etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target

Location

sudo nano /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
 
[Service]
User=dydevops
Group=www-data
WorkingDirectory=/home/dydevops/myproject
ExecStart=/home/dydevops/myproject/env/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mwcshop.wsgi:application
 
[Install]
WantedBy=multi-user.target

 

Restart and enable Gunicorn socket

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

 Configuring Nginx as a reverse proxy

Location:

sudo nano /etc/nginx/sites-available/mwcshop
server {
    listen 80;
    server_name dydevops.com www.dydevops.com;
 
    location ~ ^/.well-known {
        root /home/dydevops/myproject;
        allow all;
    }
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/dydevops/myproject;
    }
    location /media/ {
        root /home/dydevops/myproject;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
sudo ln -s /etc/nginx/sites-available/mwcshop /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Open port 80 and close 8000

sudo ufw allow 80
sudo ufw allow 'Nginx Full'
sudo ufw allow 586
sudo ufw deny 8000


 Go to sites-enabled directory and delete the default site

cd /etc/nginx/sites-enabled/
ls
sudo rm default

 Fix Static Files on Server

cd /etc/nginx/
ls
sudo nano nginx.conf
sudo systemctl restart nginx

Set Your domain name server

Open Django Project settings.py and check your project settings 

cd myproject
sudo nano mwcshop/settings.py
ALLOWED_HOSTS = ['SERVER_IP_ADDRESS', 'www.dydevops.com', 'dydevops.com']
sudo service nginx restart
sudo service gunicorn restart

Install SSL

sudo apt install certbot python3-certbot-nginx

Verify certbot installation by running which certbot

sudo certbot --nginx -d www.dydevops.com