From 07e2121367910fa3aab7fa15820e0fb61a10f0d9 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sat, 29 Aug 2026 09:13:34 +0000 Subject: [PATCH] fix(moshpit): guard addresses live at names.moshcode.sh, and the DNS exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guard addresses were designed against `@moshcode.sh` and the apex was the wrong answer twice over. `pit.moshcode.sh` — the obvious subdomain — cannot carry mail at all: it is a CNAME to Railway, and a CNAME may not coexist with an MX at the same name. That is a DNS rule, not a configuration choice. The apex would have worked, since Porkbun's ALIAS is a flattened A rather than a real CNAME. But it would put the reputation of forwarded stranger mail on the same name as any staff mail moshcode.sh ever carries, and forwarding is the hardest deliverability case there is. It gets a name of its own to damage. So: names.moshcode.sh. The records are live and verified authoritative — MX to mx1/mx2.forwardemail.net, SPF, and a report-only DMARC, added through the Porkbun API. `pit.` and `app.` are untouched. Nothing had to be migrated because nothing had been published: no alias can be minted without FORWARDEMAIL_API_KEY, so every contact is still `pending` and no address exists anywhere to be invalidated. This was the last moment the choice was free. The doc also records two things that cost time to work out. The Porkbun credentials are in the logicsrc shared vault, not absent as previously written. And a bare `dig` on this box goes to the Moshpit DNS bridge, which answers for every *.moshcode.sh name with a synthesised record — it will tell you a host exists when public DNS has never heard of it. Always `@1.1.1.1`. Still outstanding, and both need a person: adding names.moshcode.sh to the Forward Email account with its verification TXT, and putting the resulting API key on the Railway service. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_017QSp1aAoQQB7jFV7hwt4jJ --- apps/pwa/.env.example | 5 ++- apps/pwa/src/config.mjs | 19 ++++++++-- docs/contact-and-guard-addresses.md | 59 ++++++++++++++++++----------- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/apps/pwa/.env.example b/apps/pwa/.env.example index b00178d..016659d 100644 --- a/apps/pwa/.env.example +++ b/apps/pwa/.env.example @@ -48,5 +48,8 @@ SLACK_WEBHOOK_URL= # right behaviour in development: no key means no alias, and no alias means no # address on a page. The domain must be one this Forward Email account holds, # with MX pointed at them, or every mint fails. +# +# names.moshcode.sh, not the apex and not pit. — pit.moshcode.sh is a CNAME to +# Railway, and a CNAME cannot coexist with an MX at the same name. FORWARDEMAIL_API_KEY= -MOSHPIT_GUARD_DOMAIN=moshcode.sh +MOSHPIT_GUARD_DOMAIN=names.moshcode.sh diff --git a/apps/pwa/src/config.mjs b/apps/pwa/src/config.mjs index 75a3b4e..edf0b1a 100644 --- a/apps/pwa/src/config.mjs +++ b/apps/pwa/src/config.mjs @@ -69,17 +69,30 @@ export const config = { apiKey: process.env.RESEND_API_KEY || "", from: process.env.RESEND_FROM || "moshcode ", }, - // The mail host behind a name's guard address: `@moshcode.sh` forwards - // to whatever the holder reads, so the real address is never published. + // The mail host behind a name's guard address: `@names.moshcode.sh` + // forwards to whatever the holder reads, so the real address is never + // published. // // The domain is separate from `origin` and `pitOrigin` on purpose. Those two // are where the registry answers HTTP; this is where it answers mail, and the // two need not be the same host -- moving the pit to another origin must not // silently invalidate every contact address already printed on a page. + // + // Its own subdomain rather than the apex, and rather than `pit.` -- two + // separate reasons, both worth writing down: + // + // `pit.moshcode.sh` is a CNAME to Railway, and a CNAME cannot coexist with + // an MX record at the same name. Mail there is not a configuration choice, + // it is impossible. + // + // The apex would work -- Porkbun's ALIAS is a flattened A, not a CNAME -- + // but it would put the reputation of forwarded stranger mail on the same + // name as any staff mail moshcode.sh ever carries. Forwarding is the + // hardest deliverability case there is, so it gets its own name to damage. forwardEmail: { apiKey: process.env.FORWARDEMAIL_API_KEY || "", apiBase: (process.env.FORWARDEMAIL_API_BASE || "https://api.forwardemail.net").replace(/\/+$/, ""), - domain: (process.env.MOSHPIT_GUARD_DOMAIN || "moshcode.sh").trim().toLowerCase(), + domain: (process.env.MOSHPIT_GUARD_DOMAIN || "names.moshcode.sh").trim().toLowerCase(), }, push: { vapidPublic: process.env.VAPID_PUBLIC || "", diff --git a/docs/contact-and-guard-addresses.md b/docs/contact-and-guard-addresses.md index 3fe7a55..46e1606 100644 --- a/docs/contact-and-guard-addresses.md +++ b/docs/contact-and-guard-addresses.md @@ -2,7 +2,7 @@ A Moshpit name can now say how to reach whoever holds it, without saying who that is. The holder gives an address they read; the registry publishes -`k7m2xqbn3f@moshcode.sh`, which forwards to it. The real address is never in a +`k7m2xqbn3f@names.moshcode.sh`, which forwards to it. The real address is never in a page, an API response, or the allocation log. This is opt-in and off by default. A name with no contact publishes nothing, @@ -29,7 +29,7 @@ A holder picks one per name or ending, on `/pit/contact`: | visibility | what a visitor sees | |---|---| -| `guard` | `@moshcode.sh`, forwarding to them. The default. | +| `guard` | `@names.moshcode.sh`, forwarding to them. The default. | | `public` | the address they typed, as typed. For a role address they are happy to expose. | | `none` | nothing — but the token is kept, so switching back on restores the *same* address. | @@ -52,36 +52,49 @@ for the name, an abuse report about it) goes to a stranger. ## Standing the mail host up -Nothing is published until an alias exists at the mail host, and no alias can -exist until `moshcode.sh` receives mail. As of this being written it does not: -the domain has no MX and no SPF record at all. +Nothing is published until an alias exists at the mail host. Guard addresses +live at **`names.moshcode.sh`** — its own subdomain, for two separate reasons: -Three steps, in order. The first is a hand-off — `moshcode.sh` is on Porkbun and -there are no Porkbun credentials on the dev box. +- `pit.moshcode.sh` is a **CNAME** to Railway, and a CNAME cannot coexist with + an MX at the same name. Mail there is impossible, not merely unconfigured. +- The apex would work (Porkbun's ALIAS is a flattened A, not a CNAME) but it + would put the reputation of forwarded stranger mail on the same name as any + staff mail `moshcode.sh` ever carries. Forwarding is the hardest + deliverability case there is, so it gets a name of its own to damage. -**1. DNS on `moshcode.sh`.** MX is independent of the A record, so this does not -disturb `pit.` or `app.`: +**1. DNS — done (2026-08-29).** Added via the Porkbun API and verified +authoritative. `pit.` and `app.` are untouched. ``` -moshcode.sh. MX 10 mx1.forwardemail.net. -moshcode.sh. MX 10 mx2.forwardemail.net. -moshcode.sh. TXT "v=spf1 include:spf.forwardemail.net -all" +names.moshcode.sh. MX 10 mx1.forwardemail.net. +names.moshcode.sh. MX 10 mx2.forwardemail.net. +names.moshcode.sh. TXT "v=spf1 include:spf.forwardemail.net -all" +_dmarc.names.moshcode.sh. TXT "v=DMARC1; p=none;" ``` -Forward Email also issues a `forward-email-site-verification=…` TXT record when -the domain is added to the account; add it with the rest. A `_dmarc` TXT of -`v=DMARC1; p=none;` is worth having and is not required for forwarding. +DMARC is `p=none` on purpose: report only, because an aggressive policy bites a +forwarder first and nothing should be quarantined while the setup is unproven. -**2. The domain on the Forward Email account.** Add `moshcode.sh` there and -confirm the plan covers API alias management — the free tier forwards mail but -programmatic alias creation is a paid feature, and every mint fails without it. +The Porkbun credentials are `PORKBUN_API_KEY` / `PORKBUN_SECRET_API_KEY` in the +logicsrc vault `profullstack-sharable-keys--prod`. -**3. The key, in the vault.** `FORWARDEMAIL_API_KEY` on the `moshcode` Railway -service, set from the logicsrc vault rather than committed to a `.env`. -`MOSHPIT_GUARD_DOMAIN` defaults to `moshcode.sh` and only needs setting to move -the addresses somewhere else. +> **Checking these from the dev box:** always `dig ... @1.1.1.1`. The box's +> resolver is the Moshpit DNS bridge, which answers for every `*.moshcode.sh` +> name with a synthesised record — so a bare `dig` will happily tell you a +> host exists when public DNS has never heard of it. -Until all three are done the feature is inert rather than broken: a contact is +**2. The domain on the Forward Email account — outstanding.** Add +`names.moshcode.sh` there, add the `forward-email-site-verification=…` TXT it +issues, and confirm the plan covers **API alias management**. Every mint fails +without API access; which tier that needs is worth checking at signup rather +than assumed. + +**3. The key — outstanding.** `FORWARDEMAIL_API_KEY` on the `moshcode` Railway +service, from the logicsrc vault rather than a committed `.env`. +`MOSHPIT_GUARD_DOMAIN` already defaults to `names.moshcode.sh`, so it only needs +setting to move the addresses somewhere else. + +Until 2 and 3 are done the feature is inert rather than broken: a contact is recorded, `alias_status` stays `pending`, `/pit/contact` says plainly that no mail host is configured, and nothing is published on any name.