Part 2: Securing Sensitive Info, Pushing Migrations, Installing Gunicorn and NGINX

Image for post
Image for post

Here we are going to make the Raspberry able to serve the application accessible as a normal web server would.

Remove sensitive info from the project:
pip3 install python-decouple
pip3 install dj-database-url
Add a file to store the info which will not appear in the commit (.env added to .gitignore):
nano .env
Add:

SECRET_KEY=the_secret_key_in_settings.py
DEBUG=True
ALLOWED_HOSTS=127.0.0.1 ## Enter here the ip address of your web server or it domain name or leave a * to allow any ip in a non production local server) ##
DATABASE_URL=postgres://name_of_db_user:the_password@host_name:port_number/name_of_db

Here the port number is where PostgreSQL was installed, by default: 5432.

Make changes to settings.py:

from decouple import config, Csv
import dj_database_url

SECRET_KEY = config(‘SECRET_KEY’)
DEBUG = config(‘DEBUG’, default=False, cast=bool)
ALLOWED_HOSTS = config(‘ALLOWED_HOSTS’, cast=Csv())
DATABASES = {
‘default’: dj_database_url.config(
default=config(‘DATABASE_URL’)
)
}

And add the following for static files:

STATIC_URL = ‘/static/’
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), ‘staticfiles’)

STATICFILES_DIRS = [
os.path.join(BASE_DIR, ‘static’),
]

Migrate the database:

python3 manage.py migrate

Collect static files:

python3 manage.py collectstatic

staticfiles folder will be created in the project’s parent folder for NGINX to serve the files (css, js,…)

Create a super user for the Django app:

python3 manage.py createsuperuser

Configure Gunicorn
Create a file gunicorn_start in the project root directory:

#!/bin/bash

NAME=”name_of_db”
DIR=/home/name_of_system_user/django_project/name_of_project
USER=name_of_system_user
GROUP=name_of_system_user
WORKERS=3
BIND=unix:/home/name_of_system_user/django_project/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=name_of_project.settings
DJANGO_WSGI_MODULE=name_of_project.wsgi
LOG_LEVEL=error

cd $DIR
source ../venv/bin/activate

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH

exec ../venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
— name $NAME \
— workers $WORKERS \
— user=$USER \
— group=$GROUP \
— bind=$BIND \
— log-level=$LOG_LEVEL \
— log-file=-

Make file as executer:

chmod u+x gunicorn_start

Make folders for socket and logs:

mkdir run logs

Make an empty log file inside /home/name_of_system_user/django_project/logs:

touch logs/gunicorn.log

Create a configuration file in Supervisor:

sudo nano /etc/supervisor/conf.d/name_of_system_user.conf

[program:name_of_system_user]
command=/home/name_of_system_user/django_project/gunicorn_start
user=name_of_system_user
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/home/name_of_system_user/django_project/logs/gunicorn.log

Make Supervisor read the config file and update:

sudo supervisorctl reread
sudo supervisorctl update

Check Supervisor configuration:

sudo supervisorctl status name_of_system_user

In order to restart the Django server after changes were made type:

sudo supervisorctl restart name_of_system_user

Configure NGINX:
Write a file name_of_project to /etc/nginx/site-available:

upstream app_server {
server unix:/home/name_of_system_user/django_project/run/gunicorn.sock fail_timeout=0;
}

server {
listen 80;
server_name website_address_OR_ip_address; # here can also be the IP address of the server

keepalive_timeout 5;
client_max_body_size 4G;

access_log /home/name_of_system_user/django_project/logs/nginx-access.log;
error_log /home/name_of_system_user/django_project/logs/nginx-error.log;

location /static/ {
alias /home/name_of_system_user/staticfiles/;
}

# checks for static file, if not found proxy to app
location / {
try_files $uri @proxy_to_app;
}

location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}

If Django there is need to get the web server accessible on a local network and the .env config file for Django’s settings:
Add the following to allow Django to look for the header first and then generate the URL:

USE_X_FORWARDED_HOST : True

And in the NGINX configuration file change the location @proxy_to_app to this:

location @proxy_to_app {
proxy_set_header Host $host;
proxy_set_header X-Url-Scheme $scheme;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_pass http://app_server;
}

Create a symbolic link (a shortcut) between sites-available and sites-enabled:

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

Remove NGINX default config file:

sudo rm /etc/nginx/sites-enabled/default
sudo service nginx restart

Add new model to models.py then run to migrate the database:

python3 manage.py makemigrations
python3 manage.py migrate

Using programming for marketing and work efficiency

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store