# ============================================================================ # Production environment for buildmymcpserver.com # Copy to .env.production on the server and fill every value marked CHANGE-ME. # Never commit the filled file — .env.production is gitignored. # # Used two ways by docker-compose.prod.yml: # 1. compose interpolation -> docker compose --env-file .env.production ... # 2. container env -> env_file: .env.production # ============================================================================ # ---- Core ---- NODE_ENV=production # ---- Postgres (the compose file owns the container) ---- POSTGRES_USER=bmm POSTGRES_PASSWORD=CHANGE-ME-strong-db-password POSTGRES_DB=bmm # ---- Host ports (loopback only — picked free on the shared box) ---- POSTGRES_PORT=5440 REDIS_PORT=6390 API_PORT=4000 WEB_PORT=4001 # ---- Connection strings ---- # api + web reach the DBs over the compose network (service names). # The generator overrides these to 127.0.0.1 (it uses host networking). DATABASE_URL=postgresql://bmm:CHANGE-ME-strong-db-password@postgres:5432/bmm REDIS_URL=redis://redis:6379 # ---- API ---- PORT=4000 # ---- Public URLs (must match the Cloudflare DNS records) ---- NEXT_PUBLIC_APP_URL=https://buildmymcpserver.com NEXT_PUBLIC_API_URL=https://api.buildmymcpserver.com # Used to build the Google OAuth redirect URI and as the JWKS origin. CONTROL_PLANE_PUBLIC_URL=https://api.buildmymcpserver.com # Reachable by generated MCP containers — must be public so they can resolve it. CONTROL_PLANE_URL=https://api.buildmymcpserver.com OAUTH_ISSUER=https://api.buildmymcpserver.com # ---- Crypto ---- # REQUIRED in production. The API refuses to boot on the all-zero placeholder. # Generate with: openssl rand -hex 32 SECRETS_ENCRYPTION_KEY=CHANGE-ME-run-openssl-rand-hex-32 # ---- Admin bootstrap (upserted idempotently on API boot) ---- ADMIN_EMAIL=CHANGE-ME-admin@example.com ADMIN_PASSWORD=CHANGE-ME-strong-admin-password ADMIN_NAME=CHANGE-ME-Admin # ---- Anthropic (empty = mock generation; set for real Claude generation) ---- ANTHROPIC_API_KEY= # ---- Google OAuth ("Continue with Google") ---- # Google Cloud Console -> APIs & Services -> Credentials -> OAuth client (Web). # Authorized redirect URI must be EXACTLY: # https://api.buildmymcpserver.com/v1/auth/google/callback GOOGLE_OAUTH_ID= GOOGLE_OAUTH_SECRET= # ---- OAuth signing keys (RS256 JWKS) ---- # Auto-generated on first boot into this dir; persisted in the bmm_keys volume. OAUTH_KEY_DIR=./keys # ---- Runner / Generator ---- # Host used in a generated server's public URL (http://RUNNER_HOST:). # Generated MCP containers bind host ports in RUNNER_PORT_RANGE_* — this range # is kept clear of every other app already running on the box. # NOTE: per-server subdomain routing through nginx is not wired yet — a # generated server is currently reachable at the host port directly. Treat # public exposure of generated servers as a follow-up before GA. See DEPLOY.md. RUNNER_HOST=buildmymcpserver.com RUNNER_PORT_RANGE_START=4400 RUNNER_PORT_RANGE_END=4900 # ---- Stripe (billing) ---- # Secret key (server-side only — NEVER expose). From Stripe Dashboard → Developers → API keys. STRIPE_SECRET_KEY=CHANGE-ME-sk_live_... # Publishable key (safe to expose). Used by the embedded in-app checkout. STRIPE_PUBLISHABLE_KEY=CHANGE-ME-pk_live_... # Same publishable key, exposed to the web client bundle at BUILD time (the web # image is rebuilt by the deploy, so this must be set before deploying or the # in-app checkout shows "not configured"). Keep it identical to STRIPE_PUBLISHABLE_KEY. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=CHANGE-ME-pk_live_... # Webhook signing secret — from the endpoint you create at /v1/billing/webhook. STRIPE_WEBHOOK_SECRET=CHANGE-ME-whsec_... # Price IDs (price_… not prod_…) from each product's pricing in the Dashboard. STRIPE_PRICE_PRO_MONTHLY=CHANGE-ME-price_... STRIPE_PRICE_PRO_YEARLY=CHANGE-ME-price_... STRIPE_PRICE_TEAM_MONTHLY=CHANGE-ME-price_... STRIPE_PRICE_TEAM_YEARLY=CHANGE-ME-price_... # ---- Observability (optional) ---- SENTRY_DSN= OTEL_EXPORTER_OTLP_ENDPOINT=