This file is a brief overview for Docker-based self-hosting.
For the detailed, up-to-date guide, see:
Docker uses separate env files (not a root .env):
| File | Services |
|---|---|
packages/db/.env |
migrator, seeder |
apps/app/.env |
app |
apps/portal/.env |
portal |
For a functional deployment:
- Database:
DATABASE_URLin all three env files - Auth:
AUTH_SECRET,SECRET_KEY,BETTER_AUTH_URL,NEXT_PUBLIC_BETTER_AUTH_URL(app);BETTER_AUTH_SECRET(portal) - Email:
RESEND_API_KEYin app and portal - Workflows:
TRIGGER_SECRET_KEYin app - Misc:
REVALIDATION_SECRET,NEXT_PUBLIC_PORTAL_URLin app
Self-Hosted Mode:
- Set
NEXT_PUBLIC_SELF_HOSTED=trueinapps/app/.envto mark the instance as self-hosted - When enabled, organizations are automatically approved and bypass the payment/booking flow
STRIPE_SECRET_KEYis not required for self-hosted instances
- Docker Desktop or Docker Engine
- External PostgreSQL 14+ with SSL
- Resend account for email
- Trigger.dev account for workflows
# 1. Create env files from examples
cp packages/db/.env.example packages/db/.env
cp apps/app/.env.example apps/app/.env
cp apps/portal/.env.example apps/portal/.env
# Edit each with your production values
# 2. Export build args
export BETTER_AUTH_URL="https://app.yourdomain.com"
export BETTER_AUTH_URL_PORTAL="https://portal.yourdomain.com"
# 3. Build
docker compose build --no-cache
# 4. Migrate & seed
docker compose run --rm migrator
docker compose run --rm seeder
# 5. Start
docker compose up -d app portalDeploy tasks from your workstation (not inside Docker):
cd apps/app
bunx trigger.dev@latest login
bunx trigger.dev@latest deployView logs to debug missing env vars:
docker compose logs app
docker compose logs portalThe Dockerfile sets SKIP_ENV_VALIDATION=true at build time, so missing variables only cause errors at runtime.
See the full troubleshooting guide for common issues.