Django 4.0 Install on Ubuntu 20.04

These are my notes for bringing up Django Install on a Production Server. These notes were written on a fresh install of Ubuntu 20.04. Most of my notes are coming from this Digital Ocean article with a few changes: https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-20-04

NOTE: Once this step is completed and you make changes you will need to restart gunicorn to see the changes on the production server.

sudo systemctl restart gunicorn

Install Packages for Python3 (Include Git if its not already installed and venv)

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

Create PostgreSQL Database & User

Login to Postgres Session:

sudo -u postgres psql

Create Database & User:

CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';

Change settings for Django:

Set default encoding to UTF-8
Block uncomitted transactions
Set timezone to UTC

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 privs on database to user:

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

Quit PostgreSQL:

\q

Create Home Directory for Django Apps & Install Django

mkdir djangoweb
mkdir djangoweb/myprojectdir
python3 -m venv /home/<user>/djangoweb/myprojectdir/env

Activate Virtual Environment & Install Django/Gunicorn

source ~/djangoweb/myprojectdir/env/bin/activate
pip install django gunicorn psycopg2-binary

Start Django Project

django-admin startproject myproject ~/djangoapps/myprojectdir

Edit settings.py

Add DNS Name(s), IP(s), and localhost to the “ALLOWED_HOSTS” area. Put in single quotes:

ALLOWED_HOSTS = ['dns1.dns.org','xxx.xxx.xxx.xxx.','localhost']

Add PostgreSQL Database Information

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

Add static file location, needed for nginx (bold items). This tells django to place them in a directory called static in the base project directory:

STATIC_URL = '/static/'
import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Complete Project Setup

#Create Default Database Migrations
python manage.py makemigrations
python manage.py migrate

#Create Administrative User
python manage.py createsuperuser

#Collect All Static Material into Defined Static Folder
python manage.py collectstatic

#Deactivate your virtual instance
deactivate

Configure GUnicorn

Create a GUnicorn systemd socket

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

/etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Create GUnicorn systemd service file

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

/etc/systemd/system/gunicorn.service

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

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

[Install]
WantedBy=multi-user.target

Start and enable GUnicorn Socket. This will create the socket file at: /run/gunicorn.sock now and at boot time. When a connection is made it will automatically start the service.

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

Configure Nginx to Proxy Pass to Gunicorn

sudo nano /etc/nginx/sites-available/myproject

/etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/<user>/myprojectdir;
    }

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

Enable File by linking it to sites-enabled

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Check for Errors

sudo nginx -t

If no errors restart nginx

sudo systemctl restart nginx

Punch a hole in UFW for Nginx

sudo ufw allow 'Nginx Full'