Mu
Security Azure

multiOTP on Ubuntu 24.04 on Azure User Guide

| Product: multiOTP on Ubuntu 24.04 LTS on Azure

Overview

multiOTP is an open source, OATH-certified strong two-factor authentication server. It issues and validates time-based and counter-based one-time passwords (TOTP and HOTP) as well as Mobile-OTP, provisions users to authenticator apps with QR codes, and keeps its users and tokens in a simple local flat-file store. It is driven both from a powerful command-line utility and from a bundled web administration console, and integrates cleanly with RADIUS front ends (such as FreeRADIUS), PAM and VPN login flows to add a second factor to your existing authentication.

The cloudimg image runs the open source LGPL edition of multiOTP 5.10.2.2 behind nginx with PHP-FPM 8.3. It ships only the open source edition — never the commercial multiOTP Pro/Enterprise appliance. Backed by 24/7 cloudimg support.

Because an authentication server with a default administrator login is a liability, this image is secure by default. The web admin console is fronted by nginx HTTP Basic authentication, and the multiOTP administrator account is rotated in lock-step with it. On the first boot of every deployed VM a single, unique administrator password is generated, applied to both gates, and written to /root/multiotp-credentials.txt with mode 0600 so only the root user can read it. Two VMs deployed from the same image never share credentials, and no default admin / 1234 login ever ships in the image.

multiOTP web admin sign-in

What is included:

  • multiOTP 5.10.2.2 open source edition (LGPL-3.0) — CLI (multiotp) plus the bundled web admin console
  • nginx + PHP-FPM 8.3 with OPcache and every PHP extension multiOTP requires
  • OATH-certified TOTP / HOTP / Mobile-OTP with QR-code provisioning and a flat-file user/token store
  • Per-VM administrator password generated at first boot, applied to both the nginx Basic-auth gate and the multiOTP admin account, stored in a root-only file
  • An unauthenticated /health endpoint for load balancers and monitors; every other path requires authentication
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point; scale up for larger user directories. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks that reach the admin console and query the authentication service.

Step 1 — Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for multiOTP by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + createCreate. First-boot initialisation takes about a minute after the VM starts.

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name multiotp \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name multiotp --port 80 --priority 1010

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 — Verify the multiOTP services

The web stack is two systemd services, nginx and PHP-FPM. Confirm both are active, that nginx is listening on port 80, and that the unauthenticated health endpoint answers:

systemctl is-active nginx php8.3-fpm
sudo ss -tlnp | grep ':80 '
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/health

Both service lines should read active, nginx should be listening on 0.0.0.0:80, and the health check should return HTTP 200.

multiOTP service health

Step 5 — Retrieve the per-VM administrator password

The administrator password is generated uniquely on the first boot of every VM and written to a root-only file. Read it:

sudo cat /root/multiotp-credentials.txt

The multiotp.admin.pass value is unique to this VM. The same admin / password pair unlocks both the nginx Basic-auth prompt and the multiOTP web admin sign-in.

Per-VM administrator credentials

Step 6 — Sign in to the web admin console

Browse to http://<vm-public-ip>/. Your browser first shows an HTTP Basic authentication prompt: enter the user admin and the password from Step 5. You then reach the multiOTP web administration console; sign in there with the same admin user and password.

multiOTP web admin console

From the console you can add users, import hardware tokens, resync and check users, and back up or restore the configuration. The Add a new user panel enrols a user and issues a soft or hardware token:

Add a new user

The token list shows every enrolled user with actions to print a provisioning sheet, generate a scratch list or resync a token:

Enrolled users and tokens

Step 7 — Enrol a user and provision a token from the CLI

You can also manage users from the command line. The multiotp command runs as the web service account so that users created on the CLI are immediately visible in the web console. Create a user without a prefix PIN, print its provisioning link, and write a QR code a phone can scan (write it to a world-readable path such as /tmp):

$ sudo multiotp -fastcreatenopin alice
INFO: user alice successfully created (exit 11)

$ sudo multiotp -urllink alice
otpauth://totp/multiOTP:alice?secret=PKTDTQG7O5W4KZ7MHX...&digits=6&period=30

$ sudo multiotp -qrcode alice /tmp/alice-qr.png
QR provisioning code written to /tmp/alice-qr.png

Scan the QR code with an authenticator app (Google Authenticator, FreeOTP, Aegis, Microsoft Authenticator, ...). multiOTP management commands return an informational non-zero exit code on success (for example 11 = user created); a zero exit code from the validation command below is what signals an accepted one-time password.

Enrol a user from the CLI

Step 8 — Validate a one-time password

To authenticate a user, pass their current one-time password to multiotp. It exits 0 when the code is accepted and non-zero when it is rejected — the contract you wire into a RADIUS, PAM or VPN login flow:

$ sudo multiotp alice 819241
OK: token accepted            (exit 0)

$ sudo multiotp alice 000000
ERROR: wrong one-time password (exit 99)

You can also validate interactively from the Check a user panel in the web console:

Validate a one-time password

Validate a one-time password from the CLI

Step 9 — Enable HTTPS (recommended)

The image serves the admin console over HTTP on port 80. For production, put it behind HTTPS. Point a DNS name at the VM, open 443/tcp, and use Let's Encrypt:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

certbot obtains a certificate and reconfigures nginx to redirect HTTP to HTTPS. Renewal is handled automatically by the packaged systemd timer.

Step 10 — Integrate with RADIUS, PAM or VPN

multiOTP is designed to sit behind an authentication front end. A common pattern is FreeRADIUS calling multiOTP as an external check so that VPNs, Wi-Fi and network devices gain a second factor. Point your front end at the multiotp command (exit code 0 = accept) or run the bundled network web service. See the multiOTP project documentation for FreeRADIUS and PAM integration recipes.

Maintenance

  • Backups: the configuration, users and tokens live under /etc/multiotp. Use the web console's Backup the configuration panel, or archive /etc/multiotp off-box.
  • Updates: the base OS has unattended security upgrades enabled. Keep the VM patched with sudo apt-get update && sudo apt-get upgrade.
  • Credentials: re-read /root/multiotp-credentials.txt at any time to recover the initial administrator password; change it from the console's Change admin password panel.

Support

This image is maintained by cloudimg with 24/7 support. For help with deployment or configuration, contact support@cloudimg.co.uk.