Ms
Security AWS

multiOTP Strong Authentication on AWS User Guide

| Product: multiOTP on AWS

Overview

multiOTP is an open source, OATH-certified strong-authentication server. It lets you add time based (TOTP) and event based (HOTP) one-time passwords to your own applications, VPNs, and network devices while keeping every token seed on infrastructure you control. This image runs the LGPL open-source edition of multiOTP behind nginx, with PHP FPM 8.3 and OPcache enabled, and a self-contained flat-file token store.

The multiOTP application code and its flat-file user, token, device, and group store live under /usr/local/bin/multiotp on a dedicated, independently resizable EBS volume, so you can grow your user and token store without touching the operating system disk. There is no separate database server to install, secure, or back up.

The web admin console is served over HTTPS on port 443, in front of an nginx HTTP Basic authentication gate, so the console is never exposed unauthenticated. On the first boot of every deployed instance the administrator password is generated fresh and applied in lock-step to both the nginx Basic-auth gate and the multiOTP web admin, a per instance self-signed TLS certificate is regenerated, and the multiOTP default admin is reset to an unusable placeholder. Two instances launched from the same Amazon Machine Image never share credentials or a TLS key. The initial administrator password is written to /root/multiotp-credentials.txt with mode 0600 so that only the root user can read it.

multiOTP web admin sign-in

Prerequisites

Before you deploy this image you need:

  • An Amazon Web Services account where you can launch EC2 instances
  • IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
  • An EC2 key pair in the target Region for SSH access to the instance
  • A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound port 443 from the networks that will reach the web admin
  • The AWS CLI (version 2) installed locally if you plan to deploy from the command line

Step 1: Launch the Instance from the AWS Marketplace

Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for multiOTP. Select the cloudimg listing and choose Select, then Continue on the subscription summary.

Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network and inbound port 443 from the networks that will reach the web admin. Leave the root and data volumes at their default sizes or larger.

Select Launch instance. First boot initialisation takes approximately one minute after the instance state becomes Running and the status checks pass.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg multiOTP Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 443 as described above.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=multiotp-01}]'

The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.

Step 3: Connect and Retrieve Initial Credentials

Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched:

AMI variant SSH login user
multiOTP 5.10.2.2 on Ubuntu 24.04 ubuntu

For the Ubuntu 24.04 variant, connect with ssh -i <path-to-key.pem> ubuntu@<instance-public-ip>.

The administrator credentials generated on first boot are stored in a root only file. Retrieve them with the following command, which prints the multiOTP administrator user name and password for this specific instance:

sudo cat /root/multiotp-credentials.txt

The file lists the administrator user name (admin), the generated password, and the web admin URL. Store the password in your password manager and treat the file as sensitive.

Step 4: Verify the multiOTP Service

The web stack is two systemd services: nginx and PHP FPM. Confirm both are active:

systemctl is-active nginx php8.3-fpm

Both lines should read active. Confirm nginx is listening on the HTTPS port 443:

ss -tlnp 2>/dev/null | grep ':443 ' || sudo ss -tlnp | grep ':443 '

Confirm the dedicated data volume holding the application and token store is mounted:

df -h /usr/local/bin/multiotp | tail -1

The output shows the data volume mounted at /usr/local/bin/multiotp, for example:

/dev/nvme1n1    9.8G   17M  9.3G   1% /usr/local/bin/multiotp

Confirm the unauthenticated health endpoint is served over HTTPS (the certificate is self-signed, so curl is run with -k):

curl -sk -o /dev/null -w 'multiOTP health HTTP %{http_code}\n' https://127.0.0.1/health

An HTTP 200 response confirms the web tier is up. Plain HTTP is redirected to HTTPS, and the admin console requires authentication. The first command should report 301 and the second 401:

curl -s -o /dev/null -w 'plain HTTP redirect HTTP %{http_code}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'unauthenticated GET / HTTP %{http_code}\n' https://127.0.0.1/

Finally, confirm that the per instance administrator password is accepted (returns 200). This reads the generated password from the root only credentials file:

PASS=$(sudo grep '^multiotp.admin.pass=' /root/multiotp-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'authenticated GET / HTTP %{http_code}\n' -u admin:$PASS https://127.0.0.1/

Step 5: First Login to the Web Admin Console

Open a web browser and navigate to https://<instance-public-ip>/. Because the image ships a per instance self-signed certificate, your browser warns about the certificate the first time; this is expected, and you replace it with a CA signed certificate in step 8. Accept the warning to continue.

The browser first prompts for HTTP Basic authentication: enter the user name admin and the generated password from /root/multiotp-credentials.txt. You are then presented with the multiOTP web administration console sign-in form. Sign in with the same user name admin and password.

Once signed in, the console shows the multiOTP version and web service status and gives you the full set of administration actions: change the admin password, import hardware tokens, list hardware tokens, add users, and back up or restore the configuration.

multiOTP web administration console

Step 6: Create Users and Provision Tokens

Use Add a new user in the web console to create an account for each person who will authenticate. Give the user a name, choose a software token, and select the token type (for example TOTP), then add the user. You can also create a user and a software TOTP token from the command line:

sudo multiotp -fastcreatenopin alice

To enroll the user's token on a phone, open the printable provisioning page for that user from the Print button next to the user, or generate it from the command line. The page shows a QR code you scan with any OATH authenticator app (Google Authenticator, Microsoft Authenticator, FreeOTP, and others), plus the raw token details (algorithm, Base32 secret seed, number of digits, and time interval) for apps that do not support QR provisioning:

sudo multiotp -qrcode alice /tmp/alice-token.png

multiOTP QR-code token provisioning

Once the token is enrolled, the user generates a rolling one-time password in their authenticator app. You validate a submitted code with multiotp <user> <code>, which exits 0 when the code is accepted, so applications can shell out to it or call the multiOTP web service.

Step 7: Integrate with Applications, VPNs, and RADIUS

multiOTP validates one-time passwords in three ways so you can add MFA to almost anything:

  • Command line - your application shells out to multiotp <user> <otp> and checks the exit status.
  • Web service - multiOTP can answer validation requests over its bundled web service for applications that prefer an HTTP call.
  • RADIUS - front a RADIUS-capable VPN, firewall, or network appliance with multiOTP so that remote access requires a one-time code. multiOTP ships the FreeRADIUS integration scripts under its source tree; enable and configure the RADIUS server per the multiOTP documentation, and open the RADIUS ports (UDP 1812/1813) on the instance's security group only to the network devices that need them, using a per deployment RADIUS shared secret.

Step 8: Install a CA Signed Certificate with Let's Encrypt

The image serves HTTPS with a per instance self-signed certificate so the console is encrypted from first boot. For production use, replace it with a CA signed certificate so browsers and clients trust it without a warning. Point a DNS A record at the instance's public IP address, then install a certificate with Certbot. Replace the placeholders with your domain and email address.

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

Follow the prompts to obtain and install the certificate. Certbot updates the nginx configuration to use the new certificate on port 443. Keep inbound port 443 open to your client networks; port 80 is only used for the HTTP-to-HTTPS redirect and the Let's Encrypt challenge.

Step 9: Backup and Maintenance

All multiOTP state lives under /usr/local/bin/multiotp on the dedicated data volume: the application, the configuration, and the flat-file user and token store (the config store is under /etc/multiotp/config). Because the data volume is a separate EBS volume, the simplest backup is a point-in-time EBS snapshot:

aws ec2 create-snapshot --volume-id <data-volume-id> --description "multiOTP data backup"

To find the data volume ID, describe the instance's block device mappings. You can also back up the configuration from inside the web console with Backup the configuration, which produces an encrypted configuration file.

Apply operating system security updates with sudo apt-get update && sudo apt-get upgrade. The nginx and PHP FPM services restart cleanly, and multiOTP resumes serving immediately because all state is on the persistent data volume.

Support

This image is published and supported by cloudimg. For deployment help, token and user provisioning questions, RADIUS integration, certificate setup, upgrade guidance, or storage administration, contact cloudimg support by email or chat. multiOTP itself is open source software licensed under the GNU Lesser General Public License version 3 (LGPL-3.0).