diff --git a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/developing-with-wrangler.mdx b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/developing-with-wrangler.mdx index e0f0ec8c72af37..0103ff0411c84d 100644 --- a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/developing-with-wrangler.mdx +++ b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/developing-with-wrangler.mdx @@ -2,7 +2,7 @@ pcx_content_type: how-to title: Local development sidebar: - order: 3 + order: 5 --- import { Render, PackageManagers, WranglerConfig } from "~/components"; diff --git a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx index ff08b8017b2065..f43fc513d3c4c9 100644 --- a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx +++ b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/dynamic-dispatch.mdx @@ -2,7 +2,7 @@ pcx_content_type: how-to title: Create a dynamic dispatch Worker sidebar: - order: 3 + order: 2 --- diff --git a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/hostname-routing.mdx b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/hostname-routing.mdx new file mode 100644 index 00000000000000..7edcf6b773e3c9 --- /dev/null +++ b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/hostname-routing.mdx @@ -0,0 +1,112 @@ +--- +pcx_content_type: how-to +title: Hostname routing +description: Learn how to route requests to the dispatch worker. +sidebar: + order: 3 +--- + +import { Render, PackageManagers, WranglerConfig } from "~/components"; + +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. 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/). + +## (Recommended) Wildcard route with a dispatch Worker + +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: +- **Support both subdomains and vanity domains**: Handle `customer1.myplatform.com` (subdomain) and `shop.customer.com` (custom hostname) with the same routing logic. +- **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. +- **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. + +:::note +This will route all traffic inbound to the domain to the dispatch Worker. +::: + +If you'd like to exclude certain hostnames from routing to the dispatch Worker, you can either: +- 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) +- 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. + +### Setup + +To set up hostname routing with a wildcard route: + +1. **Configure custom hostnames**: Set up your domain and custom hostnames using [Cloudflare for SaaS](/cloudflare-for-platforms/cloudflare-for-saas/) +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`). +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/). +4. **Create wildcard route**: Add a `*/*` route on your platform domain (e.g. saas.com) and associate it with your dispatch Worker. +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. + +:::note +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. +::: + +#### Example dispatch Worker + +```js +export default { + async fetch(request, env) { + const hostname = new URL(request.url).hostname; + + // Get custom hostname metadata for routing decisions + const hostnameData = await env.KV.get(`hostname:${hostname}`, { type: 'json' }); + + if (!hostnameData?.workerName) { + return new Response('Hostname not configured', { status: 404 }); + } + + // Route to the appropriate user Worker + const userWorker = env.DISPATCHER.get(hostnameData.workerName); + return await userWorker.fetch(request); + } +}; +``` + +## Subdomain routing + +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. + +### Setup + +To set up subdomain routing: + +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`). +2. Set wildcard route: `*.saas.com/*` pointing to your dispatch Worker +3. Add logic to the dispatch Worker to route subdomain requests to the right Worker. + +#### Example subdomain dispatch Worker + +```js +export default { + async fetch(request, env) { + const url = new URL(request.url); + const subdomain = url.hostname.split('.')[0]; + + // Route based on subdomain + if (subdomain && subdomain !== 'saas') { + const userWorker = env.DISPATCHER.get(subdomain); + return await userWorker.fetch(request); + } + + return new Response('Invalid subdomain', { status: 400 }); + } +}; +``` + +### Orange-to-Orange (o2o) Behavior + +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) + +This can cause inconsistent behavior when using specific hostname routes: +- 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. +- 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. + +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. + +#### Worker invocation across route configurations and proxy modes + +The table below shows when Workers are invoked based on your route pattern and the customer's DNS proxy settings: + +| Route Pattern | Custom Hostname (Orange Cloud) | Custom Hostname (Grey Cloud) | +|-----------------------|--------------|------------| +| `*/*` (Recommended) | ✅ | ✅ | +| Target hostname route | ✅ | ❌ | +| Custom hostname route | ❌ | ✅ | \ No newline at end of file diff --git a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/user-workers.mdx b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/user-workers.mdx index 9390ba320a46ab..5de64a58e47b68 100644 --- a/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/user-workers.mdx +++ b/src/content/docs/cloudflare-for-platforms/workers-for-platforms/get-started/user-workers.mdx @@ -2,7 +2,7 @@ pcx_content_type: how-to title: Uploading User Workers sidebar: - order: 3 + order: 4 --- [User Workers](/cloudflare-for-platforms/workers-for-platforms/reference/how-workers-for-platforms-works/#user-workers) contain code written by your end users (end developers).