PandaStack

Preview URLs

Expose a port from a sandbox to the public internet with a stable, tokenless URL.

A preview URL is a public hostname that proxies HTTP(S) into a port inside your sandbox. It's how you let a teammate poke at a next dev server, share a Streamlit app with a stakeholder, or hand a webhook URL to a third-party service — without exposing your API key.

The URL is stable and tokenless: the sandbox UUID in the hostname is the credential. Anyone with the link can reach the port until the sandbox is killed. It runs behind the same TLS-terminating edge as the rest of the platform, so your sandbox never needs a public IP.

How it's auth'dThe sandbox UUID is the bearer credential.
Who can reach itAnyone with the URL.
LifetimeUntil the sandbox is killed.
Hostname shapehttps://{port}-{sandboxId}.pandastack.ai
Use it forDev servers, demos, webhooks, multi-port apps.

Treat the preview URL itself as a secret. Anyone who has it can reach that port for the sandbox's lifetime — there is no separate token to revoke, so kill the sandbox (or stop the server on that port) to cut access.

Public preview URLs

If your template runs a server on a port, that port is reachable instantly. Apps deployed on the base runtime start their dev/start command via the pandastack-autostart systemd unit, so the URL works the moment the sandbox is running.

const sandbox = await Sandbox.create({ template: "base" });
console.log(sandbox.previewUrl(3000));
// → https://3000-1a2b3c4d.pandastack.ai
sandbox = Sandbox.create(template="base")
print(sandbox.preview_url(3000))
# → https://3000-1a2b3c4d.pandastack.ai

previewUrl(port) is a pure string-formatter — no API call. The hostname is derived from your client's apiUrl:

apiUrlPreview suffix
https://api.pandastack.aipandastack.ai
https://api.acme.devacme.dev
(self-hosted)Set client.previewHost = "preview.example.com"

Listing all exposed ports

const urls = await sandbox.previewUrls();
// { 3000: "https://3000-…", 9229: "https://9229-…" }
urls = sandbox.preview_urls()
# {3000: "https://3000-…", 9229: "https://9229-…"}

The SDK calls GET /v1/sandboxes/{id}/ports — the in-guest agent reports every listening TCP socket it sees.

Concurrency and rate limits

  • A sandbox can expose up to 32 distinct ports simultaneously. Beyond that, the agent stops registering new ports until older ones close.
  • Each preview hostname carries the same per-key rate limit as the rest of the API (1 req/s burst 10 by default). Override per-org via the cloud dashboard.
  • WebSockets are supported transparently — useful for next dev HMR, Jupyter, and Streamlit.

REST equivalent

GET /v1/sandboxes/{id}/ports

Returns {"ports": [{"port": 3000}, {"port": 9229}]} or the bare array form. Build the URL yourself as https://{port}-{id}.{suffix}.

How it works (one paragraph)

The TLS edge runs as a small Go service in front of every host. When a request arrives at https://3000-{id}.pandastack.ai, the edge extracts id, looks up the host that owns that sandbox in the shared state store, and proxies the TCP connection over the host's tap interface to the guest's NAT IP. No request ever touches a sandbox that doesn't match the hostname.

On this page