Production setup#

Documentation - Installation#

Introduction#

This guide allows you to install, configure and operate Borgia on a production web server.

The entire installation is done on a server running Linux. The distribution is not important, but the guide is written for a Debian distribution, if this is not the case certain commands (notably the package installation commands) may need to be adapted.

This install version use Gunicorn as replacement of uwsgi/wsgi

The Gunicorn and Nginx part is strongly inspired from this very good guide made by : Erin Glass & Jamon Camisso on Digital Ocean.

First server configuration#

  • All of the following commands must be carried out using sudo, except in exceptional cases to the contrary and explicitly indicated below.

  • It is preferable that the entire server is configured on a virtual machine (VM) and not on the physical server directly. It can thus easily be copied, saved or reset.

  • In order for the guide to be clearer, it is decided to work in a specific folder named borgia-app located at the root of the server (/borgia-app). It is obviously possible to change this directory, the commands will therefore have to be modified.

Before starting#

Update the server:#

  • apt-get update

  • apt-get upgrade

Remove Apache if installed:#

  • apt-get purge apache2

Install necessary packages for the rest of the installation:#

  • apt-get install curl apt-transport-https

Install all necessary packages:#

  • sudo apt install build-essential libssl-dev libffi-dev libjpeg-dev python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl git

Creating the PostgreSQL Database and User#

  • sudo -u postgres psql

Inside the postgres=# terminal :

CREATE DATABASE borgia;
CREATE USER myprojectuser WITH PASSWORD 'password';
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;
\q

Installation of Yarn#

Explicit case of Debian, otherwise see here

  • curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

  • echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

  • apt-get update && sudo apt-get install yarn

Create the Borgia root folder:#

  • mkdir /borgia-app

  • cd /borgia-app

Copy of Borgia#

In /borgia-app:

  • git clone https://github.com/borgia-app/Borgia.git

Then in /borgia-app/Borgia:

  • git checkout tags/RELEASE_TO_UTILISER

  • git checkout -b production_RELEASE_TO_USE

Creating a Python Virtual Environment for your Project#

  • python3 -m venv venv

  • source venv/bin/activate

Installation of packages necessary for the application#

In /borgia-app/Borgia and in the virtual environment install the prod.txt requirement file.

  • pip3 install -r requirements/prod.txt

And finally, outside the virtual environment:

  • yarn global add less

Software configuration#

Vital parameters#

Copy the file /borgia-app/Borgia/contrib/production/settings.py to /borgia-app/Borgia/borgia/borgia/settings.py and:

  • Modify the SECRET_KEY = line by indicating a random private key. For example, this site allows you to generate keys, choose at least “CodeIgniter Encryption Keys”, for example: SECRET_KEY = 'AAHHBxi0qHiVWWk6J1bVWCMdF45p6X9t'.

  • Make sure DEBUG = False.

  • Modify the ALLOWED_HOSTS = line by indicating the domains or subdomains accepted by the application. For example: ALLOWED_HOSTS = ['sibers.borgia-app.com', 'borgia-me.ueam.net'].

Database#

In the /borgia-app/Borgia/borgia/borgia/settings.py file, modify the part:

DATABASES = {
...
}

by indicating the name of the database, the user name and the password defined during the configuration of the latter. For example :

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

Mail server#

  • Create a Google email account via the site Gmail and note the user name MAIL_USER_NAME and the password MAIL_PASSWORD.

In the /borgia-app/Borgia/borgia/borgia/settings.py file:

  • Modify the lines DEFAULT_FROM_EMAIL, SERVER_EMAIL and EMAIL_HOST_USER by indicating the email USER_NAME_MAIL.

  • Modify the EMAIL_HOST_PASSWORD line by indicating the correct password MOT_DE_PASSE_MAIL.

Administrators#

Administrators receive emails in the event of problems using Borgia. For example, if the database is inaccessible, Borgia will automatically send an email to the administrators. These emails are valuable and allow errors to be corrected. Indeed, the debug interface used in development is not accessible here and emails replace it. It is appropriate to add at least one administrator who will store any error emails to then debug or transfer to the Borgia maintainers team.

To add administrators, indicate the email addresses in the ADMINS= line in the /borgia-app/Borgia/borgia/borgia/settings.py file.

Database migration#

In /borgia-app/Borgia/borgia and in the virtual environment:

  • python3 manage.py makemigrations configurations users shops finances events modules sales stocks

  • python3 manage.py migrate

  • python3 manage.py loaddata initial

  • python3 manage.py collectstatic --clear by accepting the alert

Then, enter the password for the administrator account (which will be deactivated later):

Changing the password of the first user AE_ENSAM:

  • python manage.py shell

  • from users.models import User

  • u = User.objects.get(pk=1)

  • u.set_password("NEW_PASSWORD")

  • u.save()

  • exit()

Intermediate test#

UFW configuration#

If you followed the initial server setup guide, you should have a UFW firewall protecting your server. In order to test the development server, you need to allow access to the port you’ll be using.

Create exception for port 8000 :

  • sudo ufw allow 8000

Run the server#

The command in the virtual environment python3 manage.py runserver 0.0.0.0:8000 should start the server and should not report any errors. If this is the case, continue to the rest and end of the installation guide.

In your web browser, visit your server’s domain name or IP address followed by port 8000 : http://server_domain_or_IP:8000

Optionnal : testing Gunicorn’s ability to serve the project#

The last thing you need to do before leaving your virtual environment is test Gunicorn to make sure that it can serve the application. You can do this by entering the project directory and using gunicorn to load the project’s WSGI module:

  • cd /borgia-app/Borgia/borgia

  • gunicorn --bind 0.0.0.0:8000 borgia.wsgi

Deactivate the venv#

  • deactivate

Creating systemd Socket and Service Files for Gunicorn#

You have tested that Gunicorn can interact with our Django application, but you should now implement a more robust way of starting and stopping the application server. To accomplish this, you’ll make systemd service and socket files.

The Gunicorn socket will be created at boot and will listen for connections. When a connection occurs, systemd will automatically start the Gunicorn process to handle the connection.

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

Inside put the following content :


[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target


Next, create and open a systemd service file for Gunicorn with sudo privileges in your text editor. The service filename should match the socket filename with the exception of the extension:

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

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

[Service]
User=josue
Group=www-data
WorkingDirectory=/borgia-app/Borgia/borgia
ExecStart=/usr/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          borgia.wsgi:application

[Install]
WantedBy=multi-user.target

You can now start and enable the Gunicorn socket. This will create the socket file at /run/gunicorn.sock now and at boot. When a connection is made to that socket, systemd will automatically start the gunicorn.service to handle it:

  • sudo systemctl start gunicorn.socket

  • sudo systemctl enable gunicorn.socket

Checking for the Gunicorn Socket File#

  • sudo systemctl status gunicorn.socket

You should receive an output like this:

Output
● gunicorn.socket - gunicorn socket
     Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)
     Active: active (listening) since Mon 2022-04-18 17:53:25 UTC; 5s ago
   Triggers:  gunicorn.service
     Listen: /run/gunicorn.sock (Stream)
     CGroup: /system.slice/gunicorn.socket

Apr 18 17:53:25 django systemd[1]: Listening on gunicorn socket.

Next, check for the existence of the gunicorn.sock file within the /run directory:

  • file /run/gunicorn.sock

Output
/run/gunicorn.sock: socket

If the systemctl status command indicated that an error occurred or if you do not find the gunicorn.sock file in the directory, it’s an indication that the Gunicorn socket was not able to be created correctly. Check the Gunicorn socket’s logs by typing:

  • sudo journalctl -u gunicorn.socket

Take another look at your /etc/systemd/system/gunicorn.socket file to fix any problems before continuing.

Testing Socket Activation#

  • sudo systemctl status gunicorn

Output
○ gunicorn.service - gunicorn daemon
     Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
TriggeredBy: ● gunicorn.socket

If it’s OK you can run :

  • sudo systemctl daemon-reload

  • sudo systemctl restart gunicorn

Configure Nginx to Proxy Pass to Gunicorn#

  • sudo nano /etc/nginx/sites-available/borgia

server {
   
    listen 80;
    server_name YOUR.DOMAINNAME.COM;

    location = /favicon.ico { access_log off; log_not_found off; }


    location /media  {
        alias /borgia-app/Borgia/borgia/static/media;
    }

    location /static {
        alias /borgia-app/Borgia/borgia/static/static_root;
    }

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

}


  • sudo ln -s /etc/nginx/sites-available/borgia /etc/nginx/sites-enabled

Check the nginx configuration :

  • sudo nginx -t

  • sudo systemctl restart nginx

Allow Nginx through the UFW firewall#

  • sudo ufw delete allow 8000

  • sudo ufw allow 'Nginx Full'

You should now be able to go to your server’s domain or IP address to view your application.

Note: After configuring Nginx, the next step should be securing traffic to the server using SSL/TLS. This is important because without it, all information, including passwords are sent over the network in plain text. If you have a domain name, the easiest way to get an SSL certificate to secure your traffic is using Let’s Encrypt. Follow this guide to set up Let’s Encrypt with Nginx on Ubuntu 22.04. Follow the procedure using the Nginx server block you created in this guide.

Save to git#

Finally, you should save this entire configuration on a production branch (sudo not necessary here):

  • git add.

  • git commit -m "production"

It is not recommended to push this branch as it could contain sensitive information like keys and passwords.