Files
warmbly/deploy/config/env.example
T
2026-07-20 09:56:47 +02:00

168 lines
7.2 KiB
Plaintext

# ============================================
# Warmbly environment reference
# ============================================
# Defaults are no-cloud: with just the four secrets in the "Required" block set,
# Warmbly runs with no AWS, GCP, Stripe, or Kafka. Each subsystem is a provider
# switch — flip one to opt into a cloud service.
#
# Config priority: env var first, then AWS SSM/Secrets Manager (only when
# AWS_CONFIG_ENABLED=true).
# ============================================
# === Required ===
APP_ENV=dev # dev | production
# JWT / session signing. Min 32 chars. MUST match the realtime service JWT_SECRET.
AUTH_SECRET=change-me-min-32-characters-long
# 64 hex chars (32 bytes). Seals mailbox SMTP/IMAP credentials at rest.
# BACK IT UP — losing it makes connected mailboxes unrecoverable. `openssl rand -hex 32`
CREDENTIALS_ENCRYPTION_KEY=
# Shared token for the backend internal API (workers + tracking use it).
INTERNAL_API_TOKEN=change-me-internal-token
PRIMARY_DB=postgres://warmbly:warmbly@localhost:5432/warmbly_dev?sslmode=disable
REDIS=redis://localhost:6379
# === Provider switches (no-cloud defaults) ===
AWS_CONFIG_ENABLED=false # true => read secrets from AWS SSM/Secrets Manager
# Event bus. nats (default): one small JetStream binary. kafka: build the images
# with GO_TAGS=kafka / CARGO_FEATURES=kafka and set KAFKA_* below.
EVENTBUS_PROVIDER=nats
NATS_URL=nats://localhost:4222
# NATS_STREAM_NAME=warmbly
# NATS_SUBJECT_PREFIX=warmbly
# Serialization. json is required with NATS and wherever workers run. avro is
# only for a Kafka + Schema Registry deployment.
CODEC_PROVIDER=json
# Encryption root key. local (default): AES master key below. aws: AWS KMS.
KMS_PROVIDER=local
# base64 32 bytes. BACK IT UP — losing it is unrecoverable. `make gen-key`
KMS_LOCAL_MASTER_KEY=
# KMS_LOCAL_MASTER_KEY_FILE=/run/secrets/kms_master_key # alternative to the inline key
# KMS_AWS_KEY_ID=alias/warmbly # when KMS_PROVIDER=aws
# Blob storage. filesystem (default): a local dir. s3: any S3-compatible store.
BLOB_PROVIDER=filesystem
BLOB_FS_ROOT=/data/blobs # shared between backend + workers (same host / shared volume)
# Public URL base for avatars/logos served by the backend's /public route.
BLOB_PUBLIC_BASE_URL=http://localhost:8080/public
# For BLOB_PROVIDER=s3 (AWS / MinIO / R2 / B2):
# BLOB_BUCKET=warmbly
# AWS_ENDPOINT_URL_S3=http://minio:9000 # non-AWS endpoint
# AWS_REGION=us-east-1
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# Delayed tasks (campaign ticks, scheduled sends). local (default): an in-process
# Postgres poller — no external service. gcloud: GCP Cloud Tasks.
TASKS_PROVIDER=local
# TASKS_LOCAL_POLL_INTERVAL=1s
# When TASKS_PROVIDER=gcloud, also set:
# CLOUD_TASKS_QUEUE_NAME=projects/<p>/locations/<l>/queues/<q>
# CLOUD_TASKS_WEBHOOK_URL=https://<api-host>/webhook/email
# GOOGLE_APPLICATION_CREDENTIALS_JSON=<service-account-email>
# Billing. none (default): no Stripe, every feature unlocked, no trial expiry.
# stripe: wire the Stripe integration (keys below required).
BILLING_PROVIDER=none
# STRIPE_SECRET_KEY=
# STRIPE_WEBHOOK_SECRET=
# STRIPE_PUBLISHABLE_KEY=
# Captcha. Auto-off when TURNSTILE_SECRET is unset; set CAPTCHA_PROVIDER=turnstile
# + TURNSTILE_SECRET to require Cloudflare Turnstile on auth endpoints.
# CAPTCHA_PROVIDER=none
# TURNSTILE_SECRET=
# === Backend API ===
API_HOST=0.0.0.0:8080 # binds all interfaces already
GIN_MODE=release # debug | release
# With the shipped docker-compose.yml, set PUBLIC_HOST to your LAN IP or domain
# and APP_URL / CORS_ALLOW_ORIGINS / WEBSOCKET_URL / TRACKING_DOMAIN / the VITE_*
# frontend URLs all derive from it. Set them explicitly if you're not using that
# compose (e.g. behind a reverse proxy on https://your-domain).
# PUBLIC_HOST=192.168.1.50
APP_URL=http://localhost:5173
CORS_ALLOW_ORIGINS=http://localhost:5173,http://localhost:5174
WEBSOCKET_URL=ws://localhost:4000/socket/websocket
ENCRYPTED_KEYS_PROVIDER=postgres # backend/consumer: postgres; workers: http (below)
GEODB_PATH=/app/data/GeoLite2-City.mmdb # optional in dev
# === Mailbox connections ===
# Gmail mailboxes need YOUR Google Cloud OAuth client (a "Web application" client)
# with authorized redirect URI <API_HOST>/addresses/google/callback. Set on the
# backend AND every worker. Leave unset to connect mailboxes only via SMTP/IMAP.
BOX_GOOGLE_CLIENT_ID=
BOX_GOOGLE_CLIENT_SECRET=
# Microsoft 365 / Outlook OAuth client (redirect <API_HOST>/addresses/outlook/callback):
BOX_OUTLOOK_CLIENT_ID=
BOX_OUTLOOK_CLIENT_SECRET=
# === Social sign-in (all optional; email+password / passkeys work standalone) ===
# GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET / GOOGLE_REDIRECT_URI are the LOGIN client,
# separate from the BOX_GOOGLE_* mailbox client above.
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# GOOGLE_REDIRECT_URI=
# GOOGLE_IOS_CLIENT_ID=
# APPLE_APP_ID=
# APPLE_TEAM_ID=
# APPLE_KEY_ID=
# APPLE_KEY_SECRET=
# Passkeys (WebAuthn): derived from APP_URL when unset. Changing the RP ID
# invalidates enrolled passkeys, so keep it stable per deployment.
# WEBAUTHN_RP_ID=app.example.com
# WEBAUTHN_RP_ORIGINS=https://app.example.com
# === Worker (each worker process) ===
# Workers hold no relational DB; they reach DEKs over the backend internal API.
# ENCRYPTED_KEYS_PROVIDER=http
# ENCRYPTED_KEYS_BACKEND_URL=http://backend:8080
# ENCRYPTED_KEYS_WORKER_TOKEN=<same as INTERNAL_API_TOKEN>
# WORKER_ID=<uuid> # stable identity; otherwise derived from hostname
# === Notification email (outbound platform mail) ===
EMAIL_NAME=Warmbly
EMAIL_ADDRESS=noreply@example.com
TRACKING_DOMAIN=localhost:3000
SMTP_HOST=mailpit # a real SMTP relay in production
SMTP_PORT=1025
# === Tracking service (open/click) ===
TRACKING_HOST=0.0.0.0
TRACKING_PORT=3000
# Resolves opaque /c/<id> click tickets via the backend internal API.
# BACKEND_INTERNAL_URL=http://backend:8080
TRACKING_RATE_LIMIT_PER_MIN=300
# === Realtime service (Elixir/Phoenix) ===
PHX_HOST=localhost
PORT=4000
JWT_SECRET=change-me-min-32-characters-long # MUST equal the backend AUTH_SECRET
SECRET_KEY_BASE=change-me-phoenix-secret-key-base-min-64-characters-long
DATABASE_URL=postgres://warmbly:warmbly@localhost:5432/warmbly_dev?sslmode=disable
REDIS_URL=redis://localhost:6379
# Realtime transport. false (default): Redis bridge, no cloud. Read identically by
# backend, consumer, and realtime — never set true on one side only.
PUBSUB_ENABLED=false
CHECK_ORIGIN=false
# When PUBSUB_ENABLED=true (Google Pub/Sub): also set GCP_PROJECT_ID +
# GOOGLE_APPLICATION_CREDENTIALS_JSON on every service.
# GCP_PROJECT_ID=
# === AI provider (optional; omit all to run with AI features off) ===
# Set on the backend AND consumer. Self-host bills your provider directly, so the
# credit ledger is bypassed (unlimited) when BILLING_PROVIDER=none.
# AI_PROVIDER= # openai | openrouter | groq | ollama | anthropic | custom
# AI_API_KEY=
# AI_MODEL=
# AI_BASE_URL= # required for custom
# SEARCH_PROVIDER= # optional web-search tool
# SEARCH_API_URL=
# SEARCH_API_KEY=
# === Observability (all optional) ===
# SENTRY_DSN=
# LOG_DISCORD_WEBHOOK_URL=