Skip to content

Configure preview URLs on a custom domain

Last updated View as MarkdownAgent setup

Set up wildcard DNS, routes, and TLS so exposePort() preview URLs work on your domain. To deploy the Worker and sandbox image, refer to Deploy a Sandbox application.

Preview URLs need wildcard DNS because each exposed port gets a unique subdomain: https://8080-abc123.yourdomain.com.

The .workers.dev domain does not support wildcard subdomains, so preview URLs that must be reachable on a public hostname outside local development need a custom domain.

Prerequisites

  • Active Cloudflare zone with a domain
  • Worker that uses exposePort()
  • Wrangler CLI installed
  • Sandbox app already deployable (Worker + image)

Setup

Create a wildcard DNS record

In the Cloudflare dashboard, go to your domain and create an A record:

  • Type: A
  • Name: * (wildcard)
  • IPv4 address: 192.0.2.0
  • Proxy status: Proxied (orange cloud)

This routes all subdomains through Cloudflare's proxy. The IP address 192.0.2.0 is a documentation address (RFC 5737) that Cloudflare recognizes when proxied.

Configure Worker routes

Add a wildcard route to your Wrangler configuration:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "my-sandbox-app",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-16",
	"routes": [
		{
			"pattern": "*.yourdomain.com/*",
			"zone_name": "yourdomain.com"
		}
	]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "my-sandbox-app"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-16"

[[routes]]
pattern = "*.yourdomain.com/*"
zone_name = "yourdomain.com"

Replace yourdomain.com with your actual domain. This routes all subdomain requests to your Worker and enables Cloudflare to provision SSL certificates automatically.

Apply the route

Redeploy the Worker so the route configuration takes effect:

npx wrangler deploy

If this deploy also changes your sandbox image or package, follow Deploy a Sandbox application for rollout and package/image pairing. For route-only changes you can still use a normal deploy. Use --containers-rollout=none only when you intentionally skip container image and instance updates.

Verify

Test that preview URLs work:

// Extract hostname from request
const { hostname } = new URL(request.url);

const sandbox = getSandbox(env.Sandbox, "test-sandbox");
await sandbox.startProcess("python -m http.server 8080");
const exposed = await sandbox.exposePort(8080, { hostname });

console.log(exposed.url);
// https://8080-test-sandbox.yourdomain.com

Visit the URL in your browser to confirm your service is accessible.

Troubleshooting

  • CustomDomainRequiredError: Verify your Worker is not deployed only to .workers.dev and that the wildcard DNS record and route are configured correctly.
  • SSL/TLS errors: Wait a few minutes for certificate provisioning. Verify the DNS record is proxied and SSL/TLS mode is set to "Full" or "Full (strict)" in your dashboard. If your Worker is on a subdomain (for example, sandbox.yourdomain.com), Universal SSL will not cover the second-level wildcard *.sandbox.yourdomain.com. Refer to the TLS caution at the top of this page for options.
  • Preview URL not resolving: Confirm the wildcard DNS record exists and is proxied. Wait 30–60 seconds for DNS propagation.
  • Port not accessible: Ensure your service binds to 0.0.0.0 (not localhost) and that proxyToSandbox() is called first in your Worker's fetch handler.

For detailed troubleshooting, see the Workers routing documentation.

Was this helpful?