DNS & Domains¶
How a hostname finds its service — and why customer apps live on a different domain than the product.
(A synthesis page with no legacy § number. Design record:
specs/2026-07-11-region-onboarding-dns-design.md.)
The two-domain split¶
| Domain | Holds | Zone character |
|---|---|---|
starform.io |
Product only — marketing apex · Stardeck (app.) · API (api.) · status page (status., §39.2 #21) |
Small, hand-curated, trusted |
starform.app |
Customer workloads only — per-service records (below) + the wildcard 404 catch-all | Large, machine-managed by DNSProvider, on the PSL |
Three reasons, one line each (the full argument lives in the design record):
- Dashboard protection. Browsers scope cookies by registrable domain; customer apps sharing the product's domain could set or receive cookies against Stardeck. Separate domains = zero shared surface. (Render/Vercel/Fly/Heroku all split the same way.)
- Tenant-vs-tenant protection. A Public Suffix List
private-section entry for
starform.appmakes each customer subdomain its own registrable domain — without it, one tenant can set a.starform.appcookie every other tenant receives. Submission is free (template PR + a permanently-maintained_pslTXT record) but volunteer-reviewed and slow, with browser propagation lag — submit during private beta (§39.2 #72). - Reputation blast radius. Phishing hosted by a bad customer gets flagged at the domain level —
contained to
starform.app, never touching the domain the dashboard, API, and outbound email live on.
PSL is pre-launch-blocking (§39.2 #72)
Until the PSL entry merges and propagates into browsers, tenant-to-tenant cookie isolation on
starform.app does not exist. Acceptable only for a small closed beta.
Hostname generation¶
Default hostnames are single-label, always suffixed — matching Render/Railway/Vercel, so names are unique by construction with no "name taken" path and no squatting.
- Format:
production→<service-name>-<rand4>; any other environment →<service-name>-<environment>-<rand4>(<rand4>= 4 random base36 chars). Single-label only (myapp-p9vq.starform.app, nevera.b.starform.app): Cloudflare Universal SSL covers the apex + the first-level subdomain only, so a deeper label would serve no valid certificate (Universal SSL limits). - Uniqueness: the suffix makes practical collisions vanish;
service_environments.hostnamestaysUNIQUEas the backstop (regenerate the suffix on the astronomically rare clash). - Rename: the customer may edit the hostname (validate + uniqueness-check → one
DNSProviderupdate + the HTTPRoute); the old name releases immediately (the wildcard 404 takes over). The private internal address (Services › Networking) is separate and does not move on a public rename. - Private / worker services get no hostname at all — only public web services do (Services › Networking).
Per-hostname routing — how a hostname finds its region¶
A wildcard record cannot split traffic by region, so routing is one proxied record per public
service in the starform.app zone — the record's name is the service hostname, its content is
the placement region's LB IP:
Type: A · Name: myapp-p9vq · Content: <placement region's DO LB IP> · Proxy: ON
Because the record is proxied, the public internet only ever sees Cloudflare's anycast IPs:
- The user connects to the nearest Cloudflare PoP, TLS terminates at the edge, WAF runs, and Cloudflare opens the origin connection to the placement region's LB over the Origin Certificate — the existing §5 path, now with a per-hostname origin.
- This is the Sevalla/Render pattern (Cloudflare-fronted, hostname carries the region), and it delivers the edge-proximity benefit Fly/Railway built their own anycast networks for, through the CDN layer §5 already mandates.
Record lifecycle (all via the DNSProvider port, which
already defines exactly these operations):
| Event | DNS action |
|---|---|
| First deploy of a web service | Create the proxied record → placement region's LB |
| Region migration (§39.3 #40) | Update one record's content to the new LB IP |
| Service deleted / made private | Delete the record — the wildcard 404 takes over |
| Worker service | No record (no ingress) |
The wildcard's job: *.starform.app remains as a single catch-all pointing at a branded 404
origin. DNS specificity means explicit records always win — so single-region MVP works unchanged,
and region 2 requires no migration event (records are per-service from day one).
Custom domains (post-MVP, §39.3 #27, Cloudflare for
SaaS): the customer's domain CNAMEs to myapp.starform.app — the per-service record doubles as the
canonical target, and the region answer rides along.
Verify at scale
Cloudflare per-zone DNS record limits vs projected public-service count (§39.3 #73) — fine on paid tiers, needs a number checked before the count grows past a few hundred.
Cross-references
The edge→LB→Envoy path these records feed → §5 · the LB whose
IP the record targets → §34 · the DNSProvider port →
Starbase › Ports §10 · hostname → pod matching inside the
cluster (HTTPRoute) → §20.2 · region
onboarding (where a region's LB IP is first recorded) →
Starbase › Region Onboarding · PSL + custom-domain items →
Open Work. Canonical map:
Canonical Sources.