# cashumints.space configuration. # # Copy to .env and edit. Every value below is the built-in default, so an empty .env # behaves exactly like no .env at all. # # cp .env.example .env # # One file at the repo root serves all three packages. It is loaded by: # - api/ via node --env-file-if-exists=../.env (see api/package.json) # - web/ via web/scripts/load-env.mjs, imported from astro.config.mjs # # Real environment variables always win over this file, so a systemd unit or a # one-off `PORT=9000 pnpm dev:api` still overrides it. .env is gitignored. # ─── Ports ─────────────────────────────────────────────────────────────────── # The two servers `pnpm dev` starts. Change PORT and API_URL together: the web # build and the dev proxy reach the API at API_URL, so they must agree. # API HTTP port. PORT=8787 # Astro dev server / preview port. WEB_PORT=4321 # ─── Web ───────────────────────────────────────────────────────────────────── # Where the build and the dev proxy reach the API. A build-machine address; it is # never written into the markup a visitor downloads. API_URL=http://127.0.0.1:8787 # Browser-facing API origin, baked into the markup and the islands. Empty means # same origin: icons resolve to /icons and islands fetch /api, which the dev proxy # and nginx forward to API_URL. Deliberately does NOT fall back to API_URL — a # visitor's browser cannot reach 127.0.0.1. Set it only when the API answers on its # own origin, e.g. https://api.cashumints.space PUBLIC_API_URL= # Canonical origin for canonical links, OpenGraph tags and the sitemap. SITE_URL=https://cashumints.space # ─── API storage ───────────────────────────────────────────────────────────── # The API serves everything from its own database and nothing from a mint or a relay at # request time, so a restart loses nothing: mint metadata, cached /v1/info payloads, # reviews, probe history and the discovery cursor all live here. Icons live next to it # as files. In production point both at a directory the service user owns. # Which database. Unset means SQLite at DB_PATH below, which is what every existing # deployment has and needs no setup at all. Set it to a postgres:// URL to use Postgres # instead — put the API on one host and the database on another, run more than one API # process, or fold the data into an existing backup and replication setup. # # Both backends create their tables on the first connection, so an empty database is # the whole installation. To carry existing data across, in either direction: # # pnpm --filter ./api migrate --to postgres://user:pw@localhost:5432/cashumints # # then set DATABASE_URL to the same value and restart. Stop the API first: migrating # from a database that is still being written to copies a moving target. # # DATABASE_URL=postgres://cashumints:secret@localhost:5432/cashumints # DATABASE_URL=sqlite:/var/lib/cashumints/cashumints.db # SQLite file. Ignored when DATABASE_URL is set. Unset means api/data/, resolved from # the source tree regardless of where you run from. Set it and it is taken as given: a # relative path resolves against the working directory (api/ under every pnpm script), # so prefer an absolute path. # DB_PATH=/var/lib/cashumints/cashumints.db # Postgres connections held open. Ignored by SQLite, which has exactly one. The default # of 10 is well above what one indexer plus the read endpoints need. # DB_POOL_MAX=10 # Cached mint icons, served at /icons/*. Files, not rows — they are kept here whichever # database is in use, and `migrate` does not touch them. # ICON_DIR=/var/lib/cashumints/icons # ─── Nostr relays ──────────────────────────────────────────────────────────── # Three comma separated lists, all optional. Each one, unset or empty, falls back # to the list of the same name in shared/src/nostr.ts; the values below ARE those # defaults, spelled out so the relays this site talks to are visible in one place. # Setting one replaces the default pool entirely — it does not add to it. # Review and mint-announcement relays: kind 38000 and 38172. Read by the API # indexer (probe/discovery cycles) and by the build-time "latest reviews" fetch. # The union of the old site's read pool and its publish pool — the two differed, # so reviews the old site published to snort/primal were invisible to it. RELAYS=wss://relay.cashumints.space,wss://nos.lol,wss://relay.azzamo.net,wss://relay.snort.social,wss://relay.primal.net # Profile relays for the BUILD (kind 0, prerendered reviewer names on the home # page). A wider pool than RELAYS on purpose: relay.cashumints.space holds no kind # 0 at all and snort/primal hold almost none, so the two aggregators below are what # turn npubs into names. Read the PROFILE_RELAYS comment in shared/src/nostr.ts # before trimming this — relay.nostr.band was measured and deliberately excluded. PROFILE_RELAYS=wss://relay.cashumints.space,wss://nos.lol,wss://relay.azzamo.net,wss://relay.snort.social,wss://relay.primal.net,wss://purplepag.es,wss://relay.nostr.net # Profile relays for the BROWSER: the same kind 0 lookup, done client side for # pubkeys the build did not resolve. PUBLIC_ means it is baked into the shipped # markup and a visitor's browser connects to these directly, so list only relays # that accept public websocket connections. Normally kept equal to PROFILE_RELAYS. PUBLIC_PROFILE_RELAYS=wss://relay.cashumints.space,wss://nos.lol,wss://relay.azzamo.net,wss://relay.snort.social,wss://relay.primal.net,wss://purplepag.es,wss://relay.nostr.net # Review relays for the BROWSER: where the reviews panel reads from and where a # newly signed review is published. Defaults to RELAYS above when unset, which is # what production wants. Point it at a local relay to exercise the publish path in # development without putting test reviews on the public network. # PUBLIC_REVIEW_RELAYS= # Relays used to reach a NIP-46 remote signer (the "Remote signer" and "Primal" # login routes). Not review relays: these carry small encrypted RPC between this # browser and the reader's signer app, so they have to be relays both ends can # reach. Defaults to relay.nsec.app and relay.primal.net when unset. # PUBLIC_CONNECT_RELAYS= # ─── Indexer timing ────────────────────────────────────────────────────────── # All are positive integers; anything unparseable falls back to the default. # Minutes between probe cycles (every mint's /v1/info). PROBE_INTERVAL_MIN=10 # Minutes between discovery cycles (relay scan for new mints and reviews). DISCOVERY_INTERVAL_MIN=60 # Mints probed in parallel. PROBE_CONCURRENCY=8 # Per-mint request timeout, milliseconds. Cashu mints only: a federation is not # fetched directly, see below. PROBE_TIMEOUT_MS=5000 # ─── Fedimint ──────────────────────────────────────────────────────────────── # A federation has no HTTP status endpoint of its own — confirming one is up means # being a Fedimint client — so its status is read from an outside checker instead, # once per probe cycle for every federation at once. Every row whose status came # from here records that fact and its page prints it, so nothing implies this site # opened a socket itself. # # Empty disables the lookup entirely: every federation then carries the `announced` # status, which is the honest one for "nothing checks this". It is never inferred # to be online or offline. See the "Ecosystems" section of README.md. FEDIMINT_OBSERVER_URL=https://observer.fedimint.org/api/federations # ─── Ranking ───────────────────────────────────────────────────────────────── # Bayesian prior mean C. The neutral 3 is intentional — read the "Ranking" section # of README.md before changing it. `global` uses the observed global mean instead, # which is the literal BACKEND.md behaviour and ranks noticeably worse. SCORE_PRIOR_MEAN=3 # ─── Tooling ───────────────────────────────────────────────────────────────── # Dev server Boneyard captures against (`pnpm bones`). Defaults to WEB_PORT. # BONES_URL=http://localhost:4321