Self-Hosting Momo
All guides for running Momo on your own infrastructure.
Getting Started
Run Momo locally in under 10 minutes with Docker Compose. Start here.
Deployment
Production setup — Docker Compose with a reverse proxy, automatic updates via Watchtower.
Environment Variables
Complete reference for all configuration options — database, auth, push notifications, and more.
OAuth Setup
Register OAuth apps for GitHub, Discord, Google, or any OIDC provider (Authentik, Keycloak, etc.).
Two-Factor Auth
Optional TOTP for end users, plus an instance-wide enforcement switch (REQUIRE_2FA=true) that accepts TOTP or Passkey.
Passkeys
Passwordless WebAuthn login and method-agnostic second factor. Works with Face ID, Touch ID, Windows Hello and hardware keys.
Kubernetes
Deploy to a Kubernetes cluster with the provided manifests.
Quick reference
Minimum setup
git clone https://github.com/jp1337/momo.git && cd momo
cp .env.example .env.local
# Set DATABASE_URL, AUTH_SECRET, and at least one OAuth provider
docker compose up -d
Required environment variables
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
AUTH_SECRET |
Random secret — openssl rand -base64 32 |
| At least one OAuth provider | GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET, or Discord/Google/OIDC |
Behind a reverse proxy? Also set
AUTH_TRUST_HOST=true.
Full reference → Environment Variables
Enforcing two-factor authentication
If you want to require every user on your instance to set up a second factor (TOTP or Passkey) before they can use Momo:
-
Generate an encryption key for the TOTP secrets:
openssl rand -hex 32 -
Add both lines to your
.env.local:TOTP_ENCRYPTION_KEY=<the 64-character hex string from above> REQUIRE_2FA=true -
Restart Momo (
docker compose up -d).
From the next sign-in onwards, every account is sent to a forced setup page (/setup/2fa) until they enroll an authenticator app. Existing users get the same prompt — no migration is needed. The “disable 2FA” button in the user settings is hidden while REQUIRE_2FA=true is set, and removing the last remaining second factor (TOTP secret or last passkey) is blocked server-side.
Heads-up: the forced setup screen currently only walks new users through the TOTP wizard. Once they finish that, they can register passkeys from the regular settings page if they prefer. Method-agnostic enforcement is in place —
userHasSecondFactor()accepts either TOTP or any registered passkey — but the forced wizard is TOTP-only by design (to avoid getting stuck if the user’s browser doesn’t support WebAuthn). See Passkeys for the user-facing flow.
⚠️ Plan for recovery first. Once a user has 2FA on, losing both their authenticator app and all their backup codes means they cannot self-recover. You as the operator can clear their 2FA columns directly in the database. The exact SQL is in the technical guide. Make sure your users know to keep backup codes safe before you flip the switch.
⚠️ Treat
TOTP_ENCRYPTION_KEYas critical. Rotating it invalidates every existing TOTP secret — every user would need to re-enroll. Back it up alongside your database password.
Full end-user guide → Two-Factor Authentication
Container images
Available on three registries — pick whichever you prefer:
ghcr.io/jp1337/momo:latest
docker.io/kermit1337/momo:latest
quay.io/jp1337/momo:latest