Commands to setup a secure django website on ubuntu

20 Mar 2021 / OscFr
Secure web stack setup

TLDR: How to setup a secure django website on ubuntu.

Install everything

[1]: How to install and configure django with postgres, nginx and gunicorn

sudo apt update
sudo apt upgrade

sudo add-apt-repository universe
sudo add-apt-repository restricted
sudo add-apt-repository multiverse

sudo apt install python3-pip python3-dev libpq-dev python3-venv

sudo apt install postgresql postgresql-contrib

sudo apt install nginx

Setup Postgresql

[1]: How to install and configure django with postgres, nginx and gunicorn

sudo su - postgres

createdb devdb

createuser -P devuser

psql

ALTER ROLE devuser SET client_encoding TO 'utf8';

ALTER ROLE devuser SET default_transaction_isolation TO 'read committed';

ALTER ROLE devuser SET timezone TO 'UTC';

GRANT ALL PRIVILEGES ON DATABASE devdb TO devuser;

\q

exit

Security check.

For maximum security, ... this is an important security consideration.

[2]: How to secure postgresql on an ubuntu vps

sudo nano /etc/postgresql/9.6/main/pg_hba.conf

local all postgres peer

local all all peer

host all all 127.0.0.1/32 md5

host all all ::1/128 md5

To access PostgreSQL from a remote location, consider using SSH to connect to the database machine and then using a local connection to the database from there.

[2]: How to secure postgresql on an ubuntu vps

Virtual python environment

[3]: How to run django with mod_wsgi and apache with a virtualenv python environment on a debian vps

pip3 install --upgrade pip

pip3 install virtualenv

mkdir ~/dev_webb
cd ~/dev_webb

python3 -V

# python3.8 -m venv env

virtualenv env

Install and configure django

[1]: How to install and configure django with postgres, nginx and gunicorn

cd ~/dev_webb

source env/bin/activate

pip install django gunicorn psycopg2-binary

django-admin.py startproject dev_webb .

deactivate

[4]: Deployment checklist

nano ~/dev_webb/dev_webb/settings.py
SECRET_KEY = ''

with open('/etc/secret_key.txt') as f:
    SECRET_KEY = f.read().strip()

with open('/etc/database_name.txt') as f:
    db_name = f.read().strip()

with open('/etc/database_user.txt') as f:
    db_user = f.read().strip()

with open('/etc/database_password.txt') as f:
    db_password = f.read().strip()

DEBUG = False

LANGUAGE_CODE = 'sv'

TIME_ZONE = 'Europe/Stockholm'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': db_name,
        'USER': db_user,
        'PASSWORD': db_password,
        'HOST': 'localhost',
        'PORT': '',                      # Set to empty string for default.
        }
    }
sudo nano /etc/secret_key.txt
sudo nano /etc/database_name.txt
sudo nano /etc/database_user.txt
sudo nano /etc/database_password.txt

[5]: Static files (CSS, JavaScript, Images)

nano ~/dev_webb/dev_webb/settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

[6]: https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/modwsgi/

source env/bin/activate

manage.py check --deploy

python manage.py migrate

python manage.py collectstatic

manage.py check --deploy

deactivate

Creating systemd Socket and Service Files for Gunicorn

[6]: How to set up django with postgres, nginx and gunicorn on ubuntu 20.04

sudo nano /etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target
sudo nano /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=devuser
Group=www-data
WorkingDirectory=/home/devuser/dev_webb
ExecStart=/home/devuser/dev_webb/env/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          devsite.wsgi:application

[Install]
WantedBy=multi-user.target
sudo systemctl start gunicorn.socket

sudo systemctl enable gunicorn.socket

sudo systemctl status gunicorn.socket

Configure Nginx to Proxy Pass to Gunicorn

[6]: How to setup django with postgres nginx and gunicorn on ubuntu 20.04

sudo nano /etc/nginx/sites-available/dev_webb
server {
    listen 80;
    server_name domain_or_ip;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        alias /home/devuser/dev_webb/static/;
    }
    
    localtion /robots.txt {
        alias /home/devuser/dev_webb/robots.txt
    }

    location / {
        #include proxy_params;
        proxy_pass_header Server;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $http_host;

        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
sudo ln -s /etc/nginx/sites-available/dev_webb /etc/nginx/sites-enabled/

sudo nginx -t

sudo systemctl restart nginx

sudo systemctl restart gunicorn.socket gunicorn.service

sudo systemctl daemon-reload

HTTPS: SSL with lets-encrypt

[7]: https://certbot.eff.org/lets-encrypt/ubuntufocal-nginx

sudo apt-get update

sudo apt-get remove certbot

sudo apt-get update

sudo snap install --classic certbot

sudo certbot --nginx -d dev_webb.se -d www.dev_webb.se

sudo certbot renew --dry-run
nano ~/dev_webb/dev_webb/settings.py
debug = False

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# SECURE_SSL_REDIRECT = True ?

CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True

# SECURE_HSTS_SECONDS = 60 ?
SECURE_BROWSER_XSS_FILTER = True

[8]: fix-djangos-https-redirects-nginx/

source env/bin/activate

manage.py check --deploy

python manage.py migrate

python manage.py collectstatic

manage.py check --deploy

deactivate

sudo systemctl restart gunicorn.socket gunicorn.service

sudo nginx -t

sudo systemctl restart nginx
Facebook “f” Logo Black Twitter logo Black LinkedIn logo Black