Configuration
Operators configure the stack with BONDERY_* names. Copy deploy/bondery/.env.example to .env — that file is generated from packages/helpers/src/env/manifest.ts (deployExample metadata). Do not hand-edit the example; change the manifest and run pnpm run env -- --write-examples.
Core secrets
| Variable | Purpose |
|---|---|
BONDERY_PRIVATE_BETTER_AUTH_SECRETS | Better Auth versioned signing secrets (version:secret, highest version first) |
BONDERY_PRIVATE_POSTGRES_PASSWORD | Postgres password (compose db service) |
BONDERY_PRIVATE_API_KEY_PEPPER | API key hashing pepper |
BONDERY_PRIVATE_REDIS_URL | redis://redis:6379 in the default stack. Stores rate-limit counters, sync wake pub/sub, WebSocket tickets (sync:ws-ticket:*), and Better Auth secondary storage (bondery:auth:* — sessions and verification records, dual-written with Postgres). |
DATABASE_URL
DATABASE_URL is the standard Postgres connection string the API uses for everything that touches the database: Prisma ORM (@bondery/db), Better Auth sessions, and the pg-boss job queue.
postgresql://postgres:<password>@db:5432/bondery| Context | Who sets it |
|---|---|
| Self-host compose | You set BONDERY_PRIVATE_POSTGRES_PASSWORD in .env; compose derives DATABASE_URL for the api service automatically — you do not need to paste the URL into .env. |
| Local development | You set DATABASE_URL in root .env.local (see Environment configuration). |
| Webapp | Does not use DATABASE_URL — it talks to the API over HTTP. |
Used in: apps/api (Prisma client, pg-boss), packages/db (migrations), and one-off migration scripts under packages/db/scripts/.
Domains
Set hostnames only:
BONDERY_INFRA_API_DOMAIN=api.example.com
BONDERY_INFRA_WEBAPP_DOMAIN=app.example.comCompose derives public https://… URLs and Traefik Host() rules. Do not set BONDERY_PUBLIC_*_URL in the stack .env unless you have a non-standard setup.
OAuth (Better Auth)
Auth runs on the API (/auth/*). The API is its own OAuth issuer (baseURL = BONDERY_PUBLIC_API_URL). Webapp, mobile, and the Chrome extension are independent OAuth 2.1 + PKCE clients.
-
Set
BONDERY_PRIVATE_AUTH_GITHUB_*andBONDERY_PRIVATE_AUTH_LINKEDIN_*. -
In GitHub / LinkedIn developer settings, callback URL:
https://<BONDERY_INFRA_API_DOMAIN>/auth/callback/github(or/linkedin) -
Generate and set values for
BONDERY_PUBLIC_WEBAPP_OAUTH_CLIENT_ID,BONDERY_PRIVATE_WEBAPP_OAUTH_CLIENT_SECRET,BONDERY_PUBLIC_OAUTH_CLIENT_ID(extension), andBONDERY_PRIVATE_WEBAPP_SESSION_SECRET(≥32 chars) — e.g.openssl rand -hex 32. These are arbitrary values you choose, not issued by anything. -
Set
BONDERY_INFRA_CHROME_EXTENSION_IDso the API allows the extension redirect URI.OAuth clients are upserted automatically when
apipre_startrunsrelease-migrate(right afterprisma migrate deploy). There is no separate registration step or session cookie required. -
Set
BONDERY_PRIVATE_PLATFORM_ADMIN_EMAILSto a comma-separated list of operator account emails. Matching users are promoted touser.role = adminwhenapipre_startrunsrelease-migrate. Optional break-glass:BONDERY_PRIVATE_PLATFORM_ADMIN_USER_IDS(comma-separated UUIDs).
See Secrets management for production secret storage and rotation runbooks.
Storage
Object storage uses SeaweedFS (S3-compatible gateway). The API uploads via private S3 credentials; browsers load public objects from BONDERY_PUBLIC_STORAGE_URL.
| Variable | Purpose |
|---|---|
BONDERY_PRIVATE_S3_ENDPOINT | Internal S3 endpoint. Compose derives http://${BONDERY_INFRA_TRAEFIK_PREFIX}-storage:8333 (do not use http://seaweedfs-s3:8333 — that DNS name collides on shared dokploy-network). Local dev: http://127.0.0.1:8333. |
BONDERY_PRIVATE_S3_REGION | S3 region label (e.g. eu-central-1) |
BONDERY_PRIVATE_S3_ACCESS_KEY_ID / BONDERY_PRIVATE_S3_SECRET_ACCESS_KEY | S3 credentials (same pair seeds the seaweedfs-s3 gateway config) |
BONDERY_PUBLIC_STORAGE_URL | Public base URL for avatar/logo reads (Traefik → storage domain in prod; http://127.0.0.1:8333 locally) |
BONDERY_INFRA_STORAGE_DOMAIN | Hostname for Traefik routing to the S3 gateway (Compose only) |
Buckets: avatars (contact photos) and linkedin-logos (cached LinkedIn company/school logos). Created and given anonymous read policy by api pre_start → ensure-storage-buckets.
On every deploy, api pre_start runs release-migrate (schema, functions, OAuth clients, platform admins) then ensure-storage-buckets before the main API process starts. See Installation and Dokploy deployment.
Local development parity
Contributors use the same variable names in root .env.local. See Environment configuration.