wacns

Home / TIL

One Worker, one site, and a 404 for every unknown subdomain

· 2 min read

I wanted any subdomain that doesn’t exist, like hello.example.com, to show my own 404 page instead of a “site can’t be reached” error, without touching the subdomains that already run real apps. Three Cloudflare details made it work.

1. A wildcard record never beats a real one

A proxied AAAA record for *.example.com pointing to 100:: (Cloudflare’s placeholder for “handled at the edge”) catches every name that has no record of its own. Explicit records always win, so existing subdomains resolve exactly as before.

2. A route with no Worker is a valid route

A Worker route *.example.com/* sends all those requests to one Worker. To keep an app out of it, add a more specific route like app.example.com/* and attach no Worker. The most specific route wins, so app traffic never reaches the Worker at all.

3. A static-assets Worker can run code first

Setting run_worker_first: true in wrangler.jsonc gives the script every request before the static files are served, so it can decide by hostname:

const SITE_HOSTS = new Set(["example.com", "www.example.com"]);
const APP_HOSTS  = new Set(["app.example.com"]);

export default {
  async fetch(request, env) {
    const host = new URL(request.url).hostname;
    if (SITE_HOSTS.has(host)) return env.ASSETS.fetch(request);
    if (APP_HOSTS.has(host))  return fetch(request);  // safety net

    const page = await env.ASSETS.fetch(new URL("/404.html", request.url));
    return new Response(page.body, { status: 404, headers: page.headers });
  },
};

One thing to remember: the catch-all is greedy. Every new app subdomain needs its own no-Worker route, or it gets the 404 page too.