Django is a free and open-source web development framework written in Python. It is used for developing complex and database-driven Python applications. It comes with a set of Python scripts for creating Python projects. It can be run on any operating system that can run Python including, Windows, macOS, Linux/Unix, and Solaris. It helps developers to write less code and create a new website in a short amount of time.

In this tutorial, I will explain how to set up Django in Python virtual environment using the PostgreSQL database on Debian 11. We will then install and configure Nginx as a reverse proxy for Django.

Prerequisites

  • A server running Debian 11.
  • A valid domain name pointed with your server IP.
  • A root password is configured on the server.

Getting Started

Before starting, it is a good idea to update your system packages to the latest version. You can do it using the following command:

apt-get update -y

Once all the packages are updated, install other Python tools and Nginx package with the following command:

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

Once all the required packages are installed, you can proceed to the next step.

Install PostgreSQL Database Server

Here, we will use PostgreSQL as a database backend. So let’s install it using the following command:

apt-get install postgresql postgresql-contrib -y

Once the PostgreSQL is installed, connect to the PostgreSQL shell with the following command:

su - postgres

psql

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

CREATE DATABASE django;

CREATE USER django WITH PASSWORD 'password';

Next, grant some required roles with the following command:

ALTER ROLE django SET client_encoding TO 'utf8';

ALTER ROLE django SET default_transaction_isolation TO 'read committed';

ALTER ROLE django SET timezone TO 'UTC';

GRANT ALL PRIVILEGES ON DATABASE django TO django;

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

q

exit

At this point, the PostgreSQL database is ready for Django. You can now proceed to the next step.

Create a Python Virtual Environment

Next, you will need to create a Python virtual environment to create a Django project.

First, upgrade the PIP package to the latest version using the following command:

pip3 install --upgrade pip

Next, verify the PIP version using the following command:

pip --version

Sample output:

pip 21.2.4 from /usr/local/lib/python3.9/dist-packages/pip (python 3.9)

Next, install the Virtual environment package using the following command:

pip3 install virtualenv

Next, create a directory for the Django project and create a Django virtual environment:

mkdir ~/djangoapp

cd ~/djangoapp

virtualenv djangoenv

Next, activate the Django virtual environment using the command below:

source djangoenv/bin/activate

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

pip install django gunicorn psycopg2-binary

At this point, Django is installed in the Python virtual environment. Now, you can proceed to the next step.

Install and Configure Django

Django provides a django-admin.py script to create a project. You can run the following command to create a Django project:

django-admin.py startproject djangoapp ~/djangoapp

Next, you will need to edit the settings.py and define your database settings:

nano ~/djangoapp/djangoapp/settings.py

Change the following line with your domain name:

ALLOWED_HOSTS = ['django.example.com', 'localhost']

Uncomment the default database backend and add the PostgreSQL database settings:

#DATABASES = {
#    'default': {
#        'ENGINE': 'django.db.backends.sqlite3',
#        'NAME': BASE_DIR / 'db.sqlite3',
#    }
#}

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'django',
        'USER': 'django',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',

    }
}

Add the following lines at the end of the file:

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

Sample outputL:

  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

Next, create a superuser account for Django with the following command:

./manage.py createsuperuser

Set your admin username and password as shown below:

Username (leave blank to use 'root'): dadmin
Email address: [email protected]
Password: 
Password (again): 
Superuser created successfully.

Next, gather all the static content into the directory:

./manage.py collectstatic

Run the Django Development Server

At this point, Django is installed and configured. You can now start the Django development server using the following command:

./manage.py runserver 0.0.0.0:8000

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

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
August 27, 2021 - 10:02:05
Django version 3.2.6, using settings 'djangoapp.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 project using the URL http://django.example.com:8000/admin/. You will be redirected to the Django login page:

<img alt="Django login" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/09/echo/p1.png613f494bbf7a1.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="389" loading="lazy" src="data:image/svg xml,” width=”750″>

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

<img alt="Django admin dashboard" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/09/echo/p2.png613f494bf11c2.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="290" loading="lazy" src="data:image/svg xml,” width=”750″>

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

Verify Django with Gunicorn

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

gunicorn --bind 0.0.0.0:8000 djangoapp.wsgi

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

[2021-08-27 10:04:22  0000] [47383] [INFO] Starting gunicorn 20.1.0
[2021-08-27 10:04:22  0000] [47383] [INFO] Listening at: http://0.0.0.0:8000 (47383)
[2021-08-27 10:04:22  0000] [47383] [INFO] Using worker: sync
[2021-08-27 10:04:22  0000] [47384] [INFO] Booting worker with pid: 47384

Press CTRL C to stop the Gunicorn server.

Next, deactivate from Python virtual environment with the following command:

deactivate

Create a Systemd Service File for Gunicorn

Next, you will need to create a systemd service file for the Gunicorn to start and stop the Django application server.

You can create a Gunicorn 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/djangoapp
ExecStart=/root/djangoapp/djangoenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock          djangoapp.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 ~/djangoapp

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

Next, check the status of the Gunicorn using the command below:

systemctl status gunicorn.socket

You should get the following output:

? gunicorn.socket - gunicorn socket
     Loaded: loaded (/etc/systemd/system/gunicorn.socket; disabled; vendor preset: enabled)
     Active: active (listening) since Fri 2021-08-27 10:05:46 UTC; 6s ago
   Triggers: ? gunicorn.service
     Listen: /run/gunicorn.sock (Stream)
     CGroup: /system.slice/gunicorn.socket

Aug 27 10:05:46 debian11 systemd[1]: Listening on gunicorn socket.

Configure Nginx as a Reverse Proxy For Django

Next, you will need to configure Nginx as a reverse proxy to serve Django.

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/djangoapp;
     }

    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

To check the status of the Nginx, run:

systemctl status nginx

Sample output:

? nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-08-27 10:06:59 UTC; 6s ago
       Docs: man:nginx(8)
    Process: 47494 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 47495 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 47496 (nginx)
      Tasks: 2 (limit: 2341)
     Memory: 2.5M
        CPU: 49ms
     CGroup: /system.slice/nginx.service
             ??47496 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             ??47497 nginx: worker process

Aug 27 10:06:59 debian11 systemd[1]: Starting A high performance web server and a reverse proxy server...
Aug 27 10:06:59 debian11 systemd[1]: nginx.service: Failed to parse PID from file /run/nginx.pid: Invalid argument
Aug 27 10:06:59 debian11 systemd[1]: Started A high performance web server and a reverse proxy server.

Now, you can access the Django application using the URL http://django.example.com/admin. You can also access the Django application using the URL http://django.example.com/.

<img alt="Django app" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/09/echo/p3.png613f494c37e3d.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

Conclusion

Congratulations! you have successfully installed a Django application with Gunicorn and Nginx as a reverse proxy. You can now start deploying your Python application using the Django framework.