Author: 2026-04-28 surface-area review (Kristerpher + Claude) Status: living document — update when surfaces are added or postures change.
Pre-launch, default to least exposure. Operator surfaces (console, vault, internal docs) are CF Access gated. Customer-facing surfaces that are not yet ready for customers (Antlers app, customer docs, support portal) get a CF Access gate too — invite-only access via Cloudflare Zero Trust until GA. Marketing site (getraxx.com) and the company brand site (moosequest.net) stay public.
Heroku origin URLs (*.herokuapp.com) bypass Cloudflare entirely. The Cloudflare-origin guard middleware (#252 / PR #443 + console port) rejects any request that did not transit Cloudflare.
| Surface | Audience | Posture today | Target posture | Action |
|---|---|---|---|---|
raxx.app |
Antlers customer app | public, noindex | CF Access (Zero Trust) until GA | Operator: add CF Access policy on raxx-app Pages project |
www.raxx.app |
redirect | DNS NXDOMAIN | redirect → raxx.app apex |
Operator: CNAME + page rule |
api.raxx.app |
Antlers ↔ API | CF Access | CF Access until GA → public + auth-required at GA | No change today |
api-staging.raxx.app |
pre-launch testing | CF Access ✓ + Heroku origin EXPOSED | Same + origin guard ON | Operator: enable FLAG_ENFORCE_CF_ORIGIN=true on raxx-api-staging |
console.raxx.app |
operator only | CF Access ✓ + Heroku origin EXPOSED | Same + origin guard ON (this PR ports the middleware) | Merge this PR + enable FLAG_ENFORCE_CF_ORIGIN=true on raxx-console-prod |
vault.raxx.app |
bot identities + operator | CF Access ✓ | No change | — |
getraxx.com |
marketing | DNS NXDOMAIN | public + WAF + rate limit | Operator: fix DNS |
internal-docs.raxx.app |
internal docs + design (branded URL) | CF Access ✓ (via #572) | No change | — |
raxx-mockups.pages.dev |
internal docs + design (origin, still gated) | CF Access ✓ | No change | — |
raxx-app.pages.dev |
preview deploys | CF Access ✓ | No change | — |
raxx-api-prod-…herokuapp.com |
should be unreachable | partially exposed (502) | unreachable | Operator: enable FLAG_ENFORCE_CF_ORIGIN=true on raxx-api-prod (after staging soak) |
raxx-api-staging-…herokuapp.com |
should be unreachable | fully exposed (200) | unreachable | Operator: enable flag on raxx-api-staging |
raxx-console-prod-…herokuapp.com |
should be unreachable | fully exposed (200) | unreachable | Merge this PR + enable flag on raxx-console-prod |
support.raxx.app |
tickets | doesn't exist | CF Access on /admin/*, public on customer portal |
#449 (FreeScout deploy) |
docs.raxx.app |
customer docs | doesn't exist | public + indexable | #423 (sub of #104) |
status.raxx.app |
public status / health page | CF Pages project raxx-status + holding page (#602) |
public, no CF Access, indexable | #602 done; React app ships in #604 |
moosequest.net |
brand / studio | public ✓ | public, registrar locked | #217 |
repo (raxx-app/TradeMasterAPI) |
engineering | private ✓ | No change | — |
heroku config:set FLAG_ENFORCE_CF_ORIGIN=true --app raxx-api-staging
heroku ps:restart --app raxx-api-staging
Verify after restart:
# Direct origin → 403 (the change worked)
curl -i https://raxx-api-staging-1a19fb3873b9.herokuapp.com/api/system/status
# CF-proxied → still 200 (CF Access protects this so you'll see the access redirect; that's correct)
curl -i https://api-staging.raxx.app/api/system/status
Soak ≥24 h. Watch heroku logs --app raxx-api-staging --tail | grep direct_origin_blocked for false positives.
heroku config:set FLAG_ENFORCE_CF_ORIGIN=true --app raxx-api-prod
heroku ps:restart --app raxx-api-prod
Same verify pattern.
heroku config:set FLAG_ENFORCE_CF_ORIGIN=true --app raxx-console-prod
heroku ps:restart --app raxx-console-prod
Verify: curl https://raxx-console-prod-ff30a22abccb.herokuapp.com/health still returns 200 (allowlisted), but curl https://raxx-console-prod-ff30a22abccb.herokuapp.com/secrets now returns 403.
raxx.app (pre-launch)Cloudflare Zero Trust → Access → Applications → + Add an application → Self-hosted
Raxx Antlers (pre-launch)raxx.app, plus *.raxx.app if you want to cover subdomains broadlykris@moosequest.net is on it)kris@moosequest.net (+ any ops support emails)When you go GA, either delete the application or change the policy to "Allow everyone" (effectively no gate).
getraxx.com DNSCloudflare DNS panel → confirm:
getraxx.com A or CNAME points at the CF Pages project (getraxx.pages.dev)If the CF Pages project is missing, run wrangler pages project create getraxx then deploy via the existing pipeline.
www.raxx.app redirectCloudflare DNS panel:
www CNAME → raxx.app (proxied)www.raxx.app/* → 301 → https://raxx.app/$1support.raxx.app — when #449 lands, gate /admin/* only.docs.raxx.app — when #423 ships, fully public + indexable.status.raxx.app — live as of #602 (holding page); React app (#604) replaces it. Stays public, no Access gate, indexable forever.vault.raxx.app via CF Access service tokens; replicate to other internal-only surfaces if traffic patterns demand.backend_v2support.raxx.appdocs.raxx.appdocs/architecture/break-glass-auth.md (#334) — how an operator regains access if CF Access locks them out