# ╔══════════════════════════════════════════════════════════════════════════════╗ # ║ Rebase Environment Configuration ║ # ║ Copy this file to .env and fill in the values ║ # ╚══════════════════════════════════════════════════════════════════════════════╝ # ── Database ────────────────────────────────────────────────────────────────── # Database connection string (required) # You can use PostgreSQL (postgresql://) or MongoDB (mongodb:// or mongodb+srv://). # The backend will automatically detect the database type. # sslmode=disable matches the local docker-compose database, which has no TLS; # schema tooling (atlas) would otherwise default to requiring SSL. Remove it # when pointing at a managed/cloud database. DATABASE_URL=postgresql://rebase_app:changeme@localhost:5432/rebase?options=-c%20search_path%3Dpublic&sslmode=disable # DATABASE_URL=mongodb://localhost:27017/rebase # # Seeing "SSL is not enabled on the server"? Something in your environment # asks for SSL — almost always a global PGSSLMODE=require # (set once for a cloud database, then inherited by every local project), or an # sslmode=require copied in with a connection string. # # Prefer unsetting PGSSLMODE for this project. Rebase deliberately does not # downgrade SSL for you when you have asked for it, not even on localhost: # quietly ignoring a security setting is worse than a clear failure. To opt out # explicitly for a local database, say so: # DATABASE_URL=postgresql://rebase_app:changeme@localhost:5432/rebase?options=-c%20search_path%3Dpublic&sslmode=disable # Separate admin connection string for migrations and schema operations (optional) # Falls back to DATABASE_URL if not set # ADMIN_CONNECTION_STRING=postgresql://postgres:your-password@localhost:5432/rebase # Connection pool tuning (optional — sensible defaults are built-in) # DB_POOL_MAX=20 # DB_POOL_IDLE_TIMEOUT=30000 # DB_POOL_CONNECT_TIMEOUT=10000 # ── Server ──────────────────────────────────────────────────────────────────── # Used by `rebase start` (production). `rebase dev` IGNORES this and binds a # port derived from the project path, so several projects can run at once — # trust the URL `rebase dev` prints, or pin one with `rebase dev --port 3001`. PORT=3001 NODE_ENV=development # Allow connecting to localhost / 127.0.0.1 in production mode (for local testing of prod builds) # ALLOW_LOCALHOST_IN_PRODUCTION=false # ── Logging ─────────────────────────────────────────────────────────────────── # Levels: error, warn, info, debug LOG_LEVEL=info # ── JWT Authentication (required) ───────────────────────────────────────────── # Must be at least 32 characters. Generate with: # node -e "console.log(require('crypto').randomBytes(48).toString('base64'))" JWT_SECRET= JWT_ACCESS_EXPIRES_IN=1h JWT_REFRESH_EXPIRES_IN=30d # ── Registration ────────────────────────────────────────────────────────────── ALLOW_REGISTRATION=true # ── Email (optional — required for password reset / verification) ───────────── # SMTP_HOST=smtp.example.com # SMTP_PORT=587 # SMTP_SECURE=false # SMTP_USER= # SMTP_PASS= # SMTP_FROM=noreply@yourapp.com # SMTP_NAME= # APP_NAME=Your App Name # Logo atop the default email templates. Absolute http(s) PNG/JPG only — # mail clients strip SVG and block data: URIs. # EMAIL_LOGO_URL=https://yourapp.com/logo.png # ── URLs ────────────────────────────────────────────────────────────────────── # Canonical frontend URL (used in password-reset / verification emails) FRONTEND_URL=http://localhost:5173 # Allowed CORS origins in production (comma-separated) # CORS_ORIGINS=https://yourdomain.com # ── OAuth Providers (optional — uncomment to enable) ────────────────────────── # GOOGLE_CLIENT_ID= # ── Frontend (Vite) ────────────────────────────────────────────────────────── # Leave this EMPTY unless your API lives on a different origin than the site. # # Empty means "same origin as the page", which is what a deployed build wants: # the frontend is served by the backend it talks to, and a same-origin bundle # keeps working when you add a custom domain. A value here is baked in at BUILD # time — `vite build` reads this file (frontend/vite.config.ts sets # `envDir: ".."`), so a stray `http://localhost:3001` follows the bundle into # production and points every request at the machine that ran the build. # # In dev you need nothing here either: `rebase dev` injects the backend port it # actually bound, overriding this — see the PORT note above. VITE_API_URL= # VITE_GOOGLE_CLIENT_ID= # ── Storage ─────────────────────────────────────────────────────────────────── # Set STORAGE_TYPE to choose a storage backend. Default is "local" (filesystem). # # Supported values: local, s3, gcs # # In production, "local" means NO file storage: uploads answer # 501 STORAGE_NOT_CONFIGURED instead of landing on a container filesystem that # is erased on the next redeploy. Configure a bucket below to switch it on, or # set FORCE_LOCAL_STORAGE=true if a durable volume really is mounted at # STORAGE_PATH (the generated docker-compose.yml does exactly that). # # STORAGE_TYPE=local # --- Local filesystem (default — great for dev and single-server deployments) -- # STORAGE_PATH=./uploads # FORCE_LOCAL_STORAGE=true # Only with a durable volume mounted at STORAGE_PATH # --- S3-compatible (AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage, Backblaze B2) --- # STORAGE_TYPE=s3 # S3_BUCKET=my-app-uploads # S3_REGION=us-east-1 # S3_ACCESS_KEY_ID= # S3_SECRET_ACCESS_KEY= # S3_ENDPOINT= # Required for R2, MinIO, Hetzner (e.g. https://fsn1.your-objectstorage.com) # S3_FORCE_PATH_STYLE= # Set to "true" for MinIO # --- GCS via S3 interop (Cloud Run, GKE, etc.) --- # Use GCS HMAC keys: https://cloud.google.com/storage/docs/interoperability # STORAGE_TYPE=s3 # S3_BUCKET=my-gcs-bucket # S3_ENDPOINT=https://storage.googleapis.com # S3_ACCESS_KEY_ID=GOOG... # HMAC access key # S3_SECRET_ACCESS_KEY=... # HMAC secret # --- Native GCS (Google Cloud Storage, Firebase Storage) --- # STORAGE_TYPE=gcs # GCS_BUCKET=my-gcs-bucket # GCS_PROJECT_ID= # Optional — auto-detected from credentials # GCS_KEY_FILENAME= # Omit on GCP: Workload Identity/ADC supplies credentials # # For other providers (Azure Blob, etc.), implement the StorageController # interface and pass it directly in your backend config. # --- Several buckets ------------------------------------------------------ # Declare them in rebase.json, then configure each from the SAME variable names # carrying its own suffix. The default source takes no suffix, so everything # above keeps working and a single-bucket project declares nothing. # # rebase.json: "storage": { "media": { "engine": "s3" } } # # STORAGE_TYPE__MEDIA=s3 # S3_BUCKET__MEDIA=my-app-media # S3_ACCESS_KEY_ID__MEDIA= # S3_SECRET_ACCESS_KEY__MEDIA= # # The separator is a DOUBLE underscore: a single one would collide with real # variable names (S3_BUCKET_NAME would parse as bucket "name"). # ── Backups (optional) ──────────────────────────────────────────────────────── # Manual backups: `rebase db backup --out ./backups` (or an s3://… URL). # Scheduled backups: set BACKUP_SCHEDULE and add a cron file in backend/crons # that default-exports createBackupCron (from @rebasepro/server-postgres). # Backups contain secrets & PII — use a PRIVATE destination with encryption-at-rest. # BACKUP_SCHEDULE=0 3 * * * # cron expression; unset ⇒ scheduled backups off # BACKUP_DESTINATION=./backups # local path, or s3://bucket/prefix / gs://bucket/prefix # BACKUP_RETENTION_DAYS=14 # delete backups older than N days (unset/0 ⇒ keep all) # BACKUP_KEEP_MINIMUM=3 # always retain at least N most-recent backups # PG_DUMP_PATH= # override pg_dump binary (must match server major version) # PG_RESTORE_PATH= # override pg_restore binary # ── Admin Service Key (optional) ────────────────────────────────────────────── # When set, scripts authenticate with: Authorization: Bearer # Generate with: node -e "console.log(require('crypto').randomBytes(48).toString('base64'))" # REBASE_SERVICE_KEY= # Disable switching to database-level roles (e.g. 'admin') for Studio SQL execution (optional) # Falls back to false. Useful for databases with application-only roles or managed setups. # DISABLE_DB_ROLE_SWITCHING=true