ccnames.dev

cnames.dev / blog

Tutorial13 min read

How to add custom domains to a Cloudflare Workers app

Route customer hostnames in a Cloudflare Worker, the options for SSL (Custom Hostnames vs a proxy), and where each approach breaks. DIY and the one-API-call way.

S
Saeed
July 4, 2026

Adding custom domains to a Cloudflare Workers app is mostly a question of who issues the SSL certificate. The Worker itself can route by hostname in a couple of lines — but Workers do not mint certificates for domains your customers own. You either use Cloudflare for SaaS Custom Hostnames, or put a provider-independent proxy in front. Here are both paths, honestly.

// worker.ts — route by the hostname the visitor used
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const host = new URL(request.url).hostname;

    if (host === 'yourapp.com' || host.endsWith('.yourapp.com')) {
      return handleOwnDomain(request, env);
    }

    const tenant = await env.TENANTS.get(host, 'json'); // KV lookup
    if (!tenant) return new Response('Unknown domain', { status: 404 }); // fail closed
    return handleTenant(request, env, tenant);
  },
};

The SSL decision (this is the whole post)

Option A — Cloudflare for SaaS (Custom Hostnames)

Cloudflare issues and renews a certificate for each customer hostname and routes it to your zone / Worker. You call their API to add a custom hostname:

curl -X POST \
  "https://api.cloudflare.com/client/v4/zones/$ZONE/custom_hostnames" \
  -H "Authorization: Bearer $CF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hostname":"app.customer.com","ssl":{"method":"http","type":"dv"}}'

The customer CNAMEs app.customer.com to your SaaS fallback origin, Cloudflare validates and issues, and your Worker sees the hostname. It works well — if you are happy being all-in on Cloudflare and with per-hostname pricing. We lay out when that is and is not the right call in the Cloudflare for SaaS alternative comparison.

Option B — A provider-independent proxy in front of the Worker

If you want the domain + SSL layer decoupled from Cloudflare (multi-CDN, portability, your own header/redirect policies), terminate TLS on an independent edge and proxy to your Worker. Your Worker code above does not change — it still routes by host.

Routing and failing closed

However you provision, the Worker resolves the hostname to a tenant from KV, D1, or your API and 404s unknown hosts. A permissive default here is a cross-tenant data leak, not a cosmetic bug. Keep the lookup in KV or cache it — it is on every request.

The one-API-call way

cnames.dev gives you the Option B edge without building it: register a hostname pointed at your Worker (or any origin) and SSL, routing, and real client IP are handled, without tying your domain layer to a single CDN.

curl -X POST https://api.cnames.dev/v1/domains \
  -H "Authorization: Bearer sk_live_..." \
  -d '{"hostname":"app.customer.com","origin":"your-worker.example.workers.dev"}'

Verify the customer's record with the CNAME checker, and read the full architecture in the complete guide.

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

Do Workers get the custom domain in the request?

Yes. request.headers.get("host") (and the URL) reflect the hostname the visitor used, so you can route by it. What Workers do not do on their own is issue TLS certificates for arbitrary customer hostnames — that is Cloudflare for SaaS Custom Hostnames or an upstream proxy.

What is Cloudflare for SaaS vs a Worker route?

A Worker route/custom domain attaches your Worker to domains in your own zone. Cloudflare for SaaS (Custom Hostnames) is the product that issues certificates and routes traffic for domains your customers own but you do not. For customer-owned domains you need the latter, or an external proxy.

Can I avoid being locked into Cloudflare for the whole stack?

Yes — front your Worker (or any origin) with a provider-independent custom-domains layer so the domain/SSL layer is not tied to one CDN. That trade-off is exactly what our Cloudflare for SaaS comparison covers.

Keep reading

S

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