Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 20.04
Tags: guide, python, tools
Published: 2021-06-29 20:40:05

![feature_image.jpeg](https://cdn.hashnode.com/res/hashnode/image/upload/v1624993279619/k_0yCdlWj.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 http://django.example.com:8000/admin/. You will be redirected to the Django login page:

![django admin login page](https://arctype.com/blog/content/images/2021/06/Picture1.png) 

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

![django admin dashboard](https://arctype.com/blog/content/images/2021/06/Picture1-1.png)

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 **http://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: https://gerrysabar.medium.com/deploying-django-3-nginx-postgre-to-ubuntu-18-04-vps-220c529b588