A server in a sandbox is reachable from outside only on ports you declare when you create the sandbox, through a preview URL on usercontent.b3os.org.

Declare ports

json
{ "template": "base", "ports": [{ "port": 3000 }, { "port": 8080, "public": true }] }

Up to 8 ports. A port you did not declare answers port_not_exposed.

Private ports

A port is private by default: nobody reaches it without a URL you mint for it. Ask for one when you need it:

bash
curl -s -X POST "https://beta-api.b3os.org/v1/sandboxes/$SBX/ports/3000/url" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"ttl_s": 600}'
json
{ "object": "port_url", "port": 3000, "public": false, "url": "https://usercontent.b3os.org/sbx/sbx-01m5t68q1b590rj801nbzsqzkk/3000/pt1.n1.1792955460.tjsgjiRC3sSYEwneW62TSvNqd-Jo_zzFI5zFYkB_YQBNl0CiBzI9xgoV6EJD_5YEmh3HbzSmb3acL8mY1LmYCg/", "expires_at": "2026-10-25T19:11:00.000Z"}

The token in the path is signed by the node and expires after ttl_s (10 minutes by default, from one minute to 24 hours). Anyone with the URL reaches the port until then, with no cookie or other credential, so share it like a password.

Public ports

A port declared public: true gets a long-lived URL in the sandbox's ports[].url, ready as soon as the sandbox is. Its token lasts 7 days from the sandbox's creation, so the URL stays fixed; a sandbox that runs longer gets a new one.

What your server sees

The preview forwards GET (WebSocket upgrades included), HEAD, POST, PUT, PATCH, DELETE and OPTIONS; other methods get 405. Your server receives the request at the path after the token, with the query string unchanged, plus these headers:

HeaderValue
X-Forwarded-Protohttps
X-Forwarded-Hostusercontent.b3os.org
X-Forwarded-Prefix/sbx/<host_id>/<port>/<token>, the full base path of this request

Cookies are removed in both directions, as everywhere on usercontent.b3os.org. Unless your server sets Referrer-Policy, the preview adds Referrer-Policy: strict-origin, so the token in the path does not leak to other sites. A response must start within 65 seconds; a WebSocket or a streamed body can stay open up to an hour.

Base paths

Your app lives under a path prefix, not at the root of a domain. Two rules keep links working:

  • Emit relative URLs where you can. A URL that ends at the token redirects to the same URL plus /, so relative links resolve under the prefix.
  • For absolute paths, build them from X-Forwarded-Prefix on each request. B3OS_PORT_BASE_PATH in the sandbox's environment is only the fixed start, /sbx/<host_id>, because the port and the token follow it and the token differs for every minted URL.
Warning

In v0.1 every preview shares the usercontent.b3os.org origin. A page served from one preview can send requests to any other preview URL it knows. Keep secrets out of previews. Per-port hostnames are planned.

When it fails

CodeStatusWhen
signed_url_invalid403The token is malformed, expired, or for another sandbox or port
port_not_exposed404The port was not declared when the sandbox was created
sandbox_not_running409The sandbox is paused or stopped
Ask a question... ⌘I