# LinkBreeze Configuration # Server port (default: 3000) PORT=3000 # SQLite database file path DATABASE_PATH=./data/linkbreeze.db # Scheduled backups (#83: Settings -> Data). The directory must be inside a # persistent volume in Docker (the default sits under ./data) or backups are # lost on container recreation. # BACKUP_DIR=./data/backups # Refuse to write a backup when free space drops below this (MB). # BACKUP_MIN_FREE_MB=50 # Secret key for session signing (REQUIRED in production — set to a random string) # Generate one with: openssl rand -hex 32 SECRET_KEY= # Analytics salt (auto-generated on first run if empty) ANALYTICS_SALT= # Public base URL (optional but recommended — prevents host-header injection) # Set to your real domain, e.g. https://linkbreeze.example.com # BASE_URL=https://linkbreeze.example.com # ── Custom Domains (#85) ───────────────────────────────────────────────── # The primary host your admin lives on. With the custom-domains admin lock # (default strict), every host OTHER than this one gets a 404 on admin, # login and setup routes. Takes precedence over the value set in # Admin → Domains → Routing policy. Full guide: docs/custom-domains.md # LINKBREEZE_PRIMARY_HOST=links.example.com # # Domain routing reads the raw Host header by default — a client-supplied # X-Forwarded-Host is IGNORED, so it cannot spoof the admin host lock or # self-activate a pending domain. Only set this to true when a trusted # reverse proxy OVERWRITES X-Forwarded-Host on every request (nginx # `proxy_set_header X-Forwarded-Host $host;`, Caddy). If your proxy only # FORWARDS the client's header (cloudflared tunnel, some CDNs), leave it # unset — the Host header still carries the right value there. # LINKBREEZE_TRUST_X_FORWARDED_HOST=true # Dev only: allow Server Actions from external IPs (Tailscale, LAN, etc.) # Comma-separated list. Only needed for `npm run dev`, not production. # DEV_ORIGINS="http://100.x.x.x:3000,http://192.168.x.x:3000" # External analytics domains for CSP script-src allowlist. # Add the domains of any analytics providers you use in the Analytics script # field (Settings -> General). Space-separated. Example: # EXTRA_SCRIPT_SRC=plausible.io umami.is matomo.example.com # EXTRA_SCRIPT_SRC= # ── Wallet Passes & Contact Export ──────────────────────────────────────── # vCard "Save contact" on public pages is always on — no config needed. # # Google Wallet (free issuer account, see Google Pay & Wallet Console): # Issuer accounts start in DEMO mode — passes only save for whitelisted # test users until Google approves production access. # GOOGLE_WALLET_ISSUER_ID=1234567890123456789 # GOOGLE_WALLET_SERVICE_ACCOUNT_JSON={"client_email":"...","private_key":"..."} # Apple Wallet (requires a paid Apple Developer Program membership, $99/yr): # Passes install ONLY from Safari. All five variables are required together. # APPLE_WALLET_CERT_PEM=-----BEGIN CERTIFICATE-----... # APPLE_WALLET_KEY_PEM=-----BEGIN PRIVATE KEY-----... # APPLE_WALLET_KEY_PASSPHRASE= # APPLE_WALLET_WWDR_PEM=-----BEGIN CERTIFICATE-----... # APPLE_WALLET_TEAM_ID=ABC123XYZ9 # APPLE_WALLET_PASS_TYPE_ID=pass.com.yourdomain.linkbreeze # ── Demo Instance Mode ──────────────────────────────────────────────────── # These settings configure a public demo instance. When DEMO_MODE=true, all # mutations are blocked (read-only) and a demo banner is shown in the admin. # # DEMO_MODE=true # Skips the login wall — visitors land directly on the dashboard. # DEMO_AUTO_LOGIN=true # Allows the instance to be embedded in an iframe from the specified origin # (e.g. your marketing website). Relaxes CSP frame-ancestors accordingly. # DEMO_FRAME_ORIGIN=https://linkbreeze.omnirise.dev # Exposes DEMO_MODE to the browser (enables the postMessage theme listener). # NEXT_PUBLIC_DEMO_MODE=true