From 760212b81c2e7d8595a9e299945f086b6e2620d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Nov 2025 20:39:00 +0000 Subject: [PATCH] Update preview URL token format for DNS compliance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated Sandbox SDK documentation to reflect the DNS-compliant token format change from PR #247. Preview URL tokens now use only lowercase alphanumeric characters and hyphens (RFC 952/1123 compliant) instead of including underscores. Changes: - Updated URL format examples to include 16-character tokens - Added migration note about breaking change in SDK v0.5.4+ - Clarified token security characteristics - Updated all code examples with correct URL format This is a breaking change - existing preview URLs with underscores will stop working after SDK upgrade. Users must call exposePort() again to get new DNS-compliant URLs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/content/docs/sandbox/api/ports.mdx | 2 +- .../docs/sandbox/concepts/preview-urls.mdx | 24 ++++++++++++------- .../docs/sandbox/guides/expose-services.mdx | 10 ++++---- .../sandbox/guides/production-deployment.mdx | 4 ++-- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/content/docs/sandbox/api/ports.mdx b/src/content/docs/sandbox/api/ports.mdx index f87cba7f26a9e1..ae0306961e9c21 100644 --- a/src/content/docs/sandbox/api/ports.mdx +++ b/src/content/docs/sandbox/api/ports.mdx @@ -41,7 +41,7 @@ await sandbox.startProcess('python -m http.server 8000'); const exposed = await sandbox.exposePort(8000, { hostname }); console.log('Available at:', exposed.exposedAt); -// https://8000-abc123.yourdomain.com +// https://8000-abc123-a1b2c3d4e5f6g7h8.yourdomain.com // Multiple services with names await sandbox.startProcess('node api.js'); diff --git a/src/content/docs/sandbox/concepts/preview-urls.mdx b/src/content/docs/sandbox/concepts/preview-urls.mdx index 1d98a3b8e41d48..feec2b51653888 100644 --- a/src/content/docs/sandbox/concepts/preview-urls.mdx +++ b/src/content/docs/sandbox/concepts/preview-urls.mdx @@ -19,21 +19,27 @@ await sandbox.startProcess("python -m http.server 8000"); const exposed = await sandbox.exposePort(8000, { hostname }); console.log(exposed.exposedAt); -// Production: https://8000-abc123.yourdomain.com +// Production: https://8000-abc123-a1b2c3d4e5f6g7h8.yourdomain.com // Local dev: http://localhost:8787/... ``` ## URL Format -**Production**: `https://{port}-{sandbox-id}.yourdomain.com` +**Production**: `https://{port}-{sandbox-id}-{token}.yourdomain.com` -- Port 8080: `https://8080-abc123.yourdomain.com` -- Port 3000: `https://3000-abc123.yourdomain.com` +- Port 8080: `https://8080-abc123-a1b2c3d4e5f6g7h8.yourdomain.com` +- Port 3000: `https://3000-abc123-x9y8z7w6v5u4t3s2.yourdomain.com` **Local development**: `http://localhost:8787/...` +The token is a 16-character random string containing only lowercase alphanumeric characters and hyphens, ensuring DNS compliance with RFC 952/1123 hostname requirements. + Preview URLs remain stable while a port is exposed and can be shared during that time. However, if you unexpose and re-expose a port, a new random token is generated and the URL changes. For persistent URLs, keep ports exposed for the duration you need them accessible. +:::note[Token format change - SDK v0.5.4+] +Starting in SDK version 0.5.4, preview URL tokens use only DNS-valid characters (RFC 952/1123 compliant). Tokens generated by earlier versions containing underscores are automatically migrated when you access the sandbox. This is a breaking change - old preview URLs with underscores will stop working after upgrade. Call `exposePort()` again to get new DNS-compliant URLs. +::: + ## ID Case Sensitivity Preview URLs extract the sandbox ID from the hostname to route requests. Since hostnames are case-insensitive (per RFC 3986), they're always lowercased: `8080-MyProject-123.yourdomain.com` becomes `8080-myproject-123.yourdomain.com`. @@ -101,9 +107,9 @@ await sandbox.startProcess("node admin.js"); // Port 3001 const api = await sandbox.exposePort(3000, { hostname, name: "api" }); const admin = await sandbox.exposePort(3001, { hostname, name: "admin" }); -// Each gets its own URL: -// https://3000-abc123.yourdomain.com -// https://3001-abc123.yourdomain.com +// Each gets its own URL with unique tokens: +// https://3000-abc123-x1y2z3w4v5u6t7s8.yourdomain.com +// https://3001-abc123-p9q8r7s6t5u4v3w2.yourdomain.com ``` ## What Works @@ -155,9 +161,9 @@ Preview URLs are publicly accessible by default, but require a valid access toke **Built-in security**: -- **Token-based access** - Each exposed port gets a unique token in the URL (for example, `https://8080-sandbox-abc123token.yourdomain.com`) +- **Token-based access** - Each exposed port gets a unique 16-character token in the URL (for example, `https://8080-sandbox-a1b2c3d4e5f6g7h8.yourdomain.com`) - **HTTPS in production** - All traffic is encrypted with automatic TLS -- **Unpredictable URLs** - Tokens are randomly generated and difficult to guess +- **Unpredictable URLs** - Tokens are cryptographically random and use only DNS-valid characters (lowercase alphanumeric and hyphens per RFC 952/1123) **Add application-level authentication**: diff --git a/src/content/docs/sandbox/guides/expose-services.mdx b/src/content/docs/sandbox/guides/expose-services.mdx index ee82fb05d96dbe..8a4db7bb9e4ce0 100644 --- a/src/content/docs/sandbox/guides/expose-services.mdx +++ b/src/content/docs/sandbox/guides/expose-services.mdx @@ -55,7 +55,7 @@ export default { // 4. Preview URL is now available (public by default) console.log('Server accessible at:', exposed.exposedAt); - // Production: https://8000-abc123.yourdomain.com + // Production: https://8000-abc123-a1b2c3d4e5f6g7h8.yourdomain.com // Local dev: http://localhost:8787/... return Response.json({ url: exposed.exposedAt }); @@ -330,10 +330,12 @@ See [Sandbox options - normalizeId](/sandbox/configuration/sandbox-options/#norm ## Preview URL Format -**Production**: `https://{port}-{sandbox-id}.yourdomain.com` +**Production**: `https://{port}-{sandbox-id}-{token}.yourdomain.com` -- Port 8080: `https://8080-abc123.yourdomain.com` -- Port 5173: `https://5173-abc123.yourdomain.com` +- Port 8080: `https://8080-abc123-a1b2c3d4e5f6g7h8.yourdomain.com` +- Port 5173: `https://5173-abc123-x9y8z7w6v5u4t3s2.yourdomain.com` + +The token is a 16-character random string using only DNS-valid characters (lowercase alphanumeric and hyphens per RFC 952/1123). **Local development**: `http://localhost:8787/...` diff --git a/src/content/docs/sandbox/guides/production-deployment.mdx b/src/content/docs/sandbox/guides/production-deployment.mdx index 11fb445be6c8f7..3a4a7c6474ee97 100644 --- a/src/content/docs/sandbox/guides/production-deployment.mdx +++ b/src/content/docs/sandbox/guides/production-deployment.mdx @@ -12,7 +12,7 @@ import { WranglerConfig } from "~/components"; Custom domain setup is ONLY needed if you use `exposePort()` to expose services from sandboxes. If your application does not expose ports, you can deploy to `.workers.dev` without this configuration. ::: -Deploy your Sandbox SDK application to production with preview URL support. Preview URLs require wildcard DNS routing because they generate unique subdomains for each exposed port: `https://8080-abc123.yourdomain.com`. +Deploy your Sandbox SDK application to production with preview URL support. Preview URLs require wildcard DNS routing because they generate unique subdomains for each exposed port: `https://8080-abc123-a1b2c3d4e5f6g7h8.yourdomain.com`. The `.workers.dev` domain does not support wildcard subdomains, so production deployments that use preview URLs need a custom domain. @@ -74,7 +74,7 @@ await sandbox.startProcess('python -m http.server 8080'); const exposed = await sandbox.exposePort(8080, { hostname }); console.log(exposed.exposedAt); -// https://8080-test-sandbox.yourdomain.com +// https://8080-test-sandbox-a1b2c3d4e5f6g7h8.yourdomain.com ``` Visit the URL in your browser to confirm your service is accessible.