Montara Pass
Getting started

Docker

Build and run the API with its web app, and these docs, as containers.

There are two images. Releases publish the same images to GitHub Container Registry; see Releases.

API and web app

One image holds both: the web app is built with Vite and copied next to the Go binary, which serves it from ./public. The build context is the repository root. The image also contains the migrate binary.

docker build -f apps/server/Dockerfile -t montara-pass/cloud .
docker run --rm -p 8080:8080 --env-file apps/server/.env montara-pass/cloud

http://localhost:8080 then serves the UI, and http://localhost:8080/api/v1 the API.

PathAnswered by
/api/*the API; an unknown path under /api answers a JSON 404
a file that exists, such as /assets/…the static bundle
anything else without a file extensionindex.html, so client routes survive a reload

The image is alpine with the two binaries in /app, runs as a non-root user, and listens on PORT (8080). Settings are environment variables; see Configuration.

Build argumentDefaultPurpose
APP_VERSIONdevBaked into the binary and reported by GET /api/health
EDITIONcloudcloud (Cloud Edition) or community (Community Edition: one user, no sign-up, no sharing; needs SEED_ON_BOOT=true and SUPER_USER). Tag the image montara-pass/community
VITE_API_URLemptyThe API origin for the web app; empty means its own origin
VITE_APP_NAMEMontara PassName shown in the UI

Run a migration with the same image:

docker run --rm --env-file apps/server/.env \
  --entrypoint /app/migrate montara-pass/cloud up

Hosting the web app elsewhere

Pass --build-arg VITE_API_URL=https://api.example.com to point the bundle at another origin, and list the app's origin in CORS_ALLOWED_ORIGINS.

Dokploy

deploy/docker-compose.yml is a ready-made stack for Dokploy: PostgreSQL 18 with a named volume, Redis for the rate limit counts and idempotent answers (kept in memory only, since all of it expires within the hour), and the server image built from the repository.

  1. Create a Compose service from the repository and set the compose path to ./deploy/docker-compose.yml.
  2. Paste deploy/.env.example into the Environment tab and fill in POSTGRES_PASSWORD, APP_SECRET, AUTH_BASE_URL, FROM_ADDRESS and RESEND_API_KEY. The stack refuses to start while one of them is empty.
  3. Add a domain for the server service on port 8080. Dokploy connects the service to its Traefik network; the compose file publishes no ports.
  4. Deploy. The server waits for PostgreSQL to be healthy, applies its migrations on boot, and is itself checked on /api/health.

AUTH_BASE_URL must be the public https:// URL of that domain: sign-in emails and the Google callback are built from it.

Database password

The password is placed inside a connection URL, so keep it to letters, digits, - and _.

Requests reach the server through Dokploy's Traefik, so the stack sets TRUSTED_PROXIES to the private Docker ranges. Without it every visitor would share the proxy's address, and with it one rate limit.

To run this documentation site in the same stack, add COMPOSE_PROFILES=docs to the environment and give the docs service a domain on port 3000.

Docs

docker build -f apps/docs/Dockerfile -t montara-pass/docs .
docker run --rm -p 3000:3000 montara-pass/docs

On this page