ccnames.dev

cnames.dev / blog

Engineering14 min read

Anatomy of a custom-domains proxy: CNAME to first byte

A deep dive into every stage a request passes through in a multi-tenant custom-domains proxy — DNS, SNI, cert selection, host routing, header shaping, and origin fetch.

S
Saeed
July 5, 2026

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:

⑦ 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.

Building a SaaS that needs custom domains? cnames.dev gives every customer their own domain — SSL, edge routing, and per-tenant isolation in one API call. Free for 25 domains, no demo call. Start free · Read the docs

Frequently asked questions

What does a custom-domains proxy actually do?

It terminates TLS for many customer hostnames on shared IPs, selects the right certificate by SNI, maps the hostname to a tenant and origin, shapes headers (Host, real client IP, per-tenant headers), and proxies the request to that origin — then streams the response back, rewriting redirects and cookies where needed.

Why is SNI central to the design?

One IP serves thousands of domains. The browser sends the target hostname in the TLS SNI field before a certificate is chosen, so the proxy reads SNI to load or issue the correct certificate at the exact moment it is needed. Your cert store is effectively keyed by SNI.

Where does latency come from in a custom-domains proxy?

Cold TLS handshakes (especially first-ever issuance for a host), certificate-store lookups on a cache miss, and the hostname-to-tenant lookup. Keeping the allow-list and cert store in memory or fast KV, and using anycast to shorten the handshake RTT, are the main levers.

Keep reading

S

SaeedFounder, cnames.dev — runs custom-domain infra for 5,000+ production sites at Lindo.ai.