CodeBlock - How to Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04

How to Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04

Author: Daniel Marsh | Published: April 2, 2023


Welcome to the tutorial on setting up a Django project on a remote server with Gunicorn and Nginx. In this step-by-step guide, we will walk you through the process of deploying a Django application on a Linux server, configuring Gunicorn as the application server, and using Nginx as a reverse proxy to handle client requests.

Throughout the tutorial, we will provide you with specific instructions and commands to be executed on your server. Please make sure to replace the placeholder values enclosed in quotation marks with the relevant information specific to your project and environment.

By following this tutorial, you will learn how to create a new user with sudo privileges, set up a basic firewall, clone a Git repository, install required packages, create a PostgreSQL database and user, create a Python virtual environment, perform the initial project setup, test the project with Gunicorn, configure systemd socket and service files, test socket activation, configure Nginx to proxy pass to Gunicorn, and secure Nginx with Let's Encrypt for HTTPS.

Whether you are a beginner or an experienced developer, this tutorial will provide you with the necessary steps to deploy your Django project in a production environment, ensuring scalability, security, and reliability.

So, let's get started with the first step: creating a user with sudo privileges.

 NOTE - Throughout this tutorial, you will encounter specific words enclosed in quotation marks. It is important that you substitute these words with the appropriate information relevant to your situation. The following words require replacement:

  • "your_username"
  • "your_project_user"
  • "your_project"
  • ""
  • "your_projectenv"
  • "your_projectedir"
  • "your_server_IP"
  • "your_domain"


Step 1 – Login as root and create a user with sudo privileges. 

Note: Replace "your_username" with your desired username. 


adduser "your_username" 

usermod -aG sudo "your_username" 

Explanation: This step creates a new user with administrative privileges. 


Step 2 – Set up a basic firewall. 


ufw allow OpenSSH 

ufw enable 

Explanation: This step allows incoming SSH connections and enables the firewall to secure your server. 


Step 3 – Clone your git repo and create a deploy key. 

Change from the root user to the user you just created. 

sudo su - "your_username" 

Create the new SSH key. 

Note: Replace "" with your GitHub email. 

ssh-keygen -t rsa -b 4096 -C "" 

Now add the public key to your GitHub repository's deploy keys. You can view the key using the following command: 

sudo cat /home/"your_username"/.ssh/ 

Now clone the repo. 

git clone 

Explanation: This step sets up SSH authentication for accessing your Git repository and clones the repository to your server. 


Step 4 – Install all required packages from Ubuntu Repositories. 


sudo apt update 

apt list --upgradable 

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

Explanation: This step updates the package lists, installs Python, PostgreSQL, Nginx, and other necessary packages. 


Step 5 – Create the PostgreSQL Database and User. 

Note: Replace "your_project" with your project's name and "your_project_user" with your desired project username. 

sudo -u postgres psql 

CREATE DATABASE "your_project"; 

CREATE USER "your_project_user" WITH PASSWORD 'password'; 

ALTER ROLE "your_project_user" SET client_encoding TO 'utf8'; 

ALTER ROLE "your_project_user" SET default_transaction_isolation TO 'read committed'; 

ALTER ROLE "your_project_user" SET timezone TO 'UTC'; 

GRANT ALL PRIVILEGES ON DATABASE "your_project" TO "your_project_user"; 


Explanation: This step creates a new PostgreSQL database and user for your Django project. 


Step 6 – Create a Python virtual environment and install all required Python packages.

sudo -H pip3 install --upgrade pip 

sudo -H pip3 install virtualenv 

cd "your_projectdir"

virtualenv "your_projectenv"

source "your_projectenv"/bin/activate 

pip install django gunicorn psycopg2-binary 

pip install -r requirements.txt 

Explanation: This step creates a virtual environment for your project, activates it, and installs Django, Gunicorn, and other required Python packages. 


Step 7 – Complete the initial project setup. 

Make the initial migrations to your new database. 


python makemigrations 

python migrate 

Create a superuser for your project's admin login. 

python createsuperuser 

Collect all static content into one directory. 

python collectstatic 

Test that the project will run. 

sudo ufw allow 8000 
python runserver 

In your web browser, visit your server's domain name or IP address followed by ":8000". 


Explanation: This step performs the initial setup for your Django project, including database migrations, creating a superuser, and testing the server. 


Step 8 – Test if Gunicorn can serve the project. 

gunicorn --bind "your_project".wsgi 

In your web browser, visit your server's domain name or IP address followed by ":8000". 


You can now exit the Python virtual environment. 


Explanation: This step tests if Gunicorn is able to serve your Django project and deactivates the virtual environment. 


Step 9 – Creating systemd Socket and Service Files for Gunicorn. 

Start by creating and opening a systemd socket file for Gunicorn with sudo privileges in your preferred text editor. 

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

Inside, create a [Unit] section to describe the socket, a [Socket] section to define the socket location, and an [Install] section to make sure the socket is created at the right time. 



Description=gunicorn socket




Next, create and open a systemd service file for Gunicorn with sudo privileges. The service filename should match the socket filename with the exception of the extension. 

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

Once the file has opened, add the following, making sure to change the details to match your setup. 



Description=gunicorn daemon 




User= "your_username"



ExecStart=/home/"your_username"/"your_projectdir"/"your_projectenv"/bin/gunicorn \ 

          --access-logfile - \ 

          --workers 3 \ 

          --bind unix:/run/gunicorn.sock \ 




Next, start the Gunicorn socket. This will create the socket file at /run/gunicorn.sock now and at boot. 

sudo systemctl start gunicorn.socket 

Then enable it so that when a connection is made to that socket, systemd will automatically start the gunicorn.service to handle it. 

sudo systemctl enable gunicorn.socket 

Explanation: This step sets up systemd socket and service files to manage Gunicorn as a system service. 


Step 10 – Test the Socket activation. 

sudo systemctl status gunicorn 

To test the socket activation mechanism, send a connection to the socket through curl. 

curl --unix-socket /run/gunicorn.sock localhost 

You should receive the HTML output from your application in the terminal. This confirms that Gunicorn was started and able to serve your Django application. 

sudo systemctl daemon-reload 

Then restart the Gunicorn process. 

sudo systemctl restart gunicorn 

Explanation: This step tests the socket activation mechanism and restarts Gunicorn. 


Step 11 – Configure Nginx to proxy pass to Gunicorn. 

sudo nano /etc/nginx/sites-available/"your_domain" 

Once the file opens, add the following, making sure to edit the details to match your own. 


server { 

    listen 80; 

    server_name "your_server_IP" "your_domain" "www.your_domain"; 


    location = /favicon.ico { access_log off; log_not_found off; } 

    location /static/ { 

        root /home/"your_username"/"your_projectdir"; 


    location /media/ { 

        root /home/"your_username"/"your_projectdir"; 


    location / { 

        include proxy_params; 

        proxy_pass http://unix:/run/gunicorn.sock; 



Save and close the file when you are finished. Now, you can enable the file by linking it to the sites-enabled directory. 

sudo ln -s /etc/nginx/sites-available/"your_domain" /etc/nginx/sites-enabled 

Test your Nginx configuration for syntax errors. 

sudo nginx -t 

If no errors are reported, go ahead and restart Nginx. 

sudo systemctl restart nginx 

Since you no longer need access to the development server, adjust your firewall settings by removing the rule to open port 8000. 

sudo ufw delete allow 8000 

Then allow normal traffic on ports 80 and 443, thereby allowing HTTP and HTTPS connections, respectively, with the following command.

sudo ufw allow 'Nginx Full' 

You should now be able to go to your server's domain or IP address to view your application. 


Step 12 – Secure Nginx with Let's Encrypt.

sudo snap install --classic certbot 

sudo ln -s /snap/bin/certbot /usr/bin/certbot 

sudo ufw allow 'Nginx Full' 

sudo ufw delete allow 'Nginx HTTP' 

sudo certbot --nginx -d "your_domain" -d "www.your_domain" 

sudo certbot renew --dry-run 

Explanation: This step installs Let's Encrypt to obtain SSL certificates for your domain and secures Nginx with HTTPS. 



Congratulations! You have successfully completed the tutorial on deploying a Django project with Gunicorn and Nginx on a remote server. By following the step-by-step instructions, you have learned essential concepts and commands to set up a robust production environment for your Django application.

Throughout the tutorial, you have created a new user with sudo privileges, set up a basic firewall, cloned your Git repository, installed necessary packages, created a PostgreSQL database and user, created a Python virtual environment, performed the initial project setup, tested the project with Gunicorn, configured systemd socket and service files, tested socket activation, configured Nginx as a reverse proxy, and secured Nginx with Let's Encrypt for HTTPS.

By deploying your Django project using Gunicorn and Nginx, you have achieved improved performance, scalability, and security. Gunicorn acts as a high-performance web server to handle incoming requests, while Nginx acts as a reverse proxy to efficiently distribute those requests and serve static files. Additionally, you have secured your application with SSL certificates from Let's Encrypt, enabling encrypted communication between clients and your server.

With your Django application now deployed in a production environment, you can confidently handle increased traffic, provide a seamless user experience, and ensure the stability and reliability of your application.

Remember, as your project evolves, you may need to revisit certain configurations or explore additional optimizations specific to your requirements. However, this tutorial has provided you with a strong foundation to build upon.

We hope this tutorial has been valuable to you, and we encourage you to continue exploring Django's powerful features and the vast possibilities it offers for web development.

Happy coding!

Explore More articles

Subscribe to our Newsletter

CodeBlock - Empowering Your Digital Presence