Deming ISMS on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Deming on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Deming is an open source information security management system (ISMS) and governance, risk and compliance (GRC) application. Security and compliance teams use it to run an ISO 27001 programme in one place: maintain the catalogue of security controls and the security measures that implement them, record and score risks, plan and track remediation actions, run internal audits and record observations, and report on the maturity of the whole management system.
The image installs Deming 2026.08.05 from the official upstream source, nginx and PHP 8.4 FPM to serve it, and MariaDB from Ubuntu 24.04 to hold the ISMS data, and wires them all together. The ISO 27001:2022 control framework is imported on first boot and a demonstration data set (security measures, risks and action plans) is generated, so a fresh instance shows a populated ISMS rather than an empty install. Unattended security upgrades are configured to keep the server patched on your running VM.
One appliance, three components. nginx and php8.4-fpm serve the application on port 80, and mariadb holds every control, measure, risk and audit you record. 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.
A Laravel deployment done properly. Deming is a Laravel application, and the document root is the framework's public/ directory and nothing above it. The application source, its vendored dependencies, the database migrations and above all .env — which holds this VM's application key and database password — live outside any URL the web server can address. On top of that, only the framework front controller is permitted to execute PHP, so a file placed anywhere else in the web root is refused rather than run. Public self registration is disabled: the administrator creates users from inside the application.
Security by design — no shared administrator credential ships in the image. Deming's database seeder normally creates a documented default administrator (admin@admin.localhost / admin). Rather than shipping that live and hoping you change it, this image ships no .env, no application key and no database schema at all — so that default account does not exist anywhere in the image. On the very first boot of every VM a one shot service generates a unique Laravel APP_KEY, a unique database password and a unique administrator password, creates the database schema, imports the ISO 27001:2022 controls, rotates the seeded administrator to your per instance password, scrambles every demonstration account so none can be signed into, and then proves the new password signs in through the real login form and that admin@admin.localhost/admin and other common passwords do not, before writing /root/deming-credentials.txt (mode 0600, root only).
Why the per instance application key matters. APP_KEY is Laravel's session, cookie and encryption signing material. If it were baked into the image, every customer of that image would share it, and anyone holding the image could forge a signed session for anyone else's instance. Here it is generated on your VM, for your VM.
The instance cannot serve an unprovisioned VM. nginx and php8.4-fpm are each gated on a bootstrap marker that first boot writes only after every credential is in place and the seeded administrator has been rotated. Until that marker exists systemd skips those units entirely, so there is no window in which a half provisioned instance — or the seeded default login — is reachable. The units are still enabled, so the application comes straight back after a reboot.
What is included:
-
Deming 2026.08.05 served by nginx and PHP 8.4 FPM, with the Laravel
public/directory as the only web root -
MariaDB (
mariadb.service) holding the ISMS data, bound to loopback -
The ISO 27001:2022 control catalogue imported on first boot, plus demonstration security measures, risks and action plans so the dashboard, the controls list and the risk matrix are populated on day one
-
Additional frameworks that ship in the image ready to import — ISO 27001:2013, ISO 22301, DORA, NIS2, PCI DSS 4.0 and NIST 800-53 — from Configuration → Import
-
A risk register with configurable scoring, a risk matrix, action plans, internal audit management, a documents library, dashboards and reports, and a REST API (Laravel Passport)
-
Local accounts with roles, and optional LDAP or Keycloak / OpenID Connect single sign on against your own directory
-
A per instance application key, database password and administrator password generated on first boot and documented in
/root/deming-credentials.txt(0600), with the seeded default administrator rotated and proven dead and every demo account scrambled
Prerequisites
-
Active Azure subscription, SSH public key, VNet and subnet in the target region
-
Subscription to the Deming 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 your team 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 Deming 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 your own networks 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="deming-prod"; LOCATION="eastus"; VM_NAME="deming"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/deming-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 application key, database password and administrator password, creates the database schema, imports the ISO 27001:2022 controls and demonstration data, rotates the seeded administrator to your per instance password, scrambles the demo accounts, opens the bootstrap gate, starts the web server, verifies the new credentials work and the defaults are rejected, and writes /root/deming-credentials.txt. This completes within a minute or two. SSH in as azureuser and read the details:
sudo cat /root/deming-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 login 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 nginx.service
php -r 'echo "PHP ".PHP_VERSION."\n";'
mysql --version
nginx -v
ss -tlnp | grep -E ':(80|3306) ' | sed 's/users:.*//' | sort
curl -sI http://127.0.0.1/login | head -4

Step 5: Sign in to your instance
Browse to http://<your-vm-public-ip>/ and you are redirected to the sign in page. Enter the login admin@admin.localhost and the password from the credentials file.

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 form, then checks that the seeded default and other common passwords are refused:
sudo /usr/local/sbin/deming-login-check.sh admin@admin.localhost '<DEMING_ADMIN_PASSWORD>' && echo "per-VM password: ACCEPTED (correct)"
sudo /usr/local/sbin/deming-login-check.sh admin@admin.localhost 'admin' || echo "admin@admin.localhost/admin: REJECTED (correct)"
sudo /usr/local/sbin/deming-login-check.sh admin@admin.localhost '' || echo "blank password: REJECTED (correct)"

Step 6: The ISMS dashboard
Once signed in you land on the dashboard. Down the left is the whole ISMS model: Controls, Measurements, Planning, Action plans, Risks, the Risk matrix, Exceptions, Analysis, Reports and Configuration. The main panel summarises your programme — the count of domains, controls, measurements, action plans, risks and exceptions, a schedule of upcoming measures, and the status of your measurements — all populated from the ISO 27001:2022 set and the demonstration data that first boot generated.

Step 7: Change the administrator password
The first thing to do after signing in is set your own password. Open the user menu in the top right and choose your Profile, then use the change password form. Enter the per instance password from the credentials file as the current password and choose a new one.
Deming stores passwords as bcrypt hashes, so the new password is never recoverable from the database. Once you have changed it, the copy in /root/deming-credentials.txt is stale — keep the file for the database password, or remove the administrator password line from it.
Step 8: Review the ISO 27001:2022 controls
Open Controls from the left navigation. Deming lists the ISO 27001:2022 control catalogue that first boot imported, grouped by domain and clause, with the number of measurements recorded against each. From here you can open a control, plan a measurement, and record how your organisation implements it.

Deming ships several other frameworks ready to load — ISO 27001:2013, ISO 22301, DORA, NIS2, PCI DSS 4.0 and NIST 800-53. Import one from Configuration → Import, or from the command line:
sudo -u www-data php /var/www/deming/artisan deming:import-framework \
/var/www/deming/storage/app/repository/NIS2.en.xlsx
Step 9: Work the risk register and matrix
Open Risks to see the risk register, and Risk matrix for the likelihood-by-impact heat map. The demonstration data seeds a set of scored risks across the matrix, with a breakdown by risk level and by treatment status, so you can see how Deming presents risk before you record your own. Add a risk with the add button, score its probability and impact, choose a treatment, and it takes its place on the matrix.

Step 10: Start your own ISMS (resetting the demonstration data)
The instance ships with demonstration security measures, risks and action plans so every view is populated for evaluation. When you are ready to run your own programme, you can clear the demonstration data and start from the ISO 27001:2022 controls alone. This drops all data and re-imports the framework, so take a backup first (Step 15):
cd /var/www/deming
sudo -u www-data env LANG=en php artisan migrate:fresh --seed
sudo -u www-data php artisan db:seed --class=AttributeSeeder
sudo -u www-data env LANG=en php artisan deming:import-framework \
storage/app/repository/ISO27001-2022.en.xlsx --clean
migrate:fresh recreates the administrator from the seeder, so afterwards sign in with admin@admin.localhost / admin once and immediately change the password from your Profile.
Step 11: Configure mail so notifications work
A fresh instance has no working mail transport, so notification and password reset email is not delivered until you configure one. Edit the MAIL_ values in /var/www/deming/.env — MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD — to point at your SMTP server, then clear the cached configuration:
sudo -u www-data php /var/www/deming/artisan config:clear
Keep the file's ownership and permissions as they are — it is root:www-data mode 0640 on purpose, because it holds this VM's application key and database password.
Step 12: Enable LDAP or Keycloak single sign on
Deming can authenticate against your own directory. LDAP and Keycloak both ship disabled in this image. To enable LDAP, set LDAP_ENABLED=true in /var/www/deming/.env and fill in LDAP_HOST, LDAP_PORT, the bind LDAP_USERNAME and LDAP_PASSWORD, and LDAP_BASE_DN for your directory; LDAP_FALLBACK_LOCAL=true keeps local logins working alongside it. To enable Keycloak or generic OpenID Connect single sign on, add keycloak (or oidc) to SOCIALITE_PROVIDERS and fill in the matching KEYCLOAK_ (or OIDC_) values. After editing .env, clear the cached configuration:
sudo -u www-data php /var/www/deming/artisan config:clear
Step 13: Enable the REST API (optional)
Deming exposes a REST API through Laravel Passport, which ships un-provisioned so no OAuth keys are baked into the image. To enable it on your instance, generate this VM's own Passport keys and client:
cd /var/www/deming
sudo -u www-data php artisan passport:install
Keep the generated keys private — like .env, they are per instance signing material.
Step 14: Use your own domain and add TLS
Point an A record at the VM's public IP, then set APP_URL in /var/www/deming/.env to https://your.domain. For TLS, the simplest path is a certificate from Let's Encrypt with the nginx plugin, which edits the shipped nginx site in place and reloads it. Replace <your-domain> with your fully qualified domain:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain> --redirect --agree-tos -m admin@<your-domain> -n
After certbot has installed the certificate, set APP_FORCE_HTTPS=true in .env and clear the cache so every generated URL uses HTTPS.
Step 15: How the security model works
The image ships no .env, no application key and no database schema, so the seeded default administrator does not exist in it. nginx and php8.4-fpm are gated on a bootstrap marker that first boot writes only after your per instance secrets exist and the seeded administrator has been rotated. Until then, systemd skips the serving units and nothing is reachable.
grep -E 'ConditionPathExists|After=' /etc/systemd/system/nginx.service.d/cloudimg-bootstrap-gate.conf
ls -l /var/lib/cloudimg/
systemctl is-enabled php8.4-fpm.service nginx.service deming-firstboot.service

The document root is the Laravel public/ directory and nothing above it, and only the front controller executes PHP. You can confirm nothing above public/ is reachable over HTTP:
grep -E '^\s+root ' /etc/nginx/sites-available/deming
for p in /.env /config/app.php /vendor/autoload.php /artisan; do
printf '%-28s 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 '/login HTTP %{http_code}\n' http://127.0.0.1/login

Step 16: Back up your instance
The whole state of your ISMS is in the MariaDB database plus the .env file. Take a consistent dump on a schedule and copy it somewhere off the VM (Azure Blob Storage, for example):
TS="$(date +%F-%H%M)"
DB_PASS="$(sudo sed -n 's/^deming.db.password=//p' /root/deming-credentials.txt)"
sudo mysqldump --single-transaction -u deming_user -p"$DB_PASS" deming > "/tmp/deming-$TS.sql"
echo "wrote /tmp/deming-$TS.sql"
Keep a copy of /var/www/deming/.env with the backup: it holds the application key that signs your sessions and the database password, so restoring the database without it would invalidate existing sessions.
Step 17: Keeping Deming up to date
The operating system keeps itself patched through unattended upgrades. For Deming itself, cloudimg publishes refreshed images as upstream releases new versions; the supported upgrade path is to deploy the new image and restore your database into it, which keeps the appliance hardening intact. cloudimg support can help you plan and carry out an upgrade.
Troubleshooting
The site does not load. Check that first boot finished: systemctl is-active deming-firstboot.service should report active, and /var/lib/cloudimg/deming-firstboot.done should exist. If first boot is still running, wait a minute and retry. If it failed, sudo journalctl -u deming-firstboot.service shows why.
The serving units are inactive. nginx and php8.4-fpm are gated on /var/lib/cloudimg/deming-bootstrap-ready. If that marker is missing, first boot has not completed — the units are meant to stay inactive until it does.
I cannot sign in. Read the current password from /root/deming-credentials.txt. If you have already changed it and lost the new one, contact cloudimg support, or reset the demonstration state as in Step 10 (which returns the administrator to admin@admin.localhost / admin for a single sign in, after which you must change it).
A change to .env had no effect. Clear the cached configuration with sudo -u www-data php /var/www/deming/artisan config:clear.
Support
cloudimg provides 24/7 technical support for this Deming image by email (support@cloudimg.co.uk) and live chat, with a one hour average response time for critical issues. We help with first boot and credentials, rotating the administrator password, the ISO 27001 control catalogue and security measures, the risk register and action plans, audit management, importing additional frameworks (DORA, NIS2, PCI DSS, NIST 800-53), LDAP and Keycloak single sign on against your own directory, the REST API, mail delivery, domain and TLS setup, database backup and restore, performance tuning and version upgrades. For billing or subscription changes, contact support@cloudimg.co.uk.
Deming is free software licensed under the GNU General Public License version 3. 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.