Runtime

How to preview a Vite dev server running in a cloud sandbox

Start vite --port 5173 --strictPort with spawn, allow .runtimehost.com as a host, and open the port's private HTTPS preview.

On Runtime the preview is private by default and hot reload works through it. The address needs a token, WebSockets pass through, and every file the agent writes shows up in the browser without a reload. The sandbox runs Node.js 24.21.0, which Vite 8 supports; Vite 8.3.1 and create-vite 9.2.1 were current on 25 September 2026.

Start Vite and share the port

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.create({ timeoutSeconds: 3600 }); // keeps running after this script endsawait sbx.exec(  "npm create vite@9.2.1 app -- --template react-ts --no-interactive && cd app && npm install --no-fund --no-audit",  { check: true, timeoutMs: 600_000 },);await sbx.spawn("npx vite --port 5173 --strictPort", {  cwd: "/workspace/app",  env: { __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS: ".runtimehost.com" },});await sbx.exec("npx wait-on@9.1.0 tcp:127.0.0.1:5173", { check: true, timeoutMs: 120_000 });const preview = await sbx.previews.create(5173);console.log(preview.urlWithToken); // open once in your browser
Pythonfrom withruntime import Sandboxsbx = Sandbox.create(timeout_seconds=3600)sbx.exec("npm create vite@9.2.1 app -- --template react-ts --no-interactive && cd app && npm install --no-fund --no-audit",         check=True, timeout_ms=600_000)sbx.spawn("npx vite --port 5173 --strictPort", cwd="/workspace/app",          env={"__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS": ".runtimehost.com"})sbx.exec("npx wait-on@9.1.0 tcp:127.0.0.1:5173", check=True, timeout_ms=120_000)preview = sbx.previews.create(5173)print(preview["urlWithToken"])

spawn keeps Vite running after the call returns. A server started with exec, nohup included, ends when its command does. Vite listens on localhost by default, and that is enough: a preview reaches the port inside the sandbox.

Why Vite needs the allowed host

Vite answers only the hostnames in server.allowedHosts, plus localhost and IP addresses, to block DNS rebinding attacks. A preview's address is a name under runtimehost.com, the domain Runtime keeps for everything sandboxes serve, so Vite refuses it until you add it.

Way to allow it Where
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=.runtimehost.com The environment of spawn, as above; no file changes
server: { allowedHosts: [".runtimehost.com"] } vite.config.ts, for a project you keep
allowedHosts: true Not recommended: Vite's docs warn it opens the server to DNS rebinding

A leading dot allows the domain and every name under it. vite preview reads preview.allowedHosts, which defaults to server.allowedHosts.

What the browser shows without it, from a test of Vite 8.3.1 on 25 September 2026 with a preview-shaped host name:

textBlocked request. This host ("5173-abc.runtimehost.com") is not allowed.To allow this host, add "5173-abc.runtimehost.com" to `server.allowedHosts` in vite.config.js.

That was a 403 from both vite and vite preview. With __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=.runtimehost.com set, both answered 200. If an agent reports this page, the variable is missing from the process that runs Vite, often because it was started by hand instead of with the env above.

Hot reload while an agent edits

Vite watches the project's files. Anything written into the sandbox, by files.write, by git pull or by an agent's own editor, reaches the open browser tab over Vite's WebSocket:

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID ?? "");await sbx.files.write(  "/workspace/app/src/App.tsx",  "export default function App() {\n  return <h1>Edited by the agent</h1>;\n}\n",);

--strictPort makes Vite exit when 5173 is taken, instead of moving to the next free port and leaving the preview pointing at nothing. The process list, sbx.processes.list(), shows whether Vite is still running.

Build and serve the production bundle

The dev server transforms files on request. To show what users would get, build once and serve dist with vite preview:

TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID ?? "");await sbx.exec("cd app && npx vite build", { check: true, timeoutMs: 300_000 });await sbx.spawn("npx vite preview --port 4173 --strictPort", {  cwd: "/workspace/app",  env: { __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS: ".runtimehost.com" },});const shared = await sbx.previews.create(4173, { visibility: "public" });console.log(shared.url); // anyone with the address can open itawait sbx.files.download("/workspace/app/dist", "./dist");

A public preview needs no token, which suits a demo link. previews.delete(port) stops sharing, and previews.rotate(port) refuses every private token issued so far.

Skip the install next time

A new sandbox for each project spends most of its first minute in npm install. Build a custom image with the template already installed, and hand its folder to the sandbox user:

Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(    name="vite-react",    recipe={        "env": {"__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS": ".runtimehost.com"},        "commands": [            "npm create vite@9.2.1 app -- --template react-ts --no-interactive",            "cd app && npm install --no-fund --no-audit",            "chown -R 1000:1000 /workspace/app",        ],    },)sbx = runtime.sandboxes.create(image="vite-react")sbx.spawn("npx vite --port 5173 --strictPort", cwd="/workspace/app")print(sbx.previews.create(5173)["urlWithToken"])

The recipe's env becomes the image's environment, so every sandbox from it already allows the preview host.

Ports and addresses

Port What serves it Default in Vite
5173 vite dev server server.port
4173 vite preview preview.port

Any port can take a preview. The trial reaches ports 80 and 443 on the internet, which covers the npm registry.

Sources

Checked 25 September 2026.

  • Vite server options: server.host (localhost), server.port (5173), server.allowedHosts, the leading-dot rule, the DNS rebinding warning and __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS
  • Vite preview options: preview.port (4173) and preview.allowedHosts
  • Vite getting started: npm create vite@latest <name> -- --template and --no-interactive
  • vite on npm: version 8.3.1, Node ^20.19.0 || >=22.12.0; create-vite 9.2.1
  • A local test of Vite 8.3.1 and create-vite 9.2.1 on 25 September 2026: the react-ts template scaffolded with --no-interactive, and the host check answered 403 without the variable and 200 with it, for vite and vite preview

Facts on this page were checked on 25 September 2026.