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/cloudhttp://localhost:8080 then serves the UI, and http://localhost:8080/api/v1 the
API.
| Path | Answered 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 extension | index.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 argument | Default | Purpose |
|---|---|---|
APP_VERSION | dev | Baked into the binary and reported by GET /api/health |
EDITION | cloud | cloud (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_URL | empty | The API origin for the web app; empty means its own origin |
VITE_APP_NAME | Montara Pass | Name 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 upHosting 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.
- Create a Compose service from the repository and set the compose path
to
./deploy/docker-compose.yml. - Paste
deploy/.env.exampleinto the Environment tab and fill inPOSTGRES_PASSWORD,APP_SECRET,AUTH_BASE_URL,FROM_ADDRESSandRESEND_API_KEY. The stack refuses to start while one of them is empty. - Add a domain for the
serverservice on port8080. Dokploy connects the service to its Traefik network; the compose file publishes no ports. - 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