Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 20.04

·

6 min read

feature_image.jpeg

Introduction

​ Django is an open-source Python framework that can be used for deploying Python applications. It comes with a development server to test your Python code in the local system. If you want to deploy a Python application on the production environment then you will need a powerful and more secure web server. In this case, you can use Gunicorn as a WSGI HTTP server and Nginx as a proxy server to serve your application securely with robust performance. ​

Prerequisites

  • A server running Ubuntu 20.04.
  • A valid domain name pointed with your server IP.
  • A root password is configured on your server.

Install Required Packages

​ First, you will need to install Nginx and other Python dependencies on your server. You can install all the packages with the following command:

apt-get install python3-pip python3-dev libpq-dev curl nginx -y

Once all the packages are installed, start the Nginx service and enable it to start at system reboot:

systemctl start nginx

systemctl enable nginx

Install and Configure PostgreSQL

​ Next, you will need to install the PostgreSQL server on your server. You can install it with the following command:

apt-get install postgresql postgresql-contrib -y

​ After the installation, log in to PostgreSQL shell with the following command: ​

    su - postgres
    psql

​ Next, create a database and user for Django with the following command: ​

    CREATE DATABASE 
        djangodb;
    CREATE USER 
        djangouser 
        WITH PASSWORD 'password';

​ Next, grant some required roles with the following command: ​

    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';
    GRANT ALL PRIVILEGES 
        ON DATABASE djangodb 
        TO djangouser;
​

Next, exit from the PostgreSQL shell using the following command: ​

\qexit

Create a Python Virtual Environment

​ Next, you will need to create a Python virtual environment for the Django project. ​ First, upgrade the PIP package to the latest version: ​

pip3 install --upgrade pip

Next, install the virtualenv package using the following command:

pip3 install virtualenv

Next, create a directory for the Django project using the command below:

mkdir ~/django_project
​

Next, change the directory to django_project and create a Django virtual environment: ​

 cd ~/django_project
 virtualenv djangoenv

​ Next, activate the Django virtual environment:

source djangoenv/bin/activate

​ Next, install the Django, Gunicorn, and other packages with the following command:

pip install django gunicorn psycopg2-binary

Install and Configure Django

​ Next, run the following command to create a Django project:

django-admin.py startproject django_project ~/django_project

Next, edit the settings.py and define your database settings:

nano ~/django_project/django_project/settings.py

​ Find and change the following lines:

ALLOWED_HOSTS = ['django.example.com', 'localhost']
DATABASES = {  
     'default': {     
     'ENGINE': 'django.db.backends.postgresql_psycopg2',       
     'NAME': 'djangodb',       
     'USER': 'djangouser',        
      'PASSWORD': 'password',        
     'HOST': 'localhost',       
     'PORT': '',    
   }
}
STATIC_URL = '/static/'
import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Save and close the file then migrate the initial database schema to the PostgreSQL database:

./manage.py makemigrations
./manage.py migrate
​

Next, create an admin user with the following command:

./manage.py createsuperuser
​

Set your admin username and password as shown below: ​

Username (leave blank to use 'root'): admin
Email address: admin@example.com
Password: 
Password (again): 
Superuser created successfully.    
​

Next, gather all the static content into the directory

./manage.py collectstatic
​

Test the Django Development Server

​ Now, start the Django development server using the following command: ​

./manage.py runserver 0.0.0.0:8000

You should see the following output: ​

Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
June 22, 2021 - 11:15:57
Django version 3.2.4, using settings 'django_project.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
​

Now, open your web browser and access your Django app using the URL django.example.com:8000/admin. You will be redirected to the Django login page:

django admin login page

Provide your admin username, password and click on the Login. You should see the Django dashboard on the following page:

django admin dashboard

Now, go back to your terminal and press CTRL + C to stop the Django development server. ​

Test Gunicorn

​ Next, you will need to test whether the Gunicorn can serve the Django or not. You can start the Gunicorn server with the following command: ​

 gunicorn --bind 0.0.0.0:8000 django_project.wsgi

​ If everything is fine, you should get the following output: ​

[2021-06-22 11:20:02 +0000] [11820] [INFO] Starting gunicorn 20.1.0
[2021-06-22 11:20:02 +0000] [11820] [INFO] Listening at: http://0.0.0.0:8000 (11820)
[2021-06-22 11:20:02 +0000] [11820] [INFO] Using worker: sync
[2021-06-22 11:20:02 +0000] [11822] [INFO] Booting worker with pid: 11822

Press CTRL + C to stop the Gunicorn server. ​ Next, deactivate the Python virtual environment with the following command:

deactivate

Create a Systemd Service File for Gunicorn

​ It is a good idea to create a systemd service file for the Gunicorn to start and stop the Django application server. ​ To do so, create a socket file with the following command: ​

nano /etc/systemd/system/gunicorn.socket

​ Add the following lines: ​

[Unit]
Description=gunicorn socket
[Socket]ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target

​ Save and close the file then create a service file for Gunicorn:

nano /etc/systemd/system/gunicorn.service

​ Add the following lines that match your Django project path: ​

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/root/django_project
ExecStart=/root/django_project/djangoenv/bin/gunicorn --access-logfile - --workers 3 --bind 
unix:/run/gunicorn.sock          django_project.wsgi:application
[Install]
WantedBy=multi-user.target   
​

Save and close the file then set proper permission to the Django project directory:

chown -R www-data:root ~/django_project
​

Next, reload the systemd daemon with the following command:

systemctl daemon-reload
​

Next, start the Gunicorn service and enable it to start at system reboot:

systemctl start gunicorn.socket
systemctl enable gunicorn.socket
​

To check the status of the Gunicorn, run the command below:

systemctl status gunicorn.socket

​ You should get the following output: ​

gunicorn.socket - gunicorn socket     
Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)     
Active: active (running) since Tue 2021-06-22 12:05:05 UTC; 3min 7s ago   Triggers: ● gunicorn.service     
Listen: /run/gunicorn.sock (Stream)     
CGroup: /system.slice/gunicorn.socket
Jun 22 12:05:05 django systemd[1]: Listening on gunicorn socket.

Configure Nginx as a Reverse Proxy to Gunicorn Application

​ Next, you will need to configure Nginx as a reverse proxy to serve the Gunicorn application server. ​

To do so, create an Nginx configuration file:

nano /etc/nginx/conf.d/django.conf

​ Add the following lines:

   server {  
    listen 80;     
    server_name django.example.com;    
    location = /favicon.ico { access_log off; log_not_found off; }    
    location /static/ {         
        root /root/django_project;     
    }    
    location / {         
        include proxy_params;         
        proxy_pass http://unix:/run/gunicorn.sock;     
    }
}
​

Save and close the file then verify the Nginx for any configuration error:

nginx -t

​ Output: ​

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
​

Finally, restart the Nginx service to apply the changes:

systemctl restart nginx

​ Now, you can access the Django application using the URL django.example.com/admin. ​

Conclusion

​ In the above guide, you learned how to deploy a Django application with Gunicorn and Nginx as a reverse proxy. You can now use this setup in the production environment for deploying secure and high-performance Python applications.

Featured image by Gerry Sabar: gerrysabar.medium.com/deploying-django-3-ng..