# ═══════════════════════════════════════════════════════════════════════════════ # $APP_NAME — Environment Variables Template (PRODUCTION / SELF-HOSTED) # Copy to .env and fill in all CHANGE_ME values before deploying. # # Self-hosted setup (recommended): # 1. cp .env-production .env # 2. Fill in every CHANGE_ME value below # 3. docker compose up -d (see docker-compose.yml) # — or, without Docker: npm install && npm start # (or: pm2 start server.js --name $APP_NAME, with Nginx in front) # # For local development, use .env-development instead (memory cache, no # Docker/Redis/TLS required). # # Generate random secrets with: # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" # ═══════════════════════════════════════════════════════════════════════════════ # ── App ─────────────────────────────────────────────────────────────────────── APP_NAME=starr NODE_ENV=production ORIGIN_GUARD_DISABLED=false # set to true in dev to allow Postman/curl (ignored in production) PORT=3024 APP_URL=https://api.yourdomain.com APP_LOGO_URL=https://your-cdn.com/logo.png FRONTEND_URL=https://yourdomain.com # ── Database (PostgreSQL / CockroachDB) ────────────────────────────────────── # For self-hosted PostgreSQL: DB_HOST=127.0.0.1 DB_PORT=5432 # For CockroachDB serverless: DB_HOST=.cockroachlabs.cloud DB_PORT=26257 DB_HOST=CHANGE_ME DB_PORT=5432 DB_NAME=CHANGE_ME DB_USER=CHANGE_ME DB_PASSWORD=CHANGE_ME # DB_SSL=false → disable SSL (use when PostgreSQL is on the same Docker network) # DB_SSL=true → enable SSL with rejectUnauthorized=false (default — for managed DBs) DB_SSL=true # ── Cache driver ────────────────────────────────────────────────────────────── # Controls the store used by rate limiters and the CSRF session. # # memory → no Redis required. Safe for local development (single process). # Rate limit counters reset on restart; CSRF sessions are in-process. # Set this in your local .env — no Redis installation needed. # # redis → Redis or Valkey required. Use in production (multi-process safe, # survives restarts). Requires REDIS_URL below. # CACHE_DRIVER=redis # ── Redis / Valkey URL ──────────────────────────────────────────────────────── # Only read when CACHE_DRIVER=redis. # Valkey is a drop-in Redis replacement — fully supported. # Arch Linux / Valkey default port: 6380 # Ubuntu / Debian / macOS Redis default port: 6379 # Check your port: systemctl status valkey | grep "valkey-server" # Managed TLS example: rediss://:@:6380 REDIS_URL=redis://127.0.0.1:6379 # ── JWT ─────────────────────────────────────────────────────────────────────── # Generate each secret independently — never reuse across fields. JWT_SECRET=CHANGE_ME_32_BYTE_HEX MEDIA_JWT_SECRET=CHANGE_ME_32_BYTE_HEX JWT_EXPIRES_IN=15m JWT_REFRESH_SECRET=CHANGE_ME_32_BYTE_HEX JWT_REFRESH_EXPIRES_IN=7d # ── CSRF & Cookies ──────────────────────────────────────────────────────────── SESSION_SECRET=CHANGE_ME_32_BYTE_HEX # ── Google OAuth ────────────────────────────────────────────────────────────── # console.cloud.google.com → Credentials → OAuth 2.0 Client ID # Add https://api.yourdomain.com/api/auth/google/callback to Authorized redirect URIs GOOGLE_CLIENT_ID=CHANGE_ME GOOGLE_CLIENT_SECRET=CHANGE_ME GOOGLE_CALLBACK_URL=https://api.yourdomain.com/api/auth/google/callback # ── PayPal ──────────────────────────────────────────────────────────────────── # Switch PAYPAL_ENV from "sandbox" to "live" when ready for real payments. # Live credentials come from developer.paypal.com → My Apps & Credentials → Live tab. PAYPAL_CLIENT_ID=CHANGE_ME PAYPAL_CLIENT_SECRET=CHANGE_ME PAYPAL_ENV=live # ── Email (Gmail API — OAuth2, over HTTPS) ──────────────────────────────────── # Raw SMTP (port 25/465/587) is blocked outbound on Render and several other # PaaS hosts, so sending goes through the Gmail REST API over HTTPS instead. # Reuses the same OAuth client as GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET above — # just enable the Gmail API on that project, then run: # node scripts/get_gmail_refresh_token.js # and paste the printed value below. GMAIL_REFRESH_TOKEN=CHANGE_ME EMAIL_FROM=CHANGE_ME@gmail.com OTP_EXPIRY_MINUTES=10 # ── S3-compatible Storage (Garage self-hosted) ──────────────────────────────── # Garage is bundled in docker-compose.yml — no separate install needed. # # Docker setup: S3_ENDPOINT=http://garage:3900 (use the service name) # Bare-metal: S3_ENDPOINT=http://127.0.0.1:3900 # # S3_PUBLIC_URL: public-facing URL served by your reverse proxy # (e.g. Caddy/Nginx → https://cdn.yourdomain.com → garage:3900) # # GARAGE_RPC_SECRET: shared secret for Garage RPC. # Generate with: openssl rand -hex 32 S3_ENDPOINT=http://garage:3900 S3_REGION=garage S3_ACCESS_KEY=CHANGE_ME S3_SECRET_KEY=CHANGE_ME S3_BUCKET=CHANGE_ME S3_PUBLIC_URL=https://cdn.yourdomain.com GARAGE_RPC_SECRET=CHANGE_ME_32_BYTE_HEX # ── Chibisafe (optional — used alongside S3 for some asset types) ───────────── # Set CHIBISAFE_BASE_URL to the public domain pointing to your Chibisafe instance. CHIBISAFE_BASE_URL=https://files.yourdomain.com CHIBISAFE_API_KEY=CHANGE_ME CHIBISAFE_ALBUM_AVATARS=CHANGE_ME_UUID CHIBISAFE_ALBUM_IMAGES=CHANGE_ME_UUID CHIBISAFE_ALBUM_VIDEOS=CHANGE_ME_UUID CHIBISAFE_ALBUM_THUMBNAILS=CHANGE_ME_UUID CHIBISAFE_ALBUM_DOCUMENTS=CHANGE_ME_UUID CHIBISAFE_ALBUM_ARCHIVED=CHANGE_ME_UUID # ── MarkItDown (document-import PDF/PPTX -> Markdown sidecar) ──────────────── # Lives in the separate chibistar/ stack, not this one — not reachable by # Docker service name. # # Self-hosted via this repo's docker-compose.yml, on the SAME machine as # chibistar: reach it via host.docker.internal (see docker-compose.yml's # extra_hosts on `backend`), which resolves to the host running chibistar's # markitdown container (published to 127.0.0.1:8000 there). MARKITDOWN_BASE_URL=http://host.docker.internal:8000 # # Deployed elsewhere (e.g. Render) — no shared network with chibistar, so # use the public hostname instead (Cloudflare Tunnel, see # chibistar/docker-compose.yml's markitdown-cloudflared service and # chibistar/Caddyfile's @markitdown matcher — the zrok share, # markitdownstarr.share.zrok.io, is kept alongside as a fallback): # MARKITDOWN_BASE_URL=https://santa-monica.space # # Required in both cases — /convert checks this on every request since it's # reachable publicly, not just over loopback/the Docker network. MARKITDOWN_SHARED_SECRET=CHANGE_ME # ── CORS ────────────────────────────────────────────────────────────────────── # Comma-separated list of allowed origins. Must match FRONTEND_URL exactly. ALLOWED_ORIGINS=https://yourdomain.com