# Copy to /etc/thermograph.env on the VPS and edit. # Read by the systemd unit (EnvironmentFile). # Port uvicorn binds on loopback. Caddy proxies to this. Keep 8137 unless it clashes. PORT=8137 # Number of uvicorn worker processes. More than 1 stops a single slow upstream fetch # (e.g. a cache-miss weather lookup) from blocking every other request — the cause of # past brief outages. Prod runs 3; leave unset (defaults to 1) on a small box. Workers # share one metrics store (THERMOGRAPH_METRICS_DB, defaulted in the systemd unit) so the # ops dashboard still sees the whole picture, and elect one leader for the subscription # notifier via a lockfile (THERMOGRAPH_SINGLETON_LOCK, also defaulted in the unit) so its # timer-driven upstream sweep runs once, not once per worker. ~200 MB RAM per worker. WORKERS=3 # Base path the app is served under. # / -> app at the domain root (Thermograph owns the whole domain — # this is what the Caddyfile expects: thermograph.org proxies "/") # /thermograph -> app under a sub-path (share the host with other apps, e.g. a # portfolio at the root) THERMOGRAPH_BASE=/ # --- SEO: search-engine verification + IndexNow --------------------------------- # Ownership-verification tokens, rendered as tags in every page's . # Google Search Console → add property https://thermograph.org → "HTML tag" method # → paste just the content="…" value below. (Or verify via DNS TXT and skip this.) #THERMOGRAPH_GOOGLE_VERIFY= # Bing Webmaster Tools → add site → "HTML Meta Tag" (msvalidate.01) → paste the # content value. (Bing can also import verification from Google Search Console.) #THERMOGRAPH_BING_VERIFY= # IndexNow key (Bing/DuckDuckGo/Yandex instant re-crawl). Auto-generated to # data/indexnow_key.txt on first use; set here to pin a specific key. #THERMOGRAPH_INDEXNOW_KEY= # Public site URL for IndexNow. The deploy hook auto-pings IndexNow after a # successful deploy, but only when the URL set changed (a new/removed city), so # code-only deploys don't resubmit. `make indexnow` forces a full submit. THERMOGRAPH_BASE_URL=https://thermograph.org # --- Web Push (VAPID) ----------------------------------------------------------- # Keys that sign push notifications. If unset, the app generates a pair into # data/vapid.json on first run — fine as long as that file PERSISTS (it lives in the # writable data dir and survives deploys). PIN them here to be safe: if the keys ever # change, every existing browser subscription silently stops receiving (the push # service rejects with 401/403), and users must toggle alerts off/on to re-subscribe. # Generate a pair: cd backend && ../.venv/bin/python -c "import push,json; k=push._generate(); print('PRIVATE=',k['private_key']); print('PUBLIC=',k['public_key'])" #THERMOGRAPH_VAPID_PRIVATE_KEY= #THERMOGRAPH_VAPID_PUBLIC_KEY= # Contact (mailto: or https URL) sent to push services in the VAPID claim. #THERMOGRAPH_VAPID_CONTACT=mailto:you@example.com # --- Outbound email -------------------------------------------------------------- # Delivery goes through a local Postfix null client on 127.0.0.1:25 — see # deploy/provision-mail.sh. The app only ever speaks plain SMTP to loopback, so # switching between "direct to MX" and "relay through a provider" is a Postfix # config change and needs no code change or redeploy. # # Backends: console (log it, send nothing — the default, right for dev), # smtp (actually send), disabled (drop silently). # Leave unset until Postfix is provisioned: signups are still collected either way. #THERMOGRAPH_MAIL_BACKEND=smtp #THERMOGRAPH_SMTP_HOST=127.0.0.1 #THERMOGRAPH_SMTP_PORT=25 # Only needed if talking to a remote SMTP server directly instead of local Postfix. #THERMOGRAPH_SMTP_USER= #THERMOGRAPH_SMTP_PASSWORD= #THERMOGRAPH_SMTP_STARTTLS=1 #THERMOGRAPH_MAIL_FROM=Thermograph #THERMOGRAPH_MAIL_REPLY_TO= # Signing secret for email confirmation / password-reset tokens. MUST be set to a # fixed value before any such link is mailed: it defaults to a per-boot random # value, which would invalidate every outstanding link on each restart. # generate with: python -c "import secrets; print(secrets.token_urlsafe(48))" #THERMOGRAPH_AUTH_SECRET= # --- Discord --------------------------------------------------------------------- # Incoming webhook URL for the daily "most unusual right now" post. Create it in the # Discord server: Channel → Edit → Integrations → Webhooks → New Webhook → Copy URL. # The URL IS the credential — anyone who has it can post as the webhook, so keep it # here and never in the repo. Unset => the daily post is disabled (no-op). # The post rides the notifier daemon (leader-only), once per day after the feed # refresh, so it needs THERMOGRAPH_ENABLE_NOTIFIER on (the default). #THERMOGRAPH_DISCORD_WEBHOOK= # Slash commands (/grade) are served over Discord's HTTP interactions endpoint by # the app itself (no bot process). Set the portal's "Interactions Endpoint URL" to # https://thermograph.org/discord/interactions. These come from the Developer Portal: # - PUBLIC_KEY: General Information -> Public Key (used to verify every request). # - APP_ID / BOT_TOKEN: only needed to (re)register the commands, via # scripts/register_discord_commands.py. The bot token is a credential. #THERMOGRAPH_DISCORD_PUBLIC_KEY= #THERMOGRAPH_DISCORD_APP_ID= #THERMOGRAPH_DISCORD_BOT_TOKEN= # Account linking (OAuth2 "identify"): lets a signed-in user connect their Discord # account, storing their Discord user id for DM alerts. CLIENT_ID is the same App # ID above. The CLIENT_SECRET is from OAuth2 -> Client Secret (a credential). In the # portal, add the redirect: https://thermograph.org/api/v2/discord/link/callback #THERMOGRAPH_DISCORD_CLIENT_SECRET=