Installation ‐ Ubuntu 22.04 - laureate-institute-for-brain-research/StimToolOnline GitHub Wiki

Installation Steps

Installation steps on Ubuntu 22 LTS. These installation steps were made in an attempt to find a balance between security and accessibility. These instructions assume you have a local admin user on the machine called "admin"

Main Steps are:

  1. Install Dependencies
  2. User and Groups Setup
  3. Clone repo
  4. Setup Mysql
  5. Prep Nodejs
  6. Prep application
  7. Configure Nginx
  8. Setup PM2

1. Install System Dependencies

sudo apt install -y nginx mysql-server

2. Setup service account and groups

sudo useradd -d /opt/stimtool -m -r -s /bin/bash stimtool
sudo groupadd stimtool_admins && sudo groupadd pm2_admins
sudo usermod -aG stimtool_admins,pm2_admins admin
sudo chgrp -R stimtool_admins /opt/stimtool
sudo passwd stimtool #Enter strong password at prompt
sudo usermod -aG sudo stimtool #This is needed for pm2 setup, it'll be removed later

3. Clone Repo

#If not an admin of the LIBR organization, skip the first couple steps and use https to clone repo
#As the stimtool user, create a ssh key-pair
sudo su stimtool
ssh-keygen
#Add to the repo as a deploy key: https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys
git clone --config core.sharedRepository=true [email protected]:laureate-institute-for-brain-research/StimToolOnline.git 

4. Setup Mysql

mysql is used to store database.

$ sudo systemctl start mysqld

Run the secure installation:

$ sudo mysql_secure_installation

Once you have mysql setup, we'll set a password on root and setup a user account for stimtool.

Become the mysql root user using the command:

$ mysql -u root

And set the root password:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'pick_a_strong_password';

Create the stimtool database.

mysql> CREATE DATABASE stimtool;

Generate a secure password, and use it in the example below instead of REPLACEME. Save this password to the password vault.

Create the database user weblogin for communication with the database. MySQL v8 default authentication plug was changed so need to be reverted back to work with sequelize.

mysql> CREATE USER 'weblogin'@'localhost' IDENTIFIED WITH mysql_native_password BY 'REPLACEME';

Lastly for this user, all ALL privileges need to be granted to work with the database.

mysql> GRANT ALL PRIVILEGES ON stimtool.* TO 'weblogin'@'localhost'; mysql> flush privileges;

Done. This mysql user is ready to work with the application.

5. Prep Nodejs

Install NVM, then use it to install the latest version of node. I'd encourage reviewing the script before piping to bash

sudo su stimtool
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install --lts

Exit out of the stimtool user, then move back into it to apply changes to environment variables and PATH

Install the npm update check tool, then check for updates and install packages

npm install -g npm-check-updates
ncu -u
npm install
npm install pm2@latest -g

Temporaryily(?) override the minimist package being installed as a dependency to patch some critical vulnerabilities. Do this by opening package.json and adding:

overrides: { "minimist":"1.2.6" },

run npm install again to catch the change

6. Prep Application

Create a new file called .env in the application directory.

Contents should look like

NODE_ENV=development
PORT=1185
MYSQL_HOST=localhost
MYSQL_USER=weblogin
MYSQL_PASSWORD=REPLACEME
MYSQL_DATABASE=stimtool
DATA_PATH=/media/data
TWILIO_ACCOUNT_SID=AXXXXXXXXXXXXXXXXXXXXXXXXXXXX
TWILIO_AUTH_TOKEN=AXXXXXXXXXXXXXXXXXXXXXXXXXXXX
MAILGUN_API_KEY=key-AXXXXXXXXXXXXXXXXXXXXXXXXXXXX
MAILGUN_DOMAIN=AXXXXXXXXXXXXXXXXXXXXXXXXXXXX
DASHBOARD_USER=brain
DASHBOARD_PASSWORD=######

Install application node dependencies

cd /opt/stimtool/StimtoolOnline
sudo -u stimtool npm install

Run stimtool.js for the first time for the application to create the necessary tables.

$ node stimtool.js

Once you see this message:

{"level":30,"time":1641342594803,"pid":6895,"hostname":"L00019188","msg":"Database Connected for Models"}

Exit the node process by pressint Ctrl + C

7. Configure NGINX

Make All Traffic Secure using nginx Edit the configuration file:

$ sudo vi /etc/nginx/nginx.conf Make sure it has this setting below

http {
    server_tokens off; # Prevents people from seeing node/express version
}

Create a secure diffie-helman group

Will make the app stay secure

# sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

Create a configuration File for SSL

# Create snippits Folder
sudo mkdir /etc/nginx/snippits

# Create file
sudo touch /etc/nginx/snippets/ssl-params.conf

# Edit the File
sudo vi /etc/nginx/snippets/ssl-params.conf`

Paste Below. Replace $DNS-IP-1 and $DNS-IP-2 with your chosen resolver.

# See https://cipherli.st/ for details on this configuration
ssl_protocols TLSv1.2;# Requires nginx >= 1.13.0 else use TLSv1.2
ssl_prefer_server_ciphers on; 
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver $DNS-IP-1 $DNS-IP-2 valid=300s;
resolver_timeout 5s; 
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

# Add our strong Diffie-Hellman group
# Genereates from openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_dhparam /etc/nginx/dhparam.pem;

Configure Domain to use SSL

sudo nano /etc/nginx/sites-available/stimtool.conf Paste Below, but replace the domain app.example.com with your domain

# HTTPS — proxy all requests to the Node app
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name app.example.com;

    # Use certificates
    ssl_certificate /etc/nginx/snippets/wildcard_full_chain.crt;
    ssl_certificate_key /etc/nginx/snippets/wildcard_private.key;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:1185/;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
    }
}

# HTTP — redirect all traffic to HTTPS
server {
    listen 80;
    listen [::]:80 default_server ipv6only=on;
    return 301 https://$host$request_uri;
}

Place CERT and KEY and allow nginx to read the files

Copy your wildcard_full_chain.crt to the snippets folder Copy your wildecard_private.key to the snippits* folder

Test nginx configuration

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Link the stimtool config to sites-enabled and remove the default file

sudo ln -s /etc/nginx/sites-available/stimtool.conf /etc/nginx/sites-enabled
sudo rm /etc/nginx/sites-enabled/default

Start nginx

sudo systemctl start nginx

Start nginx after restart

sudo systemctl enable nginx.service

8. Setup PM2

PM2 is used to monitor the application. And is a background service that restarts the node application file if it crashes. First register this service to systemd to ensure that the application restarts when the machine restarts. Run this command as the stimtool user.

pm2 startup systemd

At the end of this command running, there will be a command that you can copy and paste to setup startup script. Copy and paste the command into the terminal. Before you execute it, change --hp from /opt/stimtool to /opt/pm2.

Make a directory for pm2 that the pm2_admins will be able to access. In this case, we are putting it in /opt alongside the stimtool directory

sudo mkdir /opt/pm2

Update permissions on the /opt/pm2 directory

sudo chgrp -R pm2_admins /opt/pm2
sudo chmod -R 770 /opt/pm2
sudo chmod g+s /opt/pm2

Update the .bashrc file for stimtool and admin to point towards the new pm2 directory

'export PM2_HOME=/opt/pm2'

run the stimtool.js application, specifying the location to put pm2 files

cd /opt/stimtool/StimToolOnline
PM2_HOME=/opt/pm2 pm2 start /opt/stimtool/StimToolOnline/stimtool.js

Save the current process

pm2 save

Install pm2-logrotate module to save logs. Default is to rotate every day @midnight

pm2 install pm2-logrotate

Logs are stored in /opt/pm2/logs


At this point the application should now be up. Jump back into the admin user and remove stimtool from the sudo group and remove the password

sudo gpasswd --delete stimtool sudo
sudo passwd --delete stimtool

Go to the IP address using a webbrowser. example:

http://172.16.10.3/

or where you setup your domain:

https://tasks.laureateinstitute.org/