How to install Django with NGINX, Gunicorn, and PostgreSQL on Ubuntu?

In this article we’ll learn how to install Django with NGINX, Gunicorn, and PostgreSQL on Ubuntu.

Django comes with a lightweight development server that is not suitable for production as it is less secure, low-performance, and not scalable.

It’s intended to be only used for development purposes so you can rapidly focus on your application development without having to worry about the production server. Similarly, if you are deploying an application in production, it is recommended to use PostgreSQL (or some other popular database server).

Why use NGINX and Gunicorn with Django?

We can conclude from the above text that we cannot use Django’s development server in production as it lacks security and performance features, which is why NGINX and Gunicorn come into play.

  • Gunicorn is a WSGI (Web Server Gateway Interface) HTTP Server used with web applications and frameworks written in the Python programming language.
  • WSGI descendent of CGI is an interface that sits in between the web server and Django to allow them to communicate with each other.
  • NGINX is used to provide additional features like load balancing, caching, and other features.

Steps for installing Django with NGINX, Gunicorn, & PostgreSQL

Follow the steps below to install and configure Django with NGINX, Gunicorn, and PostgreSQL.

Step 1: Installing required packages with the apt package manager

Before we install all the packages, update your apt package manager index by executing the following apt command with sudo:

sudo apt update

To install all the required packages, execute the following command:

sudo apt install nginx python3-dev python3-pip python3-venv postgresql postgresql-contrib libpq-dev

Now that we have all the required packages installed, we can proceed to further steps.

Step 2: Create a user and database in PostgreSQL

To enter into PostgreSQL interactive shell execute:

sudo -u postgres psql

Now to create a user and database enter:

CREATE USER djangouser WITH PASSWORD 'mypassword'; 
CREATE DATABASE djangoproject;
Creating PostgreSQL User And Database
Creating PostgreSQL user and database

Django expects the parameters listed here for its database connections, enter the following inside PostgreSQL interactive shell to set these parameters.

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

Django would work fine without these parameters but, it will require making additional queries, so Django recommends doing it in hand before. Now grant all the privileges of the djangoproject database to the djangouser by entering:

GRANT ALL PRIVILEGES ON DATABASE djangoproject TO djangouser;

and quit the interactive session by entering \q in the PostgreSQL interactive shell.

Step 3: Creating a Python virtual environment

We will create our virtual environment inside a new directory. To create a new directory execute the mkdir command:

mkdir ~/newProject

and, change directory by executing the cd command:

cd ~/newProject

Now we create a new virtual environment inside our directory newProject called django_venv by executing:

python3 -m venv django_venv

To activate our newly created virtual environment execute:

source django_venv/bin/activate

And your shell prompt should change as shown in the image below.

Activating Virtual Environment
Activating Virtual Environment

Step 3: Installing required packages with pip and configuring Django

To install Django framework, Gunicorn for WSGI and psycopg2 is required for PostgreSQL execute the following pip command:

pip install django gunicorn psycopg2

Now let’s create a sample project called djangoproject with Django.

To create a new project execute:

django-admin startproject djangoproject .

The period at the end of the command will create the project in the same directory.

You can find the Django settings at ~/newProject/djangoproject/settings.py , you can edit them using your favorite text editor.

nano djangoproject/settings.py

And add your server domain or IP under ALLOWED_HOSTS

. . .
ALLOWED_HOSTS = ['your_server_domain_or_ip', 'your_server_domain_or_ip', . . .]
. . .
Add Allowed Hosts
Add allowed hosts

The following changes are needed to be made in your settings.py of your project to use the PostgreSQL database:

. . .
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': '<db_name>',
        'USER': '<db_user>',
        'PASSWORD': '<db_password>',
        'HOST': 'localhost',
        'PORT': '',
    }
}
. . .
Make Changes In Settings.py For Django To Make Use PostgreSQL
Make changes in settings.py for Django to make use of PostgreSQL

Next, add the import os at the beginning of settings.py and then define the STATIC_ROOT path in settings.py, this is where the static files of your website will be generated and stored. It is necessary for NGINX to function.

import os
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
. . .
Add STATIC ROOT Path In Settings.py
Add STATIC_ROOT path in settings.py

Save the file. Now to migrate the database, execute:

python manage.py migrate
Migrating Database
Migrating Database

You are required to create an administrative user to use the Django web admin interface, execute the following command to create:

python manage.py createsuperuser

You will be required to answer several prompts (Username, Email, Password).

Create Superuser
Create Superuser

Now allow port 8000 in the firewall for the Django Development Server to be accessible, by executing:

sudo ufw allow 8000

Finally, we can test our new project with the help of the Django Development Server by executing:

python manage.py runserver server_ip:8000
Django Development Server Running
Django Development Server Running

Now you can visit your browser at http://server_ip:8000/ to test out your newly created Django project.

Django Project Homepage
Django project homepage

You can also visit the admin page at http://server_ip:8000/admin/ and enter credentials of the admin user we created above.

Django Admin Interface
Django Admin Interface

To test out Gunicorn’s ability to serve pages with your Django application, execute:

gunicorn --bind 0.0.0.0:8000 djangoproject.wsgi
Testing Out Gunicorns Ability To Serve
Testing out Gunicorn’s ability to serve webpages

Now go back to your browser and go to http://server_ip:8000/ to test it out. You should be able to see the same page.

Press CTRL+C to stop the Gunicorn server and return to the terminal.

Step 4: Create a systemd service file for Gunicorn

Using your favorite text editor, create gunicorn.service file at /etc/systemd/system/ by executing:

sudo nano /etc/systemd/system/gunicorn.service

Then make the following changes in the gunicorn.service file, and make sure to replace your details below:

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=myusername
Group=www-data
WorkingDirectory=/home/myusername/newProject
ExecStart=/home/myusername/newProject/django_venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/myusername/newProject/djangoproject.sock djangoproject.wsgi:application

[Install]
WantedBy=multi-user.target

Then execute the following commands to start and enable Gunicorn service:

sudo systemctl start gunicorn
sudo systemctl enable gunicorn

You can found out the status of Gunicorn service by executing:

sudo systemctl status gunicorn
Gunicorn Service Status
Gunicorn Service Status

Step 5: Configure NGINX reverse proxy

We have Gunicorn set up, now we need to set up NGINX reverse proxy to Gunicorn.

Create a new file by executing:

sudo nano /etc/nginx/sites-available/gunicorn

And then add the following and replace them with your details:

server {
    listen 80;
    server_name your_server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/myusername/newProject;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/myusername/newProject/djangoproject.sock;
    }
}
NGINX Reverse Proxy Configuration
NGINX Reverse Proxy Configuration

Save the file.

Then create a symlink to enable NGINX virtual host, by executing:

sudo ln -s /etc/nginx/sites-available/gunicorn /etc/nginx/sites-enabled/

To test your NGINX configuration for errors, execute:

sudo nginx -t
NGINX Configuration Test Successful
NGINX configuration test successful

Finally restart the NGINX service by executing:

sudo systemctl restart nginx

You can now close port 8000 and allow NGINX ports, by executing:

sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'

Now visit http://your_server_domain_or_ip/ to test out your Django set up with NGINX, Gunicorn, & PostgreSQL.

Django Webpage
Django Webpage

Congratulations! We have successfully set up Django with NGINX, Gunicorn, and PostgreSQL.

Conclusion

Django is a great Python web framework for developing web applications, it comes with a handy development server that shall never be used in a production environment. In production environments, a setup similar to what we have shown above must be used. In this article, we have set up a Django application with PostgreSQL for the database, Gunicorn for WSGI, and NGINX as a reverse proxy. If you’re wondering between PostgreSQL vs SQLite, the answer generally lies in your use-case and how portable and simple you want your database system to be.

We hope you found this tutorial helpful. Thank you for reading! 😀