mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-18 16:01:18 +00:00
259 lines
12 KiB
Plaintext
259 lines
12 KiB
Plaintext
# ============================================
|
|
# Warmbly environment reference
|
|
# ============================================
|
|
# You do not need this file to start. `make up` boots the whole platform with
|
|
# no .env at all and prints a link to claim the instance. Copy this file when
|
|
# you are ready to run something other people can reach.
|
|
#
|
|
# Defaults are no-cloud: with just the 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 ===
|
|
# dev | prod. dev allows the published default secrets, so set prod for
|
|
# anything other people can reach. prod needs no cloud account: error reporting
|
|
# and GeoIP are used when configured and skipped with a logged note when not.
|
|
APP_ENV=prod
|
|
# cloud | self_hosted. Picks the auth defaults (login code, signup lockdown,
|
|
# email verification); each stays individually overridable below.
|
|
DEPLOYMENT_MODE=self_hosted
|
|
# 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. All three keys below are then required —
|
|
# the backend exits at boot if any one of them is missing.
|
|
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
|
|
# API_PUBLIC_URL is the compose input for the API base the frontends and blob
|
|
# URLs use (falls back to http://<PUBLIC_HOST>:8080); set it explicitly behind
|
|
# a reverse proxy. ENV_LABEL labels the admin panel (compose: WARMBLY_ENV_LABEL).
|
|
# API_PUBLIC_URL=https://api.example.com
|
|
# ENV_LABEL=production
|
|
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 everywhere; missing = no location labels
|
|
|
|
# === 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
|
|
|
|
# === Platform email (login codes, resets, invitations, digests) ===
|
|
#
|
|
# MAIL_TRANSPORT is the primary switch: smtp | log | ses.
|
|
#
|
|
# log — writes every message to the backend logs and delivers nothing. The
|
|
# default for a fresh install so first login works with no relay.
|
|
# smtp — a real submission relay. Set SMTP_HOST plus the credentials below.
|
|
# ses — AWS SES; needs AWS credentials and a verified identity.
|
|
MAIL_TRANSPORT=log
|
|
EMAIL_NAME=Warmbly
|
|
EMAIL_ADDRESS=noreply@example.com
|
|
TRACKING_DOMAIN=localhost:3000
|
|
|
|
# SMTP_SECURITY is starttls | tls | none. starttls is submission on 587 and the
|
|
# right answer for almost every provider; tls is implicit TLS on 465; none is
|
|
# cleartext and only legitimate for a sink on the same host. The port defaults
|
|
# per mode, so setting either one alone is enough.
|
|
#
|
|
# Credentials are never sent over an unencrypted connection.
|
|
# SMTP_HOST=smtp.example.com
|
|
# SMTP_PORT=587
|
|
# SMTP_USERNAME=
|
|
# SMTP_PASSWORD=
|
|
# SMTP_SECURITY=starttls
|
|
# SMTP_AUTH=auto # auto | plain | login | cram-md5 | none
|
|
# SMTP_EHLO_NAME= # defaults to the sender domain
|
|
# SMTP_TLS_INSECURE_SKIP_VERIFY=false # only for a relay with a private CA
|
|
|
|
# === Auth policy ===
|
|
#
|
|
# AUTH_LOGIN_CODE: always | new_device | off. Self-host defaults to off, so a
|
|
# login never depends on outbound mail. Registration and password reset still
|
|
# use emailed codes, which is what NIST SP 800-63B permits email for.
|
|
# AUTH_LOGIN_CODE=off
|
|
# REQUIRE_EMAIL_VERIFICATION=false
|
|
#
|
|
# DISABLE_REGISTRATION: true | false | invite_only. Self-host defaults to
|
|
# invite_only, with a first-launch exemption so the very first signup works.
|
|
# DISABLE_REGISTRATION=invite_only
|
|
# DISABLE_PASSWORD_LOGIN=false # OIDC-only deployments
|
|
# AUTH_IP_RATE_LIMIT=60 # unauthenticated auth requests per IP per 15 min
|
|
#
|
|
# CIDRs allowed to set X-Forwarded-For. Empty trusts nothing, which is correct
|
|
# for a directly exposed backend. Set it when a reverse proxy sits in front, or
|
|
# rate limits and audit IPs are attacker-controlled.
|
|
# TRUSTED_PROXIES=10.0.0.0/8
|
|
|
|
# First owner, read only while the users table is empty. Leave unset and the
|
|
# backend prints a single-use setup link to its logs on first boot.
|
|
# WARMBLY_BOOTSTRAP_EMAIL=you@example.com
|
|
# WARMBLY_BOOTSTRAP_PASSWORD_HASH= # argon2 PHC string; preferred
|
|
# WARMBLY_BOOTSTRAP_PASSWORD= # plaintext convenience; warns at boot
|
|
# WARMBLY_BOOTSTRAP_ORG=My Organization
|
|
|
|
# === Single sign-on (generic OpenID Connect) ===
|
|
#
|
|
# The only sign-in path with no dependency on outbound mail, so it is the
|
|
# recommended posture for a deployment with no relay. Works with Authentik,
|
|
# Keycloak, Zitadel, Pocket ID, Dex and anything else that publishes a
|
|
# discovery document. RS256 ID tokens only.
|
|
# OIDC_ISSUER_URL=https://id.example.com/application/o/warmbly/
|
|
# OIDC_CLIENT_ID=
|
|
# OIDC_CLIENT_SECRET=
|
|
# OIDC_REDIRECT_URL= # defaults to API_PUBLIC_URL/api/v1/auth/oidc/callback
|
|
# OIDC_SCOPES=openid,profile,email
|
|
# OIDC_ALLOWED_DOMAINS=example.com
|
|
# OIDC_DEFAULT_ORG= # org every SSO user joins; without it each
|
|
# # new user gets their own single-member org
|
|
# OIDC_PROVIDER_NAME=Single sign-on
|
|
|
|
# === Transactional email branding ===
|
|
# A self-hosted install should not send mail attributed to another company.
|
|
# EMAIL_BRAND_NAME=Acme
|
|
# EMAIL_BRAND_LEGAL_ENTITY=Acme Ltd
|
|
# EMAIL_BRAND_COMPANY_NUMBER=
|
|
# EMAIL_BRAND_PLACE_OF_REG=
|
|
# EMAIL_BRAND_ADDRESS=
|
|
# EMAIL_BRAND_WEBSITE_URL=https://acme.example.com
|
|
# EMAIL_BRAND_SUPPORT_EMAIL=support@acme.example.com
|
|
# EMAIL_BRAND_TERMS_URL=
|
|
# EMAIL_BRAND_PRIVACY_URL=
|
|
|
|
# === 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 ===
|
|
# Optional in dev; REQUIRED (fatal at boot) on every Go service when APP_ENV=prod.
|
|
# SENTRY_DSN=
|