Applications Azure

LORIS Neuroimaging Data Platform on Ubuntu 24.04 on Azure User Guide

| Product: LORIS 29.0.0 Neuroimaging Data Platform on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of LORIS on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. LORIS — the Longitudinal Online Research and Imaging System — is an open-source, web-based data-management platform for neuroimaging and clinical research studies, developed by the McGill Centre for Integrative Neuroscience (MCIN) at the Montreal Neurological Institute and used by research groups worldwide to run large multi-site longitudinal studies. It gives a study a single system for organising participants, visits, behavioural and clinical instruments, imaging data and derived measures, with user accounts, roles and fine-grained permissions, a configurable study structure, a self-service data query and download tool, and an administration surface a study coordinator can run without editing files.

The image installs LORIS 29.0.0 built from the official upstream source release, Apache 2.4 and PHP 8.4 FPM to serve it, and MariaDB from Ubuntu 24.04 to hold the study data, and wires all three together. The LORIS PHP dependencies (Composer) and the React front end (webpack) are compiled once when the image is built, so the customer VM ships ready to run with no build toolchain to invoke. Unattended security upgrades keep the server patched on your running VM.

One appliance, three services. apache2 and php8.4-fpm serve the application on port 80, and mariadb holds the study database. MariaDB is bound to 127.0.0.1:3306 and PHP FPM listens on a Unix socket, so neither is ever exposed to the network. Port 80 is the only reachable surface.

The web root and nothing above it. The Apache DocumentRoot is LORIS's htdocs/ directory. The application source, its vendored dependencies, the SQL schema, the command-line tools and above all project/config.xml — which holds this VM's database password — live outside any URL the web server can address. On top of that, only the two LORIS front controllers (index.php and AjaxHelper.php) are permitted to execute PHP, so a file placed anywhere else in the web root is refused rather than run.

Security by design — the setup wizard is removed. LORIS's schema defines a single administrator account (admin), but it ships with no usable password and no configuration file, and the installdb.php web installer that would let an anonymous visitor set that password and seize the account is removed from the image. On the first boot of every VM a one-shot service generates a unique database password and a unique administrator password, writes project/config.xml, imports the schema, sets the administrator's password as a bcrypt hash using LORIS's own resetpassword.php tool, and then proves the new password signs in through the real login endpoint and that admin/admin, a blank password and other common guesses do not, before writing /root/loris-credentials.txt (mode 0600, root only).

The site cannot serve an unprovisioned instance. apache2 and php8.4-fpm are each gated on a bootstrap marker that first boot writes only after the configuration file, the schema and every credential are in place. Until that marker exists systemd skips those units entirely, so there is no window in which a half-provisioned site — or the removed installer — is reachable. The units are still enabled, so the site comes straight back after a reboot.

What is included:

  • LORIS 29.0.0 served by Apache 2.4 and PHP 8.4 FPM, with htdocs/ as the only web root and the React front end compiled to production bundles

  • MariaDB (mariadb.service) holding the study database, bound to loopback

  • A configurable study structure with sites, projects, cohorts and visit definitions, and candidate/participant management

  • A behavioural and clinical instrument system, imaging data organisation, and a self-service data query tool with saved queries and CSV export

  • User accounts with roles and fine-grained, per-module permissions, a module manager, an issue tracker and multilingual interface support

  • A per-instance database password and administrator password generated on first boot and documented in /root/loris-credentials.txt (0600)

  • The core LORIS web platform only. The optional heavy neuroimaging pipeline tooling (MINC toolkit, DICOM/MRI insertion pipeline) is not bundled — it is a separate install customers add on larger dedicated instances

Prerequisites

  • Active Azure subscription, SSH public key, VNet and subnet in the target region

  • Subscription to the LORIS listing on Azure Marketplace

  • Network Security Group rules allowing TCP 22 (administration) and TCP 80 (the application) from the networks that need them

  • A registered domain if you want researchers to reach the instance by name rather than by IP address, plus access to your DNS provider

Step 1: Deploy from the Azure Portal

Search LORIS in Marketplace, select the cloudimg publisher, and click Create. Choose Standard_B2s or larger. Configure the Network Security Group to allow TCP 80 for the application from the networks that need it and TCP 22 for administration from your administrative networks only. The database and the PHP runtime stay on loopback and are never exposed.

Step 2: Deploy from the Azure CLI

RG="research-prod"; LOCATION="eastus"; VM_NAME="loris"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/loris-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values "$SSH_KEY" \
  --public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002

Step 3: First boot and your credentials

On first boot the image generates this VM's database password and administrator password, writes project/config.xml, imports the LORIS schema, sets the administrator account's password, opens the bootstrap gate, starts the web server, verifies the new credentials work and the common defaults are rejected, and writes /root/loris-credentials.txt. This completes within a minute or two. SSH in as azureuser and read the details:

sudo cat /root/loris-credentials.txt

The file is mode 0600 and owned by root, so only a privileged user can read it. It contains the instance URL, the administrator username and password, and the database name, user and password.

Step 4: Confirm the appliance is running

All three services should report active. ss confirms the application is on port 80 while MariaDB is bound to loopback only, and the response headers carry no server version banner.

systemctl is-active mariadb.service php8.4-fpm.service apache2.service
php -r 'echo "PHP ".PHP_VERSION."\n";'
mysql --version
apache2 -v | head -1
ss -tlnp | grep -E ':(80|3306) ' | sed 's/users:.*//' | sort
curl -sI http://127.0.0.1/ | grep -iE '^(HTTP|Server):'

The Server header reads Apache with no version number, and MariaDB appears only on 127.0.0.1:3306.

Step 5: Sign in to your instance

Browse to http://<your-vm-public-ip>/ and you will see the LORIS login page with the stock Example Study branding. Sign in with the username admin and the password from the credentials file.

The LORIS login page showing the LORIS logo, the Example Study description panel with useful links, and the Login to LORIS panel with username and password fields

Once signed in you land on the LORIS dashboard, which welcomes the administrator account, summarises what the database is for, and presents the My Tasks panel and the top navigation for the study's modules.

The LORIS dashboard after signing in, welcoming the Admin account, with the study description panel, the My Tasks panel and the top navigation bar

You can prove the same sign-in from the command line. This uses the per-instance password from the credentials file to complete a real login through the LORIS authentication endpoint, then checks that common default passwords are refused:

sudo /usr/local/sbin/loris-login-check.sh admin '<LORIS_ADMIN_PASSWORD>' && echo "per-VM password: ACCEPTED (correct)"
sudo /usr/local/sbin/loris-login-check.sh admin 'admin' || echo "admin/admin: REJECTED (correct)"
sudo /usr/local/sbin/loris-login-check.sh admin '' || echo "blank password: REJECTED (correct)"

Step 6: Change the administrator password

The first thing to do after signing in is set your own password. Open the Admin account menu in the top right and choose My Preferences, then use the password form to enter the per-instance password from the credentials file as the current password and choose a new one.

LORIS stores passwords as bcrypt hashes, so the new password is never recoverable from the database. Once you have changed it, the copy in /root/loris-credentials.txt is stale — keep the file for the database password, or remove the administrator password line from it.

Step 7: Configure your study

The Configuration module (under the Admin menu) is where a new LORIS instance becomes your study. The Study settings set the study title, the description shown on the login page, and the logos; Paths sets the data directories; and further sections cover the GUI, the dashboard, imaging modules, statistics, email, uploads, API keys and logging.

The LORIS Configuration module showing the Study settings with the study title, study logo, login logos and links, and the left navigation for Paths, GUI, WWW, Dashboard, Imaging Modules, Statistics, Email, Uploads, API Keys and Log Settings

Set the Study title first, because it appears on the login page, in the navigation bar and in every email the instance sends. Then define your study structure: sites, projects, cohorts and visit definitions, using the click here links at the top of the Configuration page for cohorts and projects.

Step 8: Create user accounts and add participants

Open User Accounts (under the Admin menu) to create accounts for your research team. LORIS uses roles and per-module permissions, so grant each user only the modules and sites they need. Create a first non-administrator account and confirm it can sign in with only the permissions you gave it.

With the study configured and users created, use Candidates → New Candidate to register a participant, then create a study visit (timepoint) for that candidate and begin entering instrument data. The Data Query Tool lets you build, save and export queries across the data you collect.

You can confirm the database is genuinely local and answers only to the per-instance credential:

DBPASS="$(sudo sed -n 's/^loris.db.password=//p' /root/loris-credentials.txt)"
mysql -h 127.0.0.1 -u lorisuser -p"$DBPASS" -N -B -e "SELECT COUNT(*) AS users FROM users" LORIS
ROOT_TCP="$(mysql -h 127.0.0.1 -u root -e 'SELECT 1' 2>&1 || true)"
case "$ROOT_TCP" in *"Access denied"*) echo "MariaDB root over TCP: refused (correct)" ;; esac

Step 9: Use your own domain and add TLS

Point an A record for your domain at the VM's public IP address, then set the instance host and URL so links and emails use the name rather than the IP. LORIS holds these in the Config table; update them and clear the compiled templates:

DBPASS="$(sudo sed -n 's/^loris.db.password=//p' /root/loris-credentials.txt)"
sudo mysql LORIS -e "UPDATE Config SET Value='<your-domain>' WHERE ConfigID=(SELECT ID FROM ConfigSettings WHERE Name='host'); UPDATE Config SET Value='https://<your-domain>' WHERE ConfigID=(SELECT ID FROM ConfigSettings WHERE Name='url');"
sudo rm -f /var/www/loris/smarty/templates_c/*

Then obtain a certificate. Certbot's Apache plugin edits the existing site in place:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-apache
sudo certbot --apache -d <your-domain> --redirect --agree-tos -m admin@<your-domain> --non-interactive

Step 10: Configure mail so account emails work

A fresh instance has no mail transport configured. Open the Email section of the Configuration module and enter your SMTP host, port and credentials so that account creation and password-reset emails are delivered. Mail settings are stored in the database, so you do not need to edit any file on disk.

Step 11: How the security model works

Two mechanisms do the work, and both are verifiable on your own VM.

The bootstrap gate. apache2 and php8.4-fpm each carry a systemd drop-in with ConditionPathExists pointing at a marker that first boot writes only after the configuration file, the schema and the administrator account all exist. Until then systemd skips the unit — it does not start and fail, it does not start at all — so an unprovisioned site is never reachable. Both units remain enabled so the site returns after a reboot.

grep -h ConditionPathExists /etc/systemd/system/apache2.service.d/cloudimg-bootstrap-gate.conf /etc/systemd/system/php8.4-fpm.service.d/cloudimg-bootstrap-gate.conf
ls -l /var/lib/cloudimg/
systemctl is-enabled php8.4-fpm.service apache2.service loris-firstboot.service

The web root, the config secret and the removed installer. Only htdocs/ is served, so project/config.xml, vendor/, the SQL schema and the tools are not addressable at all, and the web installer is gone. Only the two LORIS front controllers may execute PHP, so a .php file anywhere else in the web root is refused rather than run:

grep -E 'DocumentRoot' /etc/apache2/sites-available/loris.conf
stat -c '%n mode %a owner %U:%G' /var/www/loris/project/config.xml
for p in /installdb.php /postdeploy.php /project/config.xml /SQL/0000-00-00-schema.sql /vendor/autoload.php; do
  printf '%-34s HTTP %s\n' "$p" "$(curl -s -o /dev/null -w '%{http_code}' -m 10 http://127.0.0.1$p)"
done
curl -s -o /dev/null -w 'the site itself: HTTP %{http_code}\n' http://127.0.0.1/

config.xml is mode 640 owned root:www-data — readable by the web user that must load it on every request, writable by no one but root, and above the web root so no request can fetch it. Every installer and source path returns 403 or 404, while the site itself returns 200.

Step 12: Back up your instance

Everything your study creates lives in the MariaDB database, plus any files uploaded under the LORIS data directory. Back up both, plus project/config.xml if you want an exact restore of the same instance.

sudo mysqldump --single-transaction --routines LORIS > /var/backups/loris-$(date +%F).sql
sudo tar czf /var/backups/loris-data-$(date +%F).tar.gz -C /data/LORIS data 2>/dev/null || true

Restore on a new instance by importing the SQL dump into the LORIS database and copying the data files back. Keep config.xml out of any backup you share — it carries this VM's database password.

Step 13: Keeping LORIS up to date

Upgrading LORIS between major releases requires sourcing the release's SQL upgrade patch and rebuilding the front end; follow the upstream upgrade notes for the target release. The OS itself is kept patched by unattended upgrades, which are enabled in the image:

systemctl is-enabled unattended-upgrades.service
grep -h . /etc/apt/apt.conf.d/20auto-upgrades

cloudimg engineers can perform LORIS version upgrades for you under support.

Troubleshooting

The site returns nothing and Apache is not running. Check whether first boot completed. If the marker is absent, the gate is doing its job and the real problem is in first boot:

systemctl status loris-firstboot.service --no-pager | tail -20
ls -l /var/lib/cloudimg/

A database error after editing configuration. LORIS reads project/config.xml on every request, so a malformed edit breaks every page. Restore the file's ownership and permissions if a manual edit changed them — it is root:www-data mode 0640 on purpose:

sudo chown root:www-data /var/www/loris/project/config.xml
sudo chmod 0640 /var/www/loris/project/config.xml

Account emails never arrive. Mail is unconfigured on a fresh instance by design. Configure SMTP in the Email section of the Configuration module (Step 10).

Pages render without styling. Clear the compiled Smarty templates so LORIS regenerates them:

sudo rm -f /var/www/loris/smarty/templates_c/*
sudo systemctl reload apache2

Support

cloudimg provides 24/7 technical support for this image by email at support@cloudimg.co.uk and via live chat, with a one-hour average response time for critical issues. We help with domain and TLS certificate setup, mail delivery, the Configuration module, sites, projects and cohorts, user permissions, adding candidates and instruments, the data query tool, backup and restore, performance tuning, LORIS version upgrades and connecting the optional imaging pipeline.

LORIS is free software licensed under the GNU General Public License version 3. The upstream project's documentation is at github.com/aces/Loris.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.