|
| 1 | +--- |
| 2 | +pcx_content_type: how-to |
| 3 | +title: Hostname routing |
| 4 | +description: Learn how to route requests to the dispatch worker. |
| 5 | +sidebar: |
| 6 | + order: 3 |
| 7 | +--- |
| 8 | + |
| 9 | +import { Render, PackageManagers, WranglerConfig } from "~/components"; |
| 10 | + |
| 11 | +You can use [dynamic dispatch](/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch/) Workers to route millions of vanity domains or subdomains to Workers without hitting traditional [route limits](/workers/platform/limits/#number-of-routes-per-zone). These hostnames can be subdomains under your managed domain (e.g. `customer1.saas.com`) or vanity domains controlled by your end customers (e.g. `mystore.com`), which can be managed through [custom hostnames](/cloudflare-for-platforms/cloudflare-for-saas/domain-support/). |
| 12 | + |
| 13 | +## (Recommended) Wildcard route with a dispatch Worker |
| 14 | + |
| 15 | +Configure a wildcard [Route](/workers/configuration/routing/routes/) (`*/*`) on your SaaS domain (the domain where you configure custom hostnames) to point to your dynamic dispatch Worker. This allows you to: |
| 16 | +- **Support both subdomains and vanity domains**: Handle `customer1.myplatform.com` (subdomain) and `shop.customer.com` (custom hostname) with the same routing logic. |
| 17 | +- **Avoid route limits**: Instead of creating individual routes for every domain, which can cause you to hit [Routes limits](/workers/platform/limits/#number-of-routes-per-zone), you can handle the routing logic in code and proxy millions of domains to individual Workers. |
| 18 | +- **Programmatically control routing logic**: Write custom code to route requests based on hostname, [custom metadata](/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/), path, or any other properties. |
| 19 | + |
| 20 | +:::note |
| 21 | +This will route all traffic inbound to the domain to the dispatch Worker. |
| 22 | +::: |
| 23 | + |
| 24 | +If you'd like to exclude certain hostnames from routing to the dispatch Worker, you can either: |
| 25 | +- Add routes without a Worker specification to opt certain hostnames or paths from being executed by the dispatcher Worker (for example, for `saas.com`, `api.saas.com`, etc) |
| 26 | +- Use a [dedicated domain](/dns/zone-setups/subdomain-setup/) (for example, `customers.saas.com`) for custom hostname and dispatch worker management to keep the rest of the traffic for that domain separate. |
| 27 | + |
| 28 | +### Setup |
| 29 | + |
| 30 | +To set up hostname routing with a wildcard route: |
| 31 | + |
| 32 | +1. **Configure custom hostnames**: Set up your domain and custom hostnames using [Cloudflare for SaaS](/cloudflare-for-platforms/cloudflare-for-saas/) |
| 33 | +2. **Set the fallback origin**: Set up a [fallback origin server](/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#1-create-fallback-origin), this is where all custom hostnames will be routed to. If you’d like to route them to separate origins, you can use a [custom origin server](/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/custom-origin/). Requests will route through the Worker before reaching the origin. If the Worker is the origin then place a dummy DNS record for the fallback origin (e.g., `A 192.0.2.0`). |
| 34 | +3. **Configure DNS**: Point DNS records (subdomains or custom hostname) via [CNAME record to the saas domain](/cloudflare-for-platforms/cloudflare-for-saas/start/getting-started/#3-have-customer-create-cname-record). If your customers need to proxy their apex hostname (e.g. `example.com`) and cannot use CNAME records, check out [Apex Proxying](/cloudflare-for-platforms/cloudflare-for-saas/start/advanced-settings/apex-proxying/). |
| 35 | +4. **Create wildcard route**: Add a `*/*` route on your platform domain (e.g. saas.com) and associate it with your dispatch Worker. |
| 36 | +5. **Implement dispatch logic**: Add logic to your dispatch Worker to route based on hostname, lookup mappings stored in [Workers KV]([Workers KV](/kv/)), or use [custom metadata](/cloudflare-for-platforms/cloudflare-for-saas/domain-support/custom-metadata/) attached to custom hostnames. |
| 37 | + |
| 38 | +:::note |
| 39 | +If you plan to route requests based on custom metadata, you'll need to create subdomains (e.g. `customer1.saas.com`) as custom hostnames. This is because DNS records do not support custom metadata. |
| 40 | +::: |
| 41 | + |
| 42 | +#### Example dispatch Worker |
| 43 | + |
| 44 | +```js |
| 45 | +export default { |
| 46 | + async fetch(request, env) { |
| 47 | + const hostname = new URL(request.url).hostname; |
| 48 | + |
| 49 | + // Get custom hostname metadata for routing decisions |
| 50 | + const hostnameData = await env.KV.get(`hostname:${hostname}`, { type: 'json' }); |
| 51 | + |
| 52 | + if (!hostnameData?.workerName) { |
| 53 | + return new Response('Hostname not configured', { status: 404 }); |
| 54 | + } |
| 55 | + |
| 56 | + // Route to the appropriate user Worker |
| 57 | + const userWorker = env.DISPATCHER.get(hostnameData.workerName); |
| 58 | + return await userWorker.fetch(request); |
| 59 | + } |
| 60 | +}; |
| 61 | +``` |
| 62 | +
|
| 63 | +## Subdomain routing |
| 64 | +
|
| 65 | +If you're only looking to route subdomain records (e.g. `customer1.saas.com`), you can use a more specific route (`*.saas.com/*`) to route requests to your dispatch Worker. |
| 66 | +
|
| 67 | +### Setup |
| 68 | +
|
| 69 | +To set up subdomain routing: |
| 70 | +
|
| 71 | +1. Create an orange-clouded wildcard DNS record: `*.saas.com` that points to the origin. If the Worker is the origin then you can use a dummy DNS value (for example, `A 192.0.2.0`). |
| 72 | +2. Set wildcard route: `*.saas.com/*` pointing to your dispatch Worker |
| 73 | +3. Add logic to the dispatch Worker to route subdomain requests to the right Worker. |
| 74 | +
|
| 75 | +#### Example subdomain dispatch Worker |
| 76 | +
|
| 77 | +```js |
| 78 | +export default { |
| 79 | + async fetch(request, env) { |
| 80 | + const url = new URL(request.url); |
| 81 | + const subdomain = url.hostname.split('.')[0]; |
| 82 | + |
| 83 | + // Route based on subdomain |
| 84 | + if (subdomain && subdomain !== 'saas') { |
| 85 | + const userWorker = env.DISPATCHER.get(subdomain); |
| 86 | + return await userWorker.fetch(request); |
| 87 | + } |
| 88 | + |
| 89 | + return new Response('Invalid subdomain', { status: 400 }); |
| 90 | + } |
| 91 | +}; |
| 92 | +``` |
| 93 | +
|
| 94 | +### Orange-to-Orange (o2o) Behavior |
| 95 | +
|
| 96 | +When your customers are also using Cloudflare and point their custom domain to your SaaS domain via CNAME (for example, `mystore.com` → `saas.com`), Worker routing behavior depends on whether the customer's DNS record is proxied (orange cloud) or DNS-only (grey cloud). Learn more about [Orange-to-Orange setups](/cloudflare-for-platforms/cloudflare-for-saas/saas-customers/how-it-works/#with-o2o) |
| 97 | +
|
| 98 | +This can cause inconsistent behavior when using specific hostname routes: |
| 99 | +- If you're routing based on the CNAME target (`saas.com`), the custom hostname's DNS record must be orange-clouded for the Worker to be invoked. |
| 100 | +- If you're routing based on the custom hostname (`mystore.com`), the customer's record must be grey-clouded for the Worker to be invoked. |
| 101 | +
|
| 102 | +Since you may not have control over your customer's DNS proxy settings, we recommend using `*/*` wildcard route to ensure routing logic always works as expected, regardless of how DNS is configured. |
| 103 | +
|
| 104 | +#### Worker invocation across route configurations and proxy modes |
| 105 | +
|
| 106 | +The table below shows when Workers are invoked based on your route pattern and the customer's DNS proxy settings: |
| 107 | +
|
| 108 | +| Route Pattern | Custom Hostname (Orange Cloud) | Custom Hostname (Grey Cloud) | |
| 109 | +|-----------------------|--------------|------------| |
| 110 | +| `*/*` (Recommended) | ✅ | ✅ | |
| 111 | +| Target hostname route | ✅ | ❌ | |
| 112 | +| Custom hostname route | ❌ | ✅ | |
0 commit comments