A custom-domains proxy looks simple from the outside: a customer points app.acme.com at you and it serves their app over HTTPS. Inside, a single request passes through six or seven distinct stages, each with its own failure mode. This is the walk from CNAME to first byte, based on the proxy we run for 5,000+ domains.
Browser
│ ① DNS: app.acme.com -> CNAME -> anycast edge IP
▼
│ ② TCP + ③ TLS ClientHello (SNI = app.acme.com)
▼
Edge node
│ ④ SNI -> allow-list check -> cert (serve or issue)
│ ⑤ hostname -> tenant -> origin + policy
│ ⑥ header shaping (Host, X-Forwarded-For, per-tenant)
▼
Origin ⑦ fetch + stream response (rewrite redirects/cookies)① DNS resolution
The customer's CNAME points at a hostname you own, which resolves to your anycast edge. The indirection is the point: you can renumber the edge without touching customer zones. Apex domains cannot CNAME (the CNAME-at-apex problem) and use A/AAAA to anycast IPs instead.
② TCP to the nearest edge
Anycast routes the connection to the closest edge node by network topology. This is what keeps the TLS handshake RTT low regardless of where the visitor is — the single biggest lever on perceived latency for a global custom-domain fleet.
③ TLS ClientHello and SNI
Before any certificate is chosen, the browser sends the target hostname in the SNI extension. This is the hinge the whole design turns on: with SNI, one IP can serve unlimited distinct certificates, because the proxy learns which hostname it needs at the start of the handshake.
④ Certificate selection (or issuance)
The proxy takes the SNI value and does two things: checks an allow-list(is this a hostname a verified tenant registered?), then loads the certificate from a shared store. On a miss for an allowed host, it issues on demand via ACME and caches the result. The allow-list is the security boundary — without it, anyone pointing DNS at you triggers unbounded issuance and burns your CA limits. The mechanics and the limits are in Let's Encrypt rate limits at scale.
⑤ Hostname to tenant to origin
With TLS established, the proxy maps the hostname to a tenant and an origin plus policy. This lookup runs on every request, so it lives in memory or fast KV. Critically it must fail closed: an unknown or unverified host returns an error, never a default tenant. A permissive fallthrough here is a cross-tenant data leak, not a 404.
⑥ Header shaping
Before the origin fetch, the proxy rewrites the request:
- Host — preserve the customer domain or map it to an internal tenant identifier the origin understands.
- Real client IP — forward via
X-Forwarded-For/X-Real-IPor PROXY protocol, since the origin otherwise sees your edge. Details in why we give you the real client IP. - Per-tenant headers — inject anything the tenant configured (feature flags, plan tier, auth context).
⑦ Origin fetch and response
Finally the proxy connects to the origin (which may itself be multi-tenant), streams the response back, and rewrites what needs rewriting — Location redirects that leak the internal host, cookie Domain attributes, and any absolute URLs in headers. Get this wrong and login redirects bounce customers to your internal hostname.
The takeaway
None of these stages is individually hard. The difficulty is that they are all on the hot path, they all fail in production-specific ways, and the security-sensitive ones (allow-list, fail-closed routing, cert issuance) have no margin for error. That is why we packaged the whole pipeline into cnames.dev — the full design rationale is in the complete guide, and the production story in how we run SSL for 5,000+ domains.