elektrine/.env.example
maxfield 4bcca176f0
All checks were successful
Deploy Docker Images / Build, push, and deploy (push) Successful in 19m10s
feat(payments): automate Monero invoices via wallet-rpc
Add standalone invoice create/poll flow with unique subaddresses, a public
/pay/monero page, Oban poller, and optional Docker wallet-rpc sidecar. No
product unlock hooks—payments only.
2026-08-09 21:29:01 -04:00

345 lines
14 KiB
Text

# Advanced example env file.
# For the easiest first setup, run:
# scripts/deploy/self_host.sh init --domain example.com --email admin@example.com
# Copy this file to `.env.production` only if you want the larger kitchen-sink template.
# -----------------------------------------------------------------------------
# Core domains / hostnames
# -----------------------------------------------------------------------------
PRIMARY_DOMAIN=example.com
# Optional overrides for split-domain setups. If unset, deploy tooling derives
# them from PRIMARY_DOMAIN automatically.
# PHX_HOST=example.com
# INSTANCE_DOMAIN=example.com
# EMAIL_DOMAIN=example.com
# EMAIL_RAW_SOURCE_MAX_BYTES=10485760
# SUPPORTED_DOMAINS=example.com
# PROFILE_BASE_DOMAINS=example.com
# Optional DNS branding overrides. If unset, the DNS service derives these from
# PRIMARY_DOMAIN automatically.
# DNS_NAMESERVERS=ns1.example.com,ns2.example.com
# DNS_SOA_RNAME=admin.example.com
# -----------------------------------------------------------------------------
# Phoenix runtime
# -----------------------------------------------------------------------------
PHX_SERVER=true
PORT=8080
# Optional runtime overrides.
# FORCE_SSL=false
# TRUSTED_PROXY_CIDRS=172.30.0.0/24
# PROXY_PROTOCOL_TRUSTED_CIDRS=203.0.113.10/32
# CADDY_ASK_TRUSTED_CIDRS=172.30.0.0/24
# ELEKTRINE_AUTO_CONFIGURE_DOCKER_SOURCE_IPS=true
# CADDY_TRUSTED_PROXY_CIDRS=203.0.113.10/32
# CADDY_PROXY_PROTOCOL_ALLOWED_CIDRS=203.0.113.10/32
# EXTRA_CHECK_ORIGINS=http://203.0.113.10
# ATOMINE_DM_CREDIT_GATE_ENABLED=false
# ATOMINE_EMAIL_CREDIT_GATE_ENABLED=false
# Require NetBird for login/admin surfaces and restrict admin.<domain> at Caddy.
# NETBIRD_ENABLED=true
# Exact NetBird peer /32s only (whitespace-separated for Caddy remote_ip). Never 100.64.0.0/10.
# NETBIRD_ALLOWED_CIDRS="100.90.1.10/32 100.90.2.20/32"
# Optional Management API sync (group elektrine-admins by default):
# NETBIRD_API_TOKEN=
# NETBIRD_ADMIN_GROUP=elektrine-admins
# NETBIRD_MANAGEMENT_URL=https://api.netbird.io
# NETBIRD_ENV_FILE=/opt/elektrine/.env.production
# Host peer sync without API token: scripts/netbird/sync_admin_allowlist.sh
# CADDY_ADMIN_HOST=admin.example.com
# -----------------------------------------------------------------------------
# Database / secrets
# -----------------------------------------------------------------------------
# DB_PASSWORD=<generate-a-long-random-secret>
# Keep this file owner-read/write only (deploy scripts chmod 600 when they can).
# For the default Docker stack, `DB_PASSWORD` is enough. Set `DATABASE_URL`
# only when you use an external Postgres instance or non-Docker deploy.
# DATABASE_URL=ecto://elektrine:<generate-a-long-random-secret>@postgres/elektrine_prod
# TLS is enabled by default for external DATABASE_URL connections. Only set this
# false for an internal Docker/private-network database that does not support TLS.
# DATABASE_SSL_ENABLED=false
# Minimal root secret for self-hosting. Elektrine derives internal API keys,
# salts, and other internal-only secrets from this automatically.
# ELEKTRINE_MASTER_SECRET=<generate-a-long-random-secret>
# Optional explicit override. If omitted, Elektrine derives it from
# ELEKTRINE_MASTER_SECRET.
# SECRET_KEY_BASE=
# -----------------------------------------------------------------------------
# Modules / deploy profiles
# -----------------------------------------------------------------------------
ELEKTRINE_ENABLED_MODULES=all
# Advanced build override only. Usually leave this unset.
# ELEKTRINE_RELEASE_MODULES=chat,social,nerve,atomine
DOCKER_PROFILES=caddy dns email tor turn bluesky vpn
# After each successful docker_deploy up, prune old app image tags on the host
# so deploys do not fill the disk. Keep the N newest tags of the app image.
# ELEKTRINE_IMAGE_KEEP_COUNT=3
# ELEKTRINE_IMAGE_REPO=ghcr.io/atomine-elektrine/elektrine
# ELEKTRINE_PRUNE_DANGLING_IMAGES=true
# ELEKTRINE_PRUNE_BUILD_CACHE=true
# ELEKTRINE_SKIP_IMAGE_PRUNE=false
# -----------------------------------------------------------------------------
# Database pool tuning
# -----------------------------------------------------------------------------
# Advanced DB tuning only.
# POOL_SIZE=10
# APP_POOL_SIZE=10
# WORKER_POOL_SIZE=5
# MAIL_POOL_SIZE=5
# DNS_POOL_SIZE=3
# VPN_POOL_SIZE=2
# MIGRATION_POOL_SIZE=2
# DB_QUEUE_TARGET_MS=2000
# DB_QUEUE_INTERVAL_MS=5000
# DB_TIMEOUT_MS=30000
# DB_POOL_TIMEOUT_MS=15000
# DB_CONNECT_TIMEOUT_MS=15000
# POSTGRES_EXTENSIONS=vector
# -----------------------------------------------------------------------------
# Federation / remote enrichment
# -----------------------------------------------------------------------------
# Advanced federation/remoting only.
# MESSAGING_FEDERATION_ENABLED=true
# MESSAGING_FEDERATION_IDENTITY_KEY_ID=default
# MESSAGING_FEDERATION_OFFICIAL_RELAY_OPERATOR=Community-operated
# MESSAGING_FEDERATION_OFFICIAL_RELAYS_JSON='[]'
# MESSAGING_FEDERATION_PEERS_JSON='[]'
# Optional Paige search providers.
# PAIGE_BRAVE_API_KEY=<brave-search-api-key>
# PAIGE_GITHUB_TOKEN=<github-token>
# Comma-separated first-party HTML scrapers: wiby,duckduckgo (default: wiby).
# PAIGE_SCRAPERS=wiby,duckduckgo
# Paige's independent PostgreSQL-backed index. Seeds are comma-separated URLs;
# same-host links are discovered up to PAIGE_INDEX_MAX_DEPTH.
# PAIGE_INDEX_ENABLED=true
# PAIGE_INDEX_SEEDS=https://example.com/,https://hexdocs.pm/elixir/
# PAIGE_INDEX_MAX_DEPTH=2
# PAIGE_INDEX_RECRAWL_SECONDS=604800
# PAIGE_INDEX_BATCH_SIZE=100
# OBAN_QUEUE_CRAWLER=2
# Optional IFTAS CARIAD denylist sync. Set either a full URL or an API key.
# IFTAS_BLOCKLIST_ENABLED=true
# IFTAS_BLOCKLIST_THRESHOLD=66
# IFTAS_BLOCKLIST_API_KEY=<iftas-api-key>
# IFTAS_BLOCKLIST_URL=
# -----------------------------------------------------------------------------
# Optional but recommended crypto secrets
# -----------------------------------------------------------------------------
# Optional explicit overrides. If omitted, Elektrine derives them from
# ELEKTRINE_MASTER_SECRET.
# ENCRYPTION_MASTER_SECRET=
# ENCRYPTION_KEY_SALT=
# ENCRYPTION_SEARCH_SALT=
# -----------------------------------------------------------------------------
# Email / Haraka integration
# -----------------------------------------------------------------------------
# Enable only if you actually use the `email` module/profile.
# USE_LOCAL_EMAIL=false
# EMAIL_AUTO_SUPPRESSION=true
# HARAKA_ASYNC_INGEST=true
# MAIL_SERVICE_HOST=mail.example.com
# IMAP_HOST=mail.example.com
# SMTP_HOST=mail.example.com
# Privacy defaults (match config.exs):
# Never keep a second RFC822 copy (set e.g. 10485760 to enable "view original").
# EMAIL_RAW_SOURCE_MAX_BYTES=0
# Connecting MTA IP on durable message metadata / Oban jobs (off by default).
# EMAIL_STORE_INBOUND_REMOTE_IP=false
# Hard-delete trash/spam after N days (0 = skip that bucket). Inbox max age 0 = keep forever.
# EMAIL_TRASH_RETENTION_DAYS=30
# EMAIL_SPAM_RETENTION_DAYS=30
# EMAIL_INBOX_RETENTION_DAYS=0
# EMAIL_RETENTION_BATCH_SIZE=500
# Optional overrides. If omitted, Elektrine derives these from your domain and
# ELEKTRINE_MASTER_SECRET automatically.
# HARAKA_BASE_URL=https://mail.example.com
# CUSTOM_DOMAIN_MX_HOST=mail.example.com
# INTERNAL_API_KEY=
# HARAKA_HTTP_API_KEY=
# PHOENIX_API_KEY=
# HARAKA_INTERNAL_SIGNING_SECRET=
# EMAIL_RECEIVER_WEBHOOK_SECRET=
# CUSTOM_DOMAIN_MX_PRIORITY=10
# CUSTOM_DOMAIN_SPF_INCLUDE=_spf.example.com
# CUSTOM_DOMAIN_DKIM_SELECTOR=default
# CUSTOM_DOMAIN_DKIM_SYNC_ENABLED=true
# CUSTOM_DOMAIN_HARAKA_BASE_URL=https://mail.example.com
# CUSTOM_DOMAIN_HARAKA_API_KEY=
# CUSTOM_DOMAIN_HARAKA_TIMEOUT_MS=10000
# CUSTOM_DOMAIN_HARAKA_DKIM_PATH=/api/v1/dkim/domains
# CUSTOM_DOMAIN_DMARC_POLICY=quarantine
# CUSTOM_DOMAIN_DMARC_RUA=mailto:dmarc@example.com
# CUSTOM_DOMAIN_DMARC_ADKIM=s
# CUSTOM_DOMAIN_DMARC_ASPF=s
# -----------------------------------------------------------------------------
# Edge / certificates / anti-abuse
# -----------------------------------------------------------------------------
ACME_EMAIL=admin@example.com
# Minimal wildcard setup for large/dynamic username subdomains:
# CADDY_MANAGED_SITE_1="example.com *.example.com"
# Leave CADDY_MANAGED_SITE_2 unset unless you have a second disjoint site list.
# CADDY_MANAGED_SITE_2="alt.example.net *.alt.example.net"
# Deploy tooling auto-selects the wildcard-external Caddyfile when wildcard
# sites and mounted cert paths are present. For raw `docker compose` usage,
# set `CADDY_CONFIG_PATH` explicitly.
# With the stock Caddyfile, keep these lists to explicit hosts only.
# CADDY_MANAGED_SITE_1="example.com mail.example.com imap.example.com pop.example.com smtp.example.com"
# CADDY_MANAGED_SITE_2="alt.example.net mail.alt.example.net imap.alt.example.net pop.alt.example.net smtp.alt.example.net"
# CADDY_TLS_MOUNT_DIR=/opt/elektrine/certs
# CADDY_MANAGED_SITE_1_CERT_PATH=/opt/elektrine/certs/example.com.fullchain.pem
# CADDY_MANAGED_SITE_1_KEY_PATH=/opt/elektrine/certs/example.com.key.pem
# CADDY_MANAGED_SITE_2_CERT_PATH=/opt/elektrine/certs/alt.example.net.fullchain.pem
# CADDY_MANAGED_SITE_2_KEY_PATH=/opt/elektrine/certs/alt.example.net.key.pem
# CADDY_ORIGIN_UPSTREAM=app_proxy:8080
# MAIL_TLS_CERT_PATH=/opt/elektrine/certs/mail.crt
# MAIL_TLS_KEY_PATH=/opt/elektrine/certs/mail.key
# MAIL_TLS_MOUNT_DIR=/opt/elektrine/certs
# IMAP_TLS_CERT_PATH=/opt/elektrine/certs/imap.crt
# IMAP_TLS_KEY_PATH=/opt/elektrine/certs/imap.key
# POP3_TLS_CERT_PATH=/opt/elektrine/certs/pop.crt
# POP3_TLS_KEY_PATH=/opt/elektrine/certs/pop.key
# TURN_HOST defaults to PRIMARY_DOMAIN when the `turn` profile is enabled.
# TURN_PORT=3478
# TURN_MIN_PORT=49160
# TURN_MAX_PORT=49200
# TURN_EXTERNAL_IP=
# TURN_RELAY_IP=
# TURN_SHARED_SECRET=
# ATOMINE_POW_DIFFICULTY=20
# ATOMINE_POW_SKIP_VERIFICATION=false
# STRIPE removed; billing subscriptions deleted
# STRIPE_SECRET_KEY=
# STRIPE_WEBHOOK_SECRET=
# -----------------------------------------------------------------------------
# Monero payments
# -----------------------------------------------------------------------------
# Manual display (optional):
# MONERO_ENABLED=true
# MONERO_ADDRESS=
# MONERO_PAYMENT_URL=
#
# Automated invoices (monero-wallet-rpc). Public UI: /pay/monero
# Docker: deploy/docker/compose.monero.yml profile "monero"
# MONERO_WALLET_RPC_URL=http://monero-wallet-rpc:18083/json_rpc
# MONERO_WALLET_RPC_USER=
# MONERO_WALLET_RPC_PASSWORD=
# MONERO_WALLET_ACCOUNT_INDEX=0
# MONERO_DEFAULT_AMOUNT_XMR=0.05
# MONERO_DEFAULT_AMOUNT_ATOMIC=
# MONERO_REQUIRED_CONFIRMATIONS=1
# MONERO_INVOICE_TTL_SECONDS=3600
# MONERO_DAEMON_ADDRESS=node.community.rino.io:18081
# DNS_RECURSIVE_ENABLED=true
# -----------------------------------------------------------------------------
# VPN
# -----------------------------------------------------------------------------
# Single-server self-hosted WireGuard (recommended for most installs):
# VPN_SELFHOST_ENDPOINT_HOST=vpn.example.com
# VPN_SELFHOST_PUBLIC_IP=203.0.113.10
# VPN_SELFHOST_PRIVATE_KEY=optional; auto-generated and persisted by the vpn container when omitted
# VPN_SELFHOST_ADDRESS=10.8.0.1/24
# VPN_SELFHOST_LISTEN_PORT=51820
# VPN_SELFHOST_ENDPOINT_PORT=51820
# VPN_SELFHOST_PUBLIC_KEY=optional override; normally derived automatically from the private key
# VPN_SELFHOST_INTERNAL_IP_RANGE=10.8.0.0/24
# Prefer Elektrine DNS for WireGuard clients when the dns module is on:
# VPN_USE_ELEKTRINE_DNS=true
# VPN_CLIENT_DNS_SERVERS=203.0.113.10
# PUBLIC_DNS_BIND_IP=203.0.113.10
# Fallback self-host DNS field (not Cloudflare):
# VPN_SELFHOST_DNS_SERVERS=9.9.9.9, 149.112.112.112
# VPN_SELFHOST_WG_INTERFACE=wg0
# Multi-server fleet bootstrap:
# VPN_FLEET_REGISTRATION_KEY=replace-with-base64-registration-key
# Private supernet each node's /24 is carved from. The default holds 256 nodes;
# widen it BEFORE nodes claim ranges, since changing it later strands existing
# allocations.
# VPN_WG_SUPERNET=10.8.0.0/16
# Session privacy (defaults match a no-session-log posture):
# Leave off unless you need durable connect/disconnect history on the control
# plane. Free-tier bandwidth still uses aggregate counters without this.
# VPN_DURABLE_SESSION_LOGS=false
# When durable logs are on, delete rows older than N days (0 = keep until purge).
# When durable logs are off, the daily cleanup job deletes every row.
# VPN_CONNECTION_LOG_RETENTION_DAYS=0
# -----------------------------------------------------------------------------
# Onion / Tor
# -----------------------------------------------------------------------------
# ELEKTRINE_ENABLE_TOR=true
# ONION_TLS_ENABLED=true
# ONION_TLS_PORT=8443
# ONION_TLS_CERTFILE=/data/certs/live/onion-cert.pem
# ONION_TLS_KEYFILE=/data/certs/live/onion-key.pem
# ONION_HOST=
# ONION_HS_SECRET_KEY_B64=
# ONION_HS_PUBLIC_KEY_B64=
# -----------------------------------------------------------------------------
# Bluesky
# -----------------------------------------------------------------------------
# BLUESKY_ENABLED=false
# BLUESKY_INBOUND_ENABLED=false
# BLUESKY_SERVICE_URL=https://bsky.social
# BLUESKY_TIMEOUT_MS=12000
# BLUESKY_MAX_CHARS=300
# BLUESKY_INBOUND_LIMIT=50
# BLUESKY_MANAGED_ENABLED=false
# BLUESKY_MANAGED_SERVICE_URL=http://bluesky_pds:3000
# BLUESKY_MANAGED_DOMAIN=bsky.example.com
# BLUESKY_MANAGED_ADMIN_PASSWORD=<generate-a-long-random-secret>
# BLUESKY_PDS_PORT=3000
# BLUESKY_PDS_JWT_SECRET=<generate-a-long-random-secret>
# BLUESKY_PDS_ROTATION_KEY_HEX=<generate-a-32-byte-hex-secret>
# -----------------------------------------------------------------------------
# Optional object storage (Magpie / S3-compatible)
# -----------------------------------------------------------------------------
# Leave these unset to keep uploads on local disk.
# S3_ACCESS_KEY_ID=<provider-access-key-id>
# S3_SECRET_ACCESS_KEY=<provider-secret-access-key>
# Local Magpie examples use HTTP loopback. Use HTTPS for any remote object store.
# S3_ENDPOINT=127.0.0.1:8090
# S3_BUCKET_NAME=elektrine-uploads
# S3_PUBLIC_URL=http://127.0.0.1:8090/elektrine-uploads
# S3_SCHEME=http://
# S3_PORT=8090