Getting Started
Environment variables
V03 deploy identity, secret-store references, commerce, Push, and release configuration.
.env.example is the canonical variable list. Production values belong in the deployment secret store and must never be committed.
Domains and identity
The supported VPS deployment requires DOMAIN, ADMIN_DOMAIN,
COMMERCE_DEMO_DOMAIN, EDUCATION_DEMO_DOMAIN, and
HEALTH_DEMO_DOMAIN. Host Caddy separates public and admin surfaces.
BUILD_ID identifies the immutable deployed revision.
Set NEXT_PUBLIC_SITE_URL, NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_WEB_URL,
and BETTER_AUTH_URL explicitly for both local and production execution.
Database and authentication
MIGRATION_DATABASE_URL belongs only to the one-shot release job. The
application receives the restricted runtime DATABASE_URL; it cannot alter
schema or bypass forced row-level security. Compose-specific password variables
remain only for the unverified optional adapter and are not part of the V03
deployment promise.
Use independent random values for BETTER_AUTH_SECRET, DOWNLOAD_TOKEN_SECRET, and AWP_API_KEY. The bootstrap API key should be replaced by scoped keys from /admin/api-keys after setup.
Model gateway
AI_PROVIDER_API_KEY is read only through an allowlisted CredentialBinding such as env:AI_PROVIDER_API_KEY. ALLOWED_SECRET_REFS controls which references may resolve. Provider endpoints and model policies are versioned Site configuration, not ad hoc environment switches.
No credential value is stored in Postgres, returned to the browser, included in an audit record, or copied into a buyer release.
Browser worker
BROWSER_WORKER_TOKEN authenticates internal requests and must contain at least 32 characters. BROWSER_WORKER_URL and BROWSER_WORKER_ALLOWED_SERVICE_HOSTS identify the internal service. Keep BROWSER_ALLOW_HTTP=false in production.
Turnstile, votes, and Web Push
NEXT_PUBLIC_TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY protect voting and subscription actions. The server verifies action and Host and uses Cloudflare's idempotency key for one bounded retry.
VOTER_HMAC_SECRET creates rotating, monthly pseudonymous voter identifiers. It is not an analytics identifier.
Web Push needs NEXT_PUBLIC_VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT, and a 32-byte PUSH_SUBSCRIPTION_ENCRYPTION_KEY. PUSH_ENDPOINT_HOST_ALLOWLIST adds explicitly trusted providers to the built-in FCM, Mozilla, Apple, and Windows allowlist.
R2 and Polar
R2_* variables provide bucket-scoped public media storage. The separate
R2_RELEASE_* variables provide bucket-scoped private source delivery and do
not fall back to the media credentials. Polar variables configure checkout and
webhook verification. A checkout response never grants access; only a verified
paid webhook creates an entitlement and fulfillment event.
AWP_BACKUP_* and R2_BACKUP_* belong only to the hardened one-shot backup
service. They are never passed to PM2. The database URL uses a dedicated
read-only BYPASSRLS backup role, the 32-byte base64 key encrypts every dump
with AES-256-GCM, and the R2 token is limited to the private backup bucket and
the production host IP.
Release descriptor
RELEASE_VERSION, commit SHA, manifest hash, artifact hash, size, SBOM hash, AIBOM hash, storage key, and signature reference describe one immutable buyer artifact. They are produced by release assembly and signing; do not type guessed values into production.
Optional observability
Sentry, Better Stack, GA4, and Upstash variables are optional. Their absence must not weaken authentication, tenant isolation, webhook verification, audit logging, or release gates.