minmaxkey

Deploy

Deploy

Your MinMaxKey server, running. One container, two minutes, no orchestration.

Image: pinned on GitHub Container Registry — ghcr.io/maxing-tech/minmaxkey:1.0.0-rc. While the repo is private the image is private too (docker login ghcr.io once with a GitHub account); from the public release onward it pulls with no login.

Docker

MMK_ADMIN_TOKEN=$(openssl rand -base64 32)     # management API key
MMK_ADMIN_PASSWORD=$(openssl rand -base64 16)  # dashboard login
MMK_SECRET_KEY=$(openssl rand -base64 32)      # session cookie signing

docker run -d -p 8080:8080 \
  -v ./data:/data \
  -e MMK_ADMIN_TOKEN="$MMK_ADMIN_TOKEN" \
  -e MMK_ADMIN_PASSWORD="$MMK_ADMIN_PASSWORD" \
  -e MMK_SECRET_KEY="$MMK_SECRET_KEY" \
  ghcr.io/maxing-tech/minmaxkey:1.0.0-rc

curl -s localhost:8080/healthz
# {"status": "ok", "service": "minmaxkey"}

That's it. The dashboard is at http://localhost:8080/admin (login with MMK_ADMIN_PASSWORD), the API explorer at /docs.

Keep the three secrets somewhere safe — you'll need MMK_ADMIN_TOKEN for the CLI and webhook automation.

Docker Compose

# docker-compose.yml
services:
  minmaxkey:
    image: ghcr.io/maxing-tech/minmaxkey:1.0.0-rc
    ports: ["8080:8080"]
    environment:
      MMK_ADMIN_TOKEN: ${MMK_ADMIN_TOKEN:?set in your shell}
      MMK_ADMIN_PASSWORD: ${MMK_ADMIN_PASSWORD:-admin}
      MMK_SECRET_KEY: ${MMK_SECRET_KEY:?set in your shell}
    volumes:
      - ./data:/data
    restart: unless-stopped
export MMK_ADMIN_TOKEN=$(openssl rand -base64 32)
export MMK_SECRET_KEY=$(openssl rand -base64 32)
docker compose up -d

Bare Python (no Docker)

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export MMK_ADMIN_TOKEN=$(openssl rand -base64 32)
export MMK_ADMIN_PASSWORD=$(openssl rand -base64 16)
export MMK_SECRET_KEY=$(openssl rand -base64 32)
uvicorn app.main:app --host 0.0.0.0 --port 8080

Environment variables (the only config there is)

variable default notes
MMK_DATABASE_PATH data/mmk.db SQLite file location
MMK_DATABASE_URL — set to use Postgres instead
MMK_ADMIN_TOKEN dev-admin-token management API auth — change it
MMK_ADMIN_PASSWORD admin dashboard login — change it
MMK_SECRET_KEY change-me cookie signing — change it, keep stable
MMK_COOKIE_SECURE false true when serving over HTTPS
MMK_ALLOWED_ORIGINS * comma-separated CORS allowlist
MMK_RESEND_API_KEY — Resend API key — key emails, 2-min setup
MMK_POSTMARK_TOKEN — Postmark server token — key emails
MMK_EMAIL_FROM — sender address for any backend (verified sender)
MMK_SMTP_HOST — classic SMTP server — key emails
MMK_SMTP_PORT 587 SMTP port (STARTTLS)
MMK_SMTP_USER / MMK_SMTP_PASS — SMTP login (empty = no auth)
MMK_SMTP_FROM MinMaxKey <no-reply@…> sender address (also works for the API backends)
MMK_SMTP_TLS true STARTTLS on connect (port 587)
MMK_SMTP_SSL false implicit TLS (port 465); takes precedence over MMK_SMTP_TLS

Setting any email backend turns on key delivery by email: the buyer gets their license key on checkout and a note on each renewal. Resend is the two-minute path — Email delivery.

Generate secrets: python -c "import secrets; print(secrets.token_urlsafe(32))".

Backups

/data holds the whole database. Copy the file, or point Litestream / restic / borg at the directory. That's the entire backup story.

Done? Head to Use it to issue your first license — or skip ahead to deeper ops (Postgres, reverse proxy, upgrades): self-hosting.