Deployment

This guide covers running Momo in production. For a quick local setup, see Getting Started.

Quick Start (Docker Compose)

The recommended way to self-host Momo.

Prerequisites

Steps

  1. Clone the repository:
    git clone https://github.com/jp1337/momo.git
    cd momo
    
  2. Copy and configure environment variables:
    cp .env.example .env.local
    # Edit .env.local with your credentials
    
  3. Start all services:
    docker compose up -d
    
  4. Open http://localhost:3000 (or your domain if behind a reverse proxy)

Migrations run automatically. The container runs all pending database migrations before the Next.js server starts. Check docker compose logs app after deployment to confirm.


Container Images

Images are published to three registries on every release:

Registry Image
GitHub Container Registry ghcr.io/jp1337/momo
Docker Hub docker.io/jp1337/momo
Quay.io quay.io/jp1337/momo

To use a pre-built image instead of building locally, replace the build section in docker-compose.yml with:

app:
  image: ghcr.io/jp1337/momo:latest

Dockerfile Notes


Production Checklist

Before going live, complete all items below:


Reverse Proxy with Caddy

Caddy is the simplest way to add HTTPS in front of Momo. Create a Caddyfile:

momo.example.com {
    reverse_proxy localhost:3000
}

Caddy automatically provisions a Let’s Encrypt certificate. Run:

caddy run --config Caddyfile

Important: When running behind Caddy (or any reverse proxy), set AUTH_TRUST_HOST=true in .env.local. Auth.js v5 requires this to accept requests forwarded by the proxy.

Reverse Proxy with nginx

server {
    listen 443 ssl;
    server_name momo.example.com;

    ssl_certificate /etc/letsencrypt/live/momo.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/momo.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Important: When running behind nginx (or any reverse proxy), set AUTH_TRUST_HOST=true in .env.local. Auth.js v5 requires this to accept requests forwarded by the proxy.


AUTH_SECRET Rotation

To rotate the AUTH_SECRET (e.g. after a suspected compromise):

  1. Generate a new secret:
    openssl rand -base64 32
    
  2. Update the secret in your environment:
    • Docker Compose: update AUTH_SECRET in .env.local, then restart the app:
      docker compose up -d app
      
    • Kubernetes: update the Secret and trigger a rollout:
      kubectl patch secret momo-secrets -n momo \
        --type=merge \
        -p '{"stringData":{"AUTH_SECRET":"<new-secret>"}}'
      kubectl rollout restart deployment/momo-app -n momo
      
  3. Effect: All existing sessions are immediately invalidated. All users will be signed out and must log in again. This is expected and safe.

  4. Frequency: Rotate at minimum once per year. Rotate immediately if the secret is exposed.

Kubernetes

For full Kubernetes deployment instructions, see the Kubernetes guide.

The example manifests are in deploy/examples/ in the repository:

File Purpose
namespace.yaml Creates the momo namespace
deployment.yaml App deployment with 2 replicas, liveness/readiness probes
service.yaml ClusterIP service for the app
ingress.yaml Ingress with TLS (cert-manager + ingress-nginx)
secret.example.yaml Template for required Kubernetes secrets
postgres-statefulset.yaml PostgreSQL 18 StatefulSet with persistent volume