Nomploy Nomad Packs

← All packs

2fauth v0.1.0

Secrets

2FAuth — a self-hosted web app to manage your two-factor (TOTP/HOTP) accounts and generate security codes, with a clean UI and mobile-friendly design. Deployed as a single host-networked Nomad service.

nomad-pack run 2fauth --registry nomploy
…or one line (add registry + run)
curl -fsSL https://packs.nomploy.com/install.sh | sh -s -- 2fauth

Needs nomad-pack on PATH. The script only adds the nomploy registry and runs this pack.

2 tasks http 8000 1 volume image 2fauth/2fauth:latest tracks :latest image bumped today
Variables 10
values.hcl

Save as values.hcl, edit, then run:

nomad-pack run 2fauth -f values.hcl --registry nomploy
# The name of the Nomad job.
job_name = "2fauth"

# The Nomad namespace to deploy into.
namespace = "default"

# The datacenters to deploy to.
datacenters = ["*"]

# The 2FAuth container image. Pin a tag in production.
image = "2fauth/2fauth:latest"

# Host port for the 2FAuth web UI.
port = 8000

# Named volume mounted at /2fauth (the SQLite database).
data_volume = "2fauth_data"

# Laravel app key (APP_KEY). MUST be exactly 32 characters and CHANGE THIS — it encrypts your stored secrets, so keep it stable. Generate with: openssl rand -base64 24 | cut -c1-32.
app_key = "0123456789abcdef0123456789abcdef"

# Public URL 2FAuth is reachable at (APP_URL). Empty = http://localhost:<port>.
base_url = ""

# Placement constraints. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true".
constraints = []

# The task resources.
resources = {
    cpu    = 300
    memory = 256
  }
NameTypeDefaultDescription
job_name string
"2fauth"
The name of the Nomad job.
namespace string
"default"
The Nomad namespace to deploy into.
datacenters list
["*"]
The datacenters to deploy to.
image string
"2fauth/2fauth:latest"
The 2FAuth container image. Pin a tag in production.
port number
8000
Host port for the 2FAuth web UI.
data_volume string
"2fauth_data"
Named volume mounted at /2fauth (the SQLite database).
app_key key string
"0123456789abcdef0123456789abcdef"
Laravel app key (APP_KEY). MUST be exactly 32 characters and CHANGE THIS — it encrypts your stored secrets, so keep it stable. Generate with: openssl rand -base64 24 | cut -c1-32.
base_url string
""
Public URL 2FAuth is reachable at (APP_URL). Empty = http://localhost:<port>.
constraints list
[]
Placement constraints. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true".
resources object
{
    cpu    = 300
    memory = 256
  }
The task resources.
Back up this pack

This pack stores data in one Docker named volume: 2fauth_data

restic

# Run on the node hosting this pack. Point restic at your repo first:
#   export RESTIC_REPOSITORY="s3:https://<account>.r2.cloudflarestorage.com/<bucket>"
#   export RESTIC_PASSWORD="<repo-password>"
#   export AWS_ACCESS_KEY_ID=<key>  AWS_SECRET_ACCESS_KEY=<secret>
restic backup \
  /var/lib/docker/volumes/2fauth_data/_data

rclone (sync to S3/R2)

rclone sync /var/lib/docker/volumes/2fauth_data/_data backup:<bucket>/2fauth_data

Paths assume the default Docker volume location (/var/lib/docker/volumes). Restore by stopping the job, restoring files into the same volume, and re-running the pack.

Readme

2fauth

2FAuth — a self-hosted web app to manage your two-factor authentication accounts and generate TOTP/HOTP security codes. Import from other authenticators, organize with groups, scan QR codes, and access your codes from any device — with your secrets encrypted at rest. Uses SQLite, so it runs as a single container.

Single host-networked Nomad service with a persistent data volume.

Deploy

nomad-pack registry add nomploy https://github.com/Nomploy/nomad-packs
nomad-pack run 2fauth --registry=nomploy

Configure

Variable Default Description
port 8000 Web UI port.
app_key 0123… Change this (exactly 32 chars) and keep it stable — it encrypts stored secrets (APP_KEY).
base_url "" Public URL (APP_URL). Empty = http://localhost:<port>.
image 2fauth/2fauth:latest Container image. Pin a tag in production.
data_volume 2fauth_data /2fauth — the SQLite database.
resources { cpu = 300, memory = 256 } Task resources.

Set a stable 32-character app_key before storing accounts — it encrypts your 2FA secrets, so changing it later makes them unreadable. A prestart init task makes the data volume writable. Because it holds your 2FA secrets, always put 2FAuth behind an authenticating reverse proxy over TLS, and pin the job to the node holding the volume with constraints.