How To Set Up Secure Django with Postgres, Nginx, and Gunicorn on Ubuntu

Sundar AdhikariSundar Adhikari
5 min read

Introduction

Django is a robust web framework designed to help you rapidly build Python applications or websites. While Django provides a simplified local development server, you’ll need a more secure and scalable server setup for production environments.

This guide will walk you through setting up Django on Ubuntu 22.04 (or a supported version) with a PostgreSQL database. We’ll configure the Gunicorn application server to interface with your Django app and set up Nginx to reverse proxy to Gunicorn, leveraging its security and performance benefits. Additionally, we’ll deploy the application from GitHub using DigitalOcean’s App Platform, allowing automatic scaling and management.

By isolating Django within a virtual environment, you’ll be able to handle project dependencies independently. Once your database and application are live, Gunicorn will translate client requests into Python calls. Nginx will manage connections and serve static files efficiently.

Let’s dive into setting everything up!


Prerequisites

Ensure you’re using Ubuntu 22.04 or newer, as older versions like 16.04 are no longer supported. Follow our server setup guide to create a non-root user with sudo privileges and an active firewall.


Steps to Set Up Django with PostgreSQL, Gunicorn, and Nginx

  1. Install Packages from Ubuntu Repositories

  2. Create PostgreSQL Database and User

  3. Set Up a Python Virtual Environment

  4. Create and Configure Your Django Project

  5. Complete the Django Setup

  6. Test Gunicorn’s Ability to Serve Django

  7. Create Gunicorn systemd Socket and Service Files

  8. Check Gunicorn Socket File

  9. Configure Nginx to Proxy Gunicorn

  10. Troubleshoot and Complete Setup


Step 1 — Install Packages from Ubuntu Repositories

Start by updating your package lists and installing the required packages:

sudo apt update
sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl

This will install Python, PostgreSQL, and Nginx, alongside development libraries and tools required for your project.


Step 2 — Create PostgreSQL Database and User

Set up your PostgreSQL database and user:

  1. Log in as the postgres user and access PostgreSQL:
sudo -u postgres psql
  1. Create the database and user for your Django project:
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';
  1. Configure the user’s access and settings:
ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
  1. Exit PostgreSQL:
\q

Step 3 — Set Up a Python Virtual Environment

Create a virtual environment and install Django:

  1. Create and navigate to your project directory:
mkdir ~/myprojectdir
cd ~/myprojectdir
  1. Create and activate a virtual environment:
python3 -m venv myprojectenv
source myprojectenv/bin/activate
  1. Install Django, Gunicorn, and PostgreSQL adapter:
pip install django gunicorn psycopg2-binary

Step 4 — Create and Configure a New Django Project

  1. Create a new Django project:
django-admin startproject myproject .
  1. Update Django settings:
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'localhost']
  • Configure PostgreSQL database settings:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}
  • Configure static files:
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Step 5 — Complete the Django Setup

  1. Migrate the database schema:
python manage.py migrate
  1. Create a Django superuser:
python manage.py createsuperuser
  1. Collect static files:
python manage.py collectstatic
  1. Open firewall for testing:
sudo ufw allow 8000
  1. Test the development server:
python manage.py runserver 0.0.0.0:8000

Visit http://your_server_domain_or_IP:8000 in your browser to verify that Django is running.


Step 6 — Test Gunicorn’s Ability to Serve the Project

Stop the Django development server and test Gunicorn:

  1. Run Gunicorn:
gunicorn --bind 0.0.0.0:8000 myproject.wsgi
  1. Visit your server again to ensure the app is served.

Step 7 — Create Gunicorn systemd Socket and Service Files

Create socket and service files for Gunicorn:

  1. Create a Gunicorn socket file:
sudo nano /etc/systemd/system/gunicorn.socket

Add the following content:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target
  1. Create a Gunicorn service file:
sudo nano /etc/systemd/system/gunicorn.service

Add this content:

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

[Service]
User=your_user
Group=www-data
WorkingDirectory=/home/your_user/myprojectdir
ExecStart=/home/your_user/myprojectdir/myprojectenv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          myproject.wsgi:application

[Install]
WantedBy=multi-user.target
  1. Start and enable the Gunicorn socket:
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

Step 8 — Check the Gunicorn Socket File

Verify that Gunicorn started properly:

sudo systemctl status gunicorn.socket

You should see a message indicating that the socket is active.

Check for the socket file:

file /run/gunicorn.sock

If there’s an issue, check the logs:

sudo journalctl -u gunicorn.socket

Step 9 — Configure Nginx to Proxy Gunicorn

  1. Create a new Nginx server block:
sudo nano /etc/nginx/sites-available/myproject

Add this content:

server {
    listen 80;
    server_name your_server_domain_or_IP;

    location / {
        proxy_pass http://unix:/run/gunicorn.sock;
    }

    location /static/ {
        alias /home/your_user/myprojectdir/static/;
    }
}
  1. Enable the configuration:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
  1. Restart Nginx:
sudo systemctl restart nginx

Step 10 — Troubleshoot Nginx and Gunicorn

If you encounter any issues, check Nginx’s error log:

sudo journalctl -u nginx

And Gunicorn’s logs:

sudo journalctl -u gunicorn

If everything is working, your Django application should now be live, served via Nginx and Gunicorn with PostgreSQL as the database backend!

0
Subscribe to my newsletter

Read articles from Sundar Adhikari directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sundar Adhikari
Sundar Adhikari