Inventree 1.0.x install

Bare metal Installation instructions here:

https://docs.inventree.org/en/latest/start/install/

Here’s what I did different:

Install System Packages

Do the apt-get install of required system packages
For Weasyprint:
https://doc.courtbouillon.org/weasyprint/stable/first_steps.html
apt install pango1.0-tools
The rest of what Weasyprint needs will be auto-installed into the venv later.

Create InvenTree User

Create user with uid 1118 (to not clash with other uids), which is a member of www-data group.

Instead of:

useradd -m -d /home/inventree -s /bin/bash inventree

… run:

useradd -m -U -u 1118 -G www-data -s /bin/bash inventree
chown inventree:www-data /home/inventree
chmod o-rwx /home/inventree

Re su inventree, I installed my own ssh public key:

[ -f /home/inventree/.ssh/authorized_keys ] || (
  cd /home/inventree
  mkdir --mode 700 .ssh
    chown inventree:inventree .ssh
  cp /home/mjd/.ssh/mjd@xiaomao.afork.com .ssh/
  cat .ssh/*@* | sort | uniq > .ssh/authorized_keys
    chown inventree:inventree .ssh/*
    chmod go-rwx .ssh/authorized_keys
)

From here on, do everything logged in as the inventree user.

Create Required Directories

cd
mkdir data
cd data
mkdir static media backup
chgrp www-data static media backup
chmod g+s backup media
cd ..

Download Source Code

Instead of:

git clone https://github.com/inventree/inventree src

… run:

git clone -b stable https://github.com/inventree/inventree src

Then: Create and patch config (~/src/config/config.yaml), as follows.

Note, you’ll need to provide values for anything with a % below.

# Helper function
yaml_set() {
  F=~/src/config/config.yaml
  cp $F $F.tmp; awk -v key="$1" -v val="$2" 'BEGIN {
      have_dot = index(key, ".");
      if (have_dot) {
          split(key, parts, ".")
          parent = parts[1]
          child = parts[2]
      }
  }
  { 
    if (have_dot) {
      if ($0 ~ "^[[:alnum:]_]+:") in_parent = 0;
      if ($0 ~ "^" parent ":") in_parent = 1;
      if (in_parent && match($0, "^([[:space:]]*)(#[[:space:]]*)?(" child "):", m)) $0 = m[1] m[3] ": " val;
    } else if (patsplit($0, m, "^[[:space:]]*(#[[:space:]]*)?" key ":")) $0 = key ": " val;
    print
  }' < $F.tmp > $F; rm $F.tmp
}
ln -sf ../src/backend/InvenTree/config_template.yaml src/config/config.yaml.orig
cp src/config/config.yaml.orig src/config/config.yaml

yaml_set database.ENGINE mysql
yaml_set database.NAME itree
yaml_set database.USER dbuser
yaml_set database.PASSWORD %same-as-for-the-portal

yaml_set site_url https://itree.superlab.au/

yaml_set debug False

yaml_set admin_enabled True
yaml_set admin_url itree-admin
yaml_set admin_user admin
yaml_set admin_email itreeadmin@superhouse.tv
yaml_set admin_password %admin-user-password

yaml_set language en-AU
yaml_set timezone Australia/Melbourne

yaml_set email.sender itree@superlab.au
yaml_set email.host mail.smtp2go.com
yaml_set email.port 2525
yaml_set email.username itree
yaml_set email.password %smtp2go-password

yaml_set plugins_enabled True

yaml_set media_root /home/inventree/data/media
yaml_set static_root /home/inventree/data/static
yaml_set backup_dir /home/inventree/data/backup

yaml_set background.workers 1

yaml_set login_default_protocol https

yaml_set global_settings.INVENTREE_DEFAULT_CURRENCY AUD

Create Virtual Environment

As per instructions.

Install InvenTree Packages

Instead of:

pip install --upgrade --ignore-installed invoke
invoke install

… run:

cd ~/src
pip install --upgrade --ignore-installed invoke
invoke install --skip-plugins

If you run invoke and get a message Can't find any collection named 'tasks'!, then you need to run cd ~/src first, because invoke is sensitive to the directory it runs in.

If you run invoke install and you get this message:

yaml.scanner.ScannerError: while scanning for the next token
found character '%' that cannot start any token
  in "/home/inventree/src/config/config.yaml", line 27, column 13

… then you need to go edit ~/etc/config.yaml and patch in the passwords for any line containing %.

--skip-plugins is necessary because without this, the install tries to access the db, which hasn’t been set up yet.

Create Database

Db will be MariaDB. Follow MySQL / MariaDB section. Replace this:

sudo apt-get install mysql-server libmysqlclient-dev

with

sudo apt-get install mariadb-server libmysqlclient-dev

and

pip3 install mysqlclient mariadb

with

pip3 install mysqlclient

Re the SQL statements, the db I created is called itree, and the db user is dbuser (same as for the portal). The password will need to match what’s in ~/etc/config.yaml (see above).

sudo mysql -u root
mysql> CREATE DATABASE itree;
mysql> GRANT ALL ON itree.* TO 'dbuser'@'%';
mysql> FLUSH PRIVILEGES;
mysql> EXIT;

Don’t follow the web page from here on

Initialize database

Don’t follow any of this

And then…

This creates the db tables and a bunch of other important setup things.

invoke update --skip-backup --no-frontend

Download front end react app files

TAG=v$(awk 'match($0, "^INVENTREE_SW_VERSION = \047(.*)\047", m) {print m[1]}' < ./src/backend/InvenTree/InvenTree/version.py)
mkdir -p ~/src/src/backend/InvenTree/web/static
invoke frontend-download --tag $TAG
invoke static

Worker service

Inventree has a backend worker for operations that can take time, such as generating reports and sending emails. This worker should be started on boot, and restarted if it fails. For that we’re using supervisor (docs).

sudo apt-get install supervisor
cat << EOF | sudo tee /etc/supervisor/conf.d/inventree.conf > /dev/null
; # Supervisor Config File
; Example configuration file for running InvenTree worker using supervisor
; Based on https://github.com/inventree/InvenTree/blob/master/contrib/deploy/supervisord.conf

; InvenTree Background Worker Process
; A background task manager processes long-running and periodic tasks
; InvenTree uses django-q for this purpose
[program:inventree-cluster]
user=uwsgi
directory=/home/inventree/src/src/backend/InvenTree
command=/home/inventree/env/bin/python manage.py qcluster
startsecs=10
autostart=true
autorestart=true
stdout_logfile=/var/log/uwsgi/app/inventree-worker.log
stderr_logfile=/var/log/uwsgi/app/inventree-worker-err.log
EOF

cat << EOF | sudo tee /etc/supervisor/conf.d/inet_http_server.conf > /dev/null
[inet_http_server]
port = 127.0.0.1:9001
EOF

sudo systemctl reload supervisor

Logs for the worker can be viewed here: http://localhost:9001/ … where localhost is the inventree server. Since that port is only available locally on the server, you’ll need to use ssh -L or similar to get the HTTP request forwarded from your machine to the server, or use the links text browser.

Install redis?

If redis is installed, it will be used by the backend web code to communicate to the backend worker code. If it’s not there, things will still work, but slower. Symptoms are long waits for worker stuff to happen.

## So let's not
# sudo apt install redis-server

Setting up uWSGI (app server)

It is assumed that the uwsgi-emperor package has already been installed, and it’s up and running the portal.

cat << EOF | sudo tee /etc/uwsgi-emperor/vassals-available/inventree.ini > /dev/null
[uwsgi]
plugin = python3
chdir = /home/inventree/src/src/backend/InvenTree
virtualenv = /home/inventree/env
# /home/inventree/src/src/backend/InvenTree/InvenTree/wsgi.py
module = InvenTree.wsgi:application

master = true
processes = 2
enable-threads = true

cheaper = 1
cheaper-initial = 0
cheaper-min = 0
cheaper-max = 4
cheaper-algo = spare

# idle = 60
# die-in-idle = true

http-socket = /run/uwsgi/%n.sock
chmod-socket = 660
chown-socket = uwsgi:www-data
uid = uwsgi
gid = www-data

vacuum = true
die-on-term = true

# Optional logging:
logto = /var/log/uwsgi/app/%n.log
EOF

sudo ln -sf ../vassals-available/inventree.ini /etc/uwsgi-emperor/vassals-enabled/inventree.ini 

Check that the app server is now running. Example:

inventree@portal:~$ ps aux | grep uwsgi-core | grep inventree.ini
wsgi      67994 86.1 15.9 230520 157424 ?       R    15:07   0:19 /usr/bin/uwsgi-core --ini inventree.ini

inventree@portal:~$ 

Check also for the existence of /var/run/uwsgi/inventree.sock.

The uWSGI log can be viewed with:

sudo journalctl -u uwsgi-emperor

Add -f to tail the log.

Setting up caddy (web proxy)

Amend /etc/caddy/Caddyfile to add this:

# CORS headers control (used for static and media files)
(cors-headers) {
    header Allow GET,HEAD,OPTIONS
    header Access-Control-Allow-Origin *
    header Access-Control-Allow-Methods GET,HEAD,OPTIONS
    header Access-Control-Allow-Headers Authorization,Content-Type,User-Agent
 
    @cors_preflight{args[0]} method OPTIONS
 
    handle @cors_preflight{args[0]} {
        respond "" 204
    }
}

itree.example.com {
        log {
                output file /var/log/caddy/itree.log
                format filter {
                        wrap console
                        fields {
                                request>headers>Authorization delete
                        }
                }
        }

        encode gzip

        # Add request body size limit for file uploads
        request_body {
                max_size 100MB
        }

        header {
                Strict-Transport-Security max-age=31536000;
        }

        handle /favicon.ico {
                root * /home/inventree/data/static/img/favicon
                file_server
        }

        handle_path /static/* {
                import cors-headers static
                root * /home/inventree/data/static
                file_server
        }

        handle_path /media/* {
                import cors-headers media
                root * /home/inventree/data/media
                file_server
                # Authentication for media files
                forward_auth unix//run/uwsgi/inventree.sock {
                        uri /auth/
                }
        }

        reverse_proxy unix//run/uwsgi/inventree.sock
}

# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile

Note: Change itree.example.com to a suitable hostname. You’ll also need to create A or CNAME DNS records for this host.

(Basis: https://github.com/inventree/inventree/blob/master/contrib/container/Caddyfile)

Restart caddy:

sudo systemctl reload caddy

The caddy log can be viewed with:

sudo journalctl -u caddy

Add -f to tail the log.

Backups

Backups of the database and of the media files are done to ~/data/backup once a day by the worker. Database backups end in .dump.gz, and media backups end in .tar.gz. A cron job, run by the uwsgi user, sends the backups offsite every four hours using rsync. The backup filenames contain the hostname rather than the virtual host name due to limitations in InvenTree that will be fixed in InvenTree 1.1.

Upgrading

(If you’re just coming here for the upgrade, you’ll need to log in as inventree, then activate the virtual environment):

source ~/env/bin/activate

Then:

cd ~/src
git pull

Then do the steps in the Download front end react app files section above. Then:

sudo touch /etc/uwsgi-emperor/vassals/inventree.ini

You’ll need to reload any Inventree web pages you have open.