Build and run
There is no public pull-by-tag registry image today. Build from this repository, then run the container:-e DATABASE_URL='postgres://…' for durable multi-replica Postgres. Without it, state lives under /data and must be on a mounted volume. For production bring-up checklists beyond this page, see docs/DEPLOY.md and docs/OPERATIONS.md in the repository.
What you need
The container
One Passport container, listening on
PORT (default 8790).Postgres
A Postgres database for durable, backed-up state that survives redeploys. Without it, state lives in a JSON file you must persist on a mounted volume.
Production posture the server enforces at boot
WhenNODE_ENV=production, Passport fails closed: a misconfigured deployment refuses to boot rather than run with plaintext secrets, open unverified signup, or mock data on a real domain. Startup exits with a named error unless all of the following hold:
PASSPORT_ENCRYPTION_KEYis set. Without it, upstream OAuth tokens and company keys would be stored in plaintext.PUBLIC_URLis set and starts withhttps://. Otherwise OAuth callbacks and CORS would trust theHostheader.PASSPORT_DEMOis explicit, eitheroff(recommended) oron.- If signup is enabled, configure either verified email or Google/GitHub identity login. With
PASSPORT_EMAIL_VERIFY=off, production becomes provider-only: typed email addresses cannot create sessions or workspaces.
Core
Persistence
Security and encryption
Key rotation. Set
PASSPORT_ENCRYPTION_KEY to the new key, move the old key into PASSPORT_ENCRYPTION_KEYS, deploy, then from the repository run cd server && npm run rekey to re-encrypt every stored secret under the new primary, then drop the old key. A value whose key is absent is left untouched, never overwritten, so nothing is lost mid-rotation.Signup and demo
Single sign-on (OIDC) fallback
Per-workspace SSO is configured in Settings (see SSO). These environment variables provide a global fallback for the single-tenant or appliance case.Connecting upstream accounts
You can also let a person sign into Passport itself with Google or GitHub by setting the
PASSPORT_LOGIN_GOOGLE_* and PASSPORT_LOGIN_GITHUB_* pairs. A provider is available only when both its client ID and secret are set.
Billing (Stripe)
LeaveSTRIPE_SECRET_KEY unset on a self-hosted appliance: with no key, every workspace gets everything unlocked and billing does not exist.
Gateway rate limits
Per-workspace and per-token caps on the gateway, plus a per-replica concurrency guard. These fail open: a rate-limiter error never blocks the gateway.Metrics, monitoring, and paging
Sentry is entirely optional for a self-hosted deployment. With both DSNs unset,
no Sentry telemetry leaves the instance.
VITE_* and the browser copy of
SENTRY_RELEASE are image-build inputs. For source maps, first run the web build
locally with SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT,
SENTRY_REPOSITORY, and the same release, then build the image without the
token. Omitting that local upload simply means browser frames have no source
maps. The entrypoint removes any platform-injected runtime token before Node
starts, and only public browser settings are compiled into assets.
When enabled, Passport sends normalized route/status/latency data, stack traces,
operational spans/logs/metrics, MCP app/tool/client identifiers and outcomes, and
opaque member/workspace IDs. Collection of query strings, cookies, authorization
headers, HTTP bodies, database statements, MCP inputs/outputs, and AI content is
disabled. Passport does not deliberately attach names or emails, and its
scrubbers redact email-like values and credential patterns found in diagnostic
text. Browser Replay is intentionally disabled because its rrweb metadata can
serialize hash/query URLs before event hooks can scrub them. Do not enable it
until URL metadata can be guaranteed safe before serialization. Sentry retention
is controlled by your Sentry plan and organization settings, independently of
Passport’s event-log retention. For staging verification of Sentry releases and
source maps, see docs/DEPLOY.md and docs/OPERATIONS.md in the repository.
Advanced tuning
These have sensible defaults and rarely need changing.Health checks:
GET /healthz returns {"ok":true} when the process is up. GET /readyz runs a cheap storage ping (SELECT 1 on Postgres) and returns 503 if storage is unreachable. When Postgres is down, Passport fails closed on policy: mutating requests fail (and failed commits return 503 with retry guidance) rather than bypass controls. Some read-only paths may still serve a stale in-memory snapshot until connectivity returns.