Production Setup
Configure domains, TLS, storage, and critical environment variables for production.
Required Environment Variables
Set these in apps/server/.env:
DATABASE_URL
BETTER_AUTH_SECRET
BETTER_AUTH_URL
CORS_ORIGINS
BETTER_AUTH_COOKIE_DOMAIN (required when app and API use different subdomains)
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET
ENABLE_PAYMENTS (false)
STORAGE_BUCKET
STORAGE_ACCESS_KEY_ID
STORAGE_SECRET_ACCESS_KEY
STORAGE_REGION (required when STORAGE_ENDPOINT is unset)
STORAGE_ENDPOINT (recommended for R2/custom S3 endpoints)Set these in apps/web/.env:
NEXT_PUBLIC_APP_URL
NEXT_PUBLIC_SERVER_URLGoogle OAuth is currently the only login method. Keep
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETconfigured.For self-hosting, set
ENABLE_PAYMENTS=falseand ignorePOLAR_*.
Notes:
DATABASE_URLis the source of truth for the app.POSTGRES_*vars are only for configuring the bundled Compose Postgres service.- Root
.envis Docker-only (ports and bundled Postgres init).
Recommended Security
These settings are not required for self-hosting, but they are recommended:
CAPTURE_SUBMIT_TOKEN_SECRET
UPSTASH_REDIS_REST_URL
UPSTASH_REDIS_REST_TOKEN
TURNSTILE_SITE_KEY
TURNSTILE_SECRET_KEYWhat each one does:
CAPTURE_SUBMIT_TOKEN_SECRETenables signed short-lived capture submit tokens.- Upstash Redis enables rate limiting and one-time submit token replay protection.
- Turnstile enables an anti-bot challenge for capture submissions.
Without them, self-hosted instances still work, but capture submission protections are reduced.
Reverse Proxy and HTTPS
Recommended layout:
- Public traffic -> reverse proxy (
80/443) - Proxy ->
web:3001 - API reachable via public URL (for example
https://api.example.com)
Container routing note:
- In the default compose file,
webandserverrun as two containers. websharesservernetworking, so server-side calls tolocalhost:3000work without extra internal URL variables.
If using a separate API domain:
NEXT_PUBLIC_SERVER_URL=https://api.example.com
BETTER_AUTH_URL=https://api.example.com
CORS_ORIGINS=https://app.example.com,https://admin.example.com
BETTER_AUTH_COOKIE_DOMAIN=example.comStorage
- Cloud storage is mandatory in all environments.
- Configure
STORAGE_BUCKET,STORAGE_ACCESS_KEY_ID, andSTORAGE_SECRET_ACCESS_KEY. - Use
STORAGE_REGIONfor AWS S3. - Use
STORAGE_ENDPOINTfor Cloudflare R2/custom S3-compatible storage. - Set
STORAGE_PUBLIC_URLif you want stable public URLs instead of signed URLs.
Data Durability
Compose volume persistence:
- PostgreSQL data in
postgres_data
Also implement off-host backups and periodic restore tests.