Server Installation

These steps are from a production installation.

Create a system user

Fill in the prompts after running the command:

adduser cstock

This user will be the one to run cstock and other related processes.

Make the cstock user a sudoer

This will allow them to run necessary commands as root.

sudo usermod -aG sudo cstock

Install and configure MySQL

Follow this guide to install MySQL.

sudo apt install mysql-server
sudo systemctl start mysql.service

Set a root login/password

Replace the password with the one you want to set.

$ sudo mysql
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '***';
mysql> \q

Secure installation

sudo mysql_secure_installation

Restore user-based access

$ mysql -u root -p
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;
mysql> \q

Create cstock database user

Don’t forget to change the password!

$ sudo mysql
mysql> CREATE USER 'cstock'@'localhost' IDENTIFIED WITH mysql_native_password BY '***';
mysql> GRANT CREATE, ALTER, DROP, INSERT, UPDATE, INDEX, DELETE, SELECT, REFERENCES, RELOAD on *.* TO 'cstock'@'localhost' WITH GRANT OPTION;
mysql> \q

Create cstock database

$ mysql -u cstock -p
mysql> CREATE DATABASE cstock;
mysql> \q

Restore cstock database

If you haven’t already, take a backup of the database from whatever server it is running on:

sudo mysqldump -v cstock > cstock_database.sql
gzip cstock_database.sql

When you have it, copy the backup to the server using rsync. If the servers cannot access each other you might have to do this in two steps, first copying the file to your own machine, as follows:

rsync -P -e ssh user@oldserver:cstock_database.sql.gz ./
rsync -P -e ssh ./cstock_database.sql.gz user@newserver: 

When it completes, unzip and restore it:

gunzip cstock_database.sql.gz
sudo mysql cstock < cstock_database.sql

Note: the above restore usually has to be run as root due to permissions issues.

Install Python, pip, virtualenv, virtualenvwrapper, mysql dependencies

For these steps, be sure you are logged in as the cstock user.

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.9 python3.9-dev libmysqlclient-dev python3.9-distutils
sudo apt install python3-pip
python3 -m pip install --user virtualenv virtualenvwrapper

Set up virtualenvewrapper

source /home/cstock/.local/bin/virtualenvwrapper.sh

If you run into errors, check your environment variables and update your .profile as described here and here.

Install Redis

Following this guide.

sudo apt install redis-server

Then change /etc/redis/redis.conf to have

supervised systemd

As described in the article.

Finally, restart with:

sudo systemctl restart redis.service

None of the other steps are required.

Create project directories

As the cstock user, set up your project directories:

mkdir -p ~/www/cstock/
mkdir -p ~/www/cstock/log/

Set up cstock

Set up cstock code according to the Dev Setup Instructions.

As the cstock user, set up your code directory and Python environment:

cd ~/www/cstock/
git clone https://github.com/dimagi/logistics.git code_root
cd code_root
mkvirtualenv -p python3.9 cstock
setvirtualenvproject
pip install -r requirements.txt

Configure localsettings

Copy your localsettings across from the previous production project and edit anything relevant (e.g. database credentials)

If you are able to run ./manage.py runserver with no issues, things are likely working as expected.

Install and configure nginx

By following this guide.

sudo apt install nginx

Follow the software firewall steps if you don’t have any other firewall in place.

Then create a new site named cstock in /etc/nginx/sites-available/ based off the following. You will have to adjust hosts, ports, and file paths to match your setup.

upstream cstock {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).
  server localhost:9095 fail_timeout=0;
}

server {
  listen 80;
  listen [::]:80;

  server_name cstock.health.gov.mw

  # don't forward traffic from unexpected hosts.
  # this prevents a flood of django.security.DisallowedHost errors from bots/spammers, etc.
  if ($host !~* ^(cstock.health.gov.mw|localhost|127.0.0.1)$ ) {
    return 444;
  }


  # Serve static files from nginx
  location /static/ {
    alias  /home/cstock/www/code_root/static_root/;
  }


  location / {

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 300s;
    proxy_redirect off;

    if (!-f $request_filename) {
       proxy_pass http://cstock;
       break;
    }
  }

}

Then enable the file with:

ln -s /etc/nginx/sites-available/cstock /etc/nginx/sites-enabled/

And restart nginx:

sudo service nginx reload

Set up static files

In the cstock code home directory run:

python manage.py collectstatic

If static files are returning a 403 error, check the permissions on the path.

If static files are returning a 404 error, check the paths in the nginx configuration above.

Set up SSL

Install certbot

sudo apt install certbot
sudo apt install python3-certbot-nginx

Configure nginx:

sudo certbot --nginx -d cstock.dimagi.com

Follow the steps, and you’re done.

Install and configure supervisord

Follow these instructions to set up supervisord.

sudo apt install supervisor

Then create a supervisord configuration file that looks something like this. Save it to /etc/supervisor/conf.d/cstock.conf. Like nginx, you’ll have to tweak paths and such.

[program:rapidsms-router]
process_name=rapidsms-router
command=/home/cstock/.virtualenvs/cstock/bin/python /home/cstock/www/cstock/code_root/manage.py runrouter 
directory=/home/cstock/www/cstock/code_root/
user=cstock
autostart=true
autorestart=true
stdout_logfile=/home/cstock/www/cstock/log/rapidsms.log
redirect_stderr=true
stderr_logfile=/home/cstock/www/cstock/log/rapidsms.error.log

[program:celery]
;command=/usr/bin/python /usr/local/bin/celery -A logistics_project worker -l info -B
command=/home/cstock/.virtualenvs/cstock/bin/celery -A logistics_project worker -l info -B
directory=/home/cstock/www/cstock/code_root/
user=cstock
numprocs=1
stdout_logfile=/home/cstock/www/cstock/log/celery.log
stderr_logfile=/home/cstock/www/cstock/log/celery.error.log
autostart=true
autorestart=true
startsecs=10
stopwaitsecs = 600
priority=998

[program:gunicorn]
command=/home/cstock/.virtualenvs/cstock/bin/gunicorn -w 4 logistics_project.wsgi --bind 127.0.0.1:9095 --log-file /home/cstock/www/cstock/log/gunicorn.command.log --log-level debug --timeout 300
directory=/home/cstock/www/cstock/code_root/
user=cstock
stdout_logfile=/home/cstock/www/cstock/log/gunicorn.log
stderr_logfile=/home/cstock/www/cstock/log/gunicorn.error.log
autostart=true
autorestart=true

Once the file is set up correctly, you can add it to supervisor and start all the processes by running:

sudo supervisorctl reload

Set up and configure Kannel (SMS gateway)

sudo apt install kannel

Update your /etc/kannel/kannel.conf file based on the example provided here

You will have to provide appropriate passwords.

Additionally, you will need to disable the wapbox and enable smsbox by editing /etc/default/kannel as follows:

#START_WAPBOX=1
START_SMSBOX=1

Finally restart kannel:

sudo service kannel restart