5.8. Production Server

Although there are a lot of similarities to the development environment, there are a few key differences especially when it comes to security and performance considerations.

  • Create the server

  • Secure the server

  • Install required software

  • Download the project

  • Set up configuration files

5.8.1. Create a Production Machine

Choose your host and create your new virtual server then use SSH to access it using a terminal on your local machine.

Note

It saves complications if you set up your server (including the site and Nginx etc.) before you change DNS settings and traffic starts getting routed.

Initial set up overview:

* SSH access
* Install software
* Firewall
* Swap for extra memory
* Fail2ban

5.8.1.1. SSH Access

Consider adding the dev machine SSH Key to the server when creating it or set up a very strong password then log in to it and create a priveleged user other than root:

ssh root@ip-address
adduser example.co.uk --force-badname
password

Note

For security on the production web server, each project will have its own user area and password but for development purposes each project will live in the home folder for the main developer.

You can add SUDO permissions for a user by running visudo while logged in as root and adding the following line:

newusername ALL=(ALL:ALL) ALL
CTRL+O followed by ENTER to save
CTRL+X followed by ENTER to close
exit (to log off)

Back on local machine:

ssh-copy-id th-example.co.uk@IP-ADDRESS
ssh th-example.co.uk@IP-ADDRESS
sudo nano /etc/ssh/sshd_config
  permitrootlogin no
  SAVE AND EXIT
sudo dpkg-reconfigure locales en_GB.UTF-8  # Might not be required
ssh-keygen -t rsa
COPY SSH KEY TO BITBUCKET
reboot

Note

SSH log in is dependent on whether the DNS is set up and working for your server or not. If not, use the IP address.

5.8.1.2. Install Software

Install the Django Software Requirements.

5.8.1.3. Firewall

For Ubuntu an easy way to restrict access is to use UFW:

https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-20-04

5.8.1.4. Swap for extra memory

https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-20-04

5.8.1.5. Fail2ban

Limit access to repeat offenders:

https://linuxize.com/post/install-configure-fail2ban-on-ubuntu-20-04/

5.8.2. Download the Django application

Note

For production you should already have a Django application developed and uploaded to an online version control system such as BitBucket. If not, follow the instructions for creating a Development Machine and develop one first.

Follow the instructions for Using an existing Django application.

5.8.2.1. Database

For development in Django you can use a simple sqlite database that is just a file in the project folder and is simpler to set up and wipe and start fresh. Sometimes it is worth setting up a database to mirror production.

  • Create user and database

  • Backup

Follow the PostgreSQL instructions for setting up a production database.

Follow the Backup instructions.

5.8.2.2. Nginx

Note

When you use debian-base systems, you should fill /etc/hostname file with FQDN

Note

Set up Nginx for your site so it is listening before setting up DNS or it will set it to the default entry and be a pain to clear.

Add configuration file to sites-available then symbolic link to sites-enabled (sudo ln -s /etc/nginx/sites-available/hello /etc/nginx/sites-enabled/hello). Restart nginx to check there are no errors (sudo service nginx restart).

Run SSL certificate creation with Let’s Encrypt.

Refer to the Nginx instructions for more information.

5.8.3. Gunicorn

pip install gunicorn in the virtualenv and create config file called gunicorn_start(.bash?) and save it in /bin.

Set the executable bit on the file with sudo chmod u+x bin/gunicorn_start

“As a rule-of-thumb set the –workers (NUM_WORKERS) according to the following formula: 2 * CPUs + 1. The idea being, that at any given time half of your workers will be busy doing I/O. For a single CPU machine it would give you 3.”

Example config:

#!/bin/bash

NAME="hello_app"                                  # Name of the application
DJANGODIR=/webapps/hello_django/hello             # Django project directory
SOCKFILE=/webapps/hello_django/run/gunicorn.sock  # we will communicte using this unix socket
USER=hello                                        # the user to run as
GROUP=webapps                                     # the group to run as
NUM_WORKERS=3                                     # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=hello.settings             # which settings file should Django use
DJANGO_WSGI_MODULE=hello.wsgi                     # WSGI module name

echo "Starting $NAME as `whoami`"

# Activate the virtual environment
cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=-

5.8.4. Supervisor

Create config file in /etc/supervisor/conf.d

Example config file:

[program:hello]
command = /webapps/hello_django/bin/gunicorn_start                    ; Command to start app
user = hello                                                          ; User to run as
stdout_logfile = /webapps/hello_django/logs/gunicorn_supervisor.log   ; Where to write log messages
redirect_stderr = true                                                ; Save stderr in the same log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8                       ; Set UTF-8 as default encoding

Create logs:

mkdir -p /home/project/logs/
touch /home/project/logs/gunicorn_supervisor.log

Reload:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status

This should mean the application is automatically started after a system reboot.

5.8.5. Celery and Beat

ACTIVATE THE ENVIRONMENTS THEN ENTER THE PROJECT FOLDER

python -m celery -A proj worker

celery -A proj beat -l INFO –scheduler django_celery_beat.schedulers:DatabaseScheduler

5.8.6. Daphne and Channels

https://techflow360.com/how-to-deploy-django-channels-by-configuring-nginx-to-run-both-gunicorn-and-daphne/

5.8.7. SSL

Let’s Encrypt

https://www.f5.com/company/blog/nginx/using-free-ssltls-certificates-from-lets-encrypt-with-nginx

Create conf files that get automatically adjusted by certbot instead of using the previous sites-available/enabled system.

Reload nginx with a different command:

sudo nginx -t && sudo nginx -s reload

5.8.8. DNS

Here is an example DNS configuration file:

A - @ - SERVER_IP
CNAME - www - DOMAIN.co.uk. # note the trailing dot
NS - ns1.digitalocean.com.
NS - ns2.digitalocean.com.
NS - ns3.digitalocean.com.

5.8.9. Fixtures

python manage.py dumpdata APP --indent=4 > APP-fixtures.json