Deployment guide

multiOTP

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.

This SecureAnyCloud 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. You manage it from a command-line utility or the bundled web administration console, and it integrates with RADIUS front ends (such as FreeRADIUS), PAM and VPN login flows to add a second factor to your existing authentication.

What you get:

  • multiOTP 5.10.2.2 open-source edition (LGPL-3.0): the CLI (multiotp) plus the bundled web admin console
  • nginx and PHP-FPM 8.3 with OPcache and every PHP extension multiOTP requires
  • OATH-certified TOTP, HOTP and Mobile-OTP with QR-code provisioning and a flat-file user and token store
  • Secure by default: nginx HTTP Basic authentication fronts the web admin console, and the multiOTP administrator account is rotated in lock-step with it
  • A per-VM administrator password, generated at first boot and applied to both the nginx Basic-auth gate and the multiOTP admin account. It is written to /root/multiotp-credentials.txt with mode 0600, so only the root user can read it
  • No shared credentials: two VMs deployed from the same image never share a password, and no default admin / 1234 login ever ships in the image
  • An unauthenticated /health endpoint for load balancers and monitors. Every other path requires authentication
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet and subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point. Scale up for larger user directories.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network. Also allow 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 SecureAnyCloud, and select Create.

On the Basics tab, 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).

Select Review + create, then Create. First-boot initialisation takes about a minute after the VM starts.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:multiotp-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name multiotp \
  --image sac1647283583153:multiotp-ubuntu-24-04:default:latest \
  --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 that 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.

Step 5 - Retrieve the per-VM administrator password

The first boot of every VM generates a unique administrator password and writes it to a root-only file. Read it with:

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.

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 user admin and password.

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:

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

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 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 that a phone can scan. Write the QR code 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 signals an accepted one-time password.

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. This is 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:

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. The packaged systemd timer renews the certificate automatically.

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 the VM.
  • 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 SecureAnyCloud with 24/7 support. For help with deployment or configuration, contact sales@secureanycloud.com.

Deploy on Azure

Launch multiOTP on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure