Files

83 lines
4.6 KiB
Bash

# Copy to .env and source it (e.g. `set -a; . ./.env; set +a`) before running.
MESHTENDER_ADDR=:8080
MESHTENDER_DATABASE_URL=postgres://meshtender:meshtender@localhost:5432/meshtender?sslmode=disable
# 32-byte AES key, hex-encoded (64 chars) — REQUIRED (the server refuses to start
# without it). Left blank on purpose so a verbatim copy fails closed rather than
# booting with a predictable key. Generate one with:
# openssl rand -hex 32
MESHTENDER_MASTER_KEY=
# WebAuthn relying-party settings. RP_ID is the bare domain (no scheme/port).
# Set it to the ROOT registrable domain (e.g. meshtender.com) so passkeys stay
# valid across every subdomain — this is permanent, so don't pin it to a
# subdomain. RP_ORIGIN is a comma-separated list of every origin a ceremony may
# run from (the auth and app hosts). These must line up with the hosts below.
MESHTENDER_RP_ID=leighthaus.dev
MESHTENDER_RP_NAME=MeshTender
MESHTENDER_RP_ORIGIN=https://auth.leighthaus.dev:8080,https://app.leighthaus.dev:8080
# Host topology — REQUIRED. One binary serves all three on one port; the server
# refuses to start unless AUTH_HOST and ROOT_HOST are set. Roles:
# ROOT_HOST — public marketing + organization discovery (no session).
# WWW_HOST — redirects to ROOT_HOST (defaults to "www." + ROOT_HOST).
# AUTH_HOST — login/signup + WebAuthn ceremonies; hands off to the app host.
# PRIMARY_HOST — the product/app host (dashboard at /, authenticated area).
#
# NOTE: don't use *.localhost — "localhost" is a public suffix, so browsers reject
# RP ID "localhost" from a subdomain and passkeys won't work. Use a real
# registrable dev domain with its subdomains pointed at 127.0.0.1, so RP ID can be
# the registrable parent. Example (leighthaus.dev — also update RP_ID/RP_ORIGIN):
# MESHTENDER_RP_ID=leighthaus.dev
# MESHTENDER_RP_ORIGIN=https://auth.leighthaus.dev:8080,https://app.leighthaus.dev:8080
MESHTENDER_ROOT_HOST=leighthaus.dev
MESHTENDER_AUTH_HOST=auth.leighthaus.dev
MESHTENDER_PRIMARY_HOST=app.leighthaus.dev
# MESHTENDER_WWW_HOST= # defaults to "www." + ROOT_HOST
#
# HSTS-preloaded TLDs (.dev, .app, …) force HTTPS, so plain-HTTP dev won't load.
# Serve TLS in-process with a locally-trusted mkcert cert (origins above are
# https for this reason):
# brew install mkcert && mkcert -install
# mkcert -cert-file ./certs/dev.pem -key-file ./certs/dev-key.pem "*.leighthaus.dev" leighthaus.dev
MESHTENDER_TLS_CERT=./certs/dev.pem
MESHTENDER_TLS_KEY=./certs/dev-key.pem
# Outbound mail (Resend) — OPTIONAL, and used only for account recovery: verifying
# an address a user added, and sending a password-reset link.
#
# Two switches, deliberately separate:
# MAIL_FROM turns the email FEATURE on (the account page's Email card, the
# "Forgot password?" link). Unset ⇒ none of it is shown, so we never
# offer recovery mail we couldn't deliver.
# RESEND_API_KEY turns real DELIVERY on. Without it — the dev default below — the
# server LOGS each message (recipient, subject, full body) instead of
# sending it, so the whole flow is walkable from the terminal with no
# provider, no verified domain, and no network.
MESHTENDER_MAIL_FROM=MeshTender <noreply@leighthaus.dev>
#
# Before setting a key in production:
# 1. Add the sending domain in Resend and publish its SPF + DKIM records.
# 2. Add a DMARC record for that domain.
# 3. MAIL_FROM must be an address on that verified domain, or every send is
# rejected. Setting the key without MAIL_FROM is a startup error.
# Free tier: 3,000 emails/month with a 100/day cap — the reset flow is rate limited
# per IP and per address partly to stay inside that.
# MESHTENDER_RESEND_API_KEY=
# MESHTENDER_MAIL_REPLY_TO=
# CARTO's API key for the basemap, appended as ?key= to every request a map style
# makes — the style JSON, the vector tiles, the sprite and the glyphs. Without it
# CARTO watermark what they serve. The browser fetches directly, so this key is
# served in the page. Unset => the key parameter is omitted entirely.
# MESHTENDER_CARTO_KEY=
# The OCI digest of the image this server runs as — reported by GET /version and
# the admin build page, so an auditor can rebuild the commit and compare digests.
# A binary can't derive its own image digest (the digest is computed over the
# binary), so CI resolves it at publish time and the deployment passes it in; see
# .woodpecker/build.yaml. Leave unset when running from source: the field is then
# simply absent rather than wrong. A malformed value is a startup error.
# MESHTENDER_IMAGE_DIGEST=sha256:<64 hex>