# ────────────────────────────────────────────────────────── # Openship — environment reference (self-hosted AND SaaS) # # cp .env.example .env && docker compose up -d --build # # The SAME file drives both modes — flip CLOUD_MODE + fill the SaaS section. # docker-compose overrides DATABASE_URL / REDIS_URL with in-cluster service # DNS, so the localhost values here are for running the apps WITHOUT Docker. # ────────────────────────────────────────────────────────── NODE_ENV=production # ─── Mode (the ONLY switch — one compose stack, env decides) ── # false = self-hosted (default, no billing) | true = SaaS (billing, metering, multi-tenant) CLOUD_MODE=false # docker (default, self-hosted) | cloud (SaaS) DEPLOY_MODE=docker # Runtime URL row (packages/core/runtime-config.ts). Leave unset for self-hosted. # For the SaaS set: OPENSHIP_TARGET=cloud-saas (app.openship.io / api.openship.io) # OPENSHIP_TARGET=local # ─── Storage (Postgres) ─────────────────────────────────── # Set DATABASE_URL → Postgres driver. Leave empty → PGlite embedded (dev only; # NOT for a multi-tenant SaaS). Compose builds this from POSTGRES_* below. DATABASE_URL=postgresql://openship:openship@localhost:5432/openship POSTGRES_USER=openship POSTGRES_PASSWORD=openship POSTGRES_DB=openship # PGLITE_DATA_DIR=/var/lib/openship/data # ─── Redis (queue + cache + rate-limit) ─────────────────── REDIS_URL=redis://localhost:6379 # Force the Redis-backed job runner / cache / rate-limiter and DISABLE the # silent in-memory fallback. Defaults ON when CLOUD_MODE=true; set true to force # it for self-hosted multi-replica too. false = auto-probe (single-box dev). OPENSHIP_REQUIRE_REDIS=true # Per-subsystem overrides (rarely needed): in-process|bullmq / memory|redis # OPENSHIP_JOB_RUNNER=bullmq # OPENSHIP_CACHE_STORE=redis # OPENSHIP_RATE_LIMIT_STORE=redis # ─── Auth (Better Auth) ─────────────────────────────────── # REQUIRED (secure, non-default) on any SaaS target. Generate: # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" BETTER_AUTH_SECRET=change-me-in-production BETTER_AUTH_URL=http://localhost:4000 # SaaS cross-subdomain SSO (must start with "." and be a parent of the API host) # BETTER_AUTH_COOKIE_DOMAIN=.openship.io # TRUSTED_ORIGINS=http://localhost:3000,http://localhost:3001 # Internal-auth token fronting trusted endpoints. REQUIRED for any non-desktop # deploy — the API REFUSES to boot without it. Generate: # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" INTERNAL_TOKEN=change-me-32-byte-random-hex # ─── OAuth login (optional) ─────────────────────────────── # GITHUB_CLIENT_ID= # GITHUB_CLIENT_SECRET= # GOOGLE_CLIENT_ID= # GOOGLE_CLIENT_SECRET= # ══════════════════════════════════════════════════════════ # SaaS-only (CLOUD_MODE=true) # ══════════════════════════════════════════════════════════ # In CLOUD_MODE the API MUST use GitHub App auth (cli/token modes are rejected # at boot). Register a GitHub App and fill these: # GITHUB_APP_ID= GITHUB_APP_SLUG=openship-io # GITHUB_PRIVATE_KEY_BASE64= # base64 of the App's .pem private key # GITHUB_WEBHOOK_SECRET= # Oblien (cloud runtime + billing). Required for cloud deploys / metering. # OBLIEN_CLIENT_ID= # OBLIEN_CLIENT_SECRET= # OBLIEN_WEBHOOK_SECRET= # HMAC for /api/billing/oblien-webhook (else 503) # Transactional email (optional) # SMTP_HOST= # SMTP_PORT=587 # SMTP_USER= # SMTP_PASS= # SMTP_FROM=Openship SYSTEM_DEBUG_LOGS=false