Skip to content

Code Sandbox / Agent Browser

Code Sandbox (sandbox-service) and Agent Browser (browser-service) are two optional advanced services, off by default. Code Sandbox lets agents run code and serve temporary web previews; Agent Browser is self-hosted browser as a service — agents drive a real browser while users watch live. Both log in via the platform’s OAuth flow. This page covers enabling them, OAuth client auto-registration, and public-URL overrides for external-ingress scenarios.

ServiceCapabilityDependency
Code SandboxLets agents run code and serve temporary web previewsThe third-party OpenSandbox (you install it yourself; the platform points at it via OPENSANDBOX_URL)
Agent BrowserLets agents drive a real browser while users watch live over WebRTCThe bundled TURN relay (coturn), enabled together with BROWSER_ENABLED

In the configuration generator, toggle the corresponding module to produce a values.env with these sections, or set SANDBOX_ENABLED / BROWSER_ENABLED to true by hand.

Set the relevant values.env toggle to true, fill in the required fields, and the next install.sh applies it:

Terminal window
# Code Sandbox
SANDBOX_ENABLED=true
SANDBOX_NODE_PORT=30086
SANDBOX_JWT_SECRET= # openssl rand -hex 32
SANDBOX_SERVICE_KEY= # openssl rand -hex 32, shared between browser and sandbox
# Agent Browser (incl. TURN)
BROWSER_ENABLED=true
BROWSER_NODE_PORT=30085
BROWSER_JWT_SECRET= # openssl rand -hex 32
TURN_HOST= # public / LAN IP browsers can reach, required
TURN_AUTH_SECRET= # openssl rand -hex 32

SANDBOX_JWT_SECRET / BROWSER_JWT_SECRET are each service’s session signing key; SANDBOX_SERVICE_KEY is the shared key the browser uses to call the sandbox (reused by the browser when both modules are on). For TURN_HOST and its troubleshooting, see Ingress Integration and “Debugging” below.

Code Sandbox is powered by OpenSandbox (github.com/alibaba/OpenSandbox), a third-party component the platform installer does not install for you. When SANDBOX_ENABLED=true, install.sh deploys nap-sandbox and assumes OpenSandbox is already installed and reachable at OPENSANDBOX_URL.

Install OpenSandbox (controller + server) from its upstream Helm charts, then point the platform at it:

Terminal window
git clone https://github.com/alibaba/OpenSandbox && cd OpenSandbox/kubernetes/charts
helm dependency build opensandbox
helm install opensandbox ./opensandbox \
--namespace nap --create-namespace \
-f <path-to>/optional/sandbox/opensandbox-values.yaml

Running OpenSandbox in the nap namespace lets the platform’s default OPENSANDBOX_URL resolve. If you install OpenSandbox into its own namespace, set OPENSANDBOX_URL explicitly (e.g. http://opensandbox-server.opensandbox-system.svc:80). For the full reference, including mounting the platform’s sandbox pod template, see “Enabling Code Sandbox” in the self-host README.

Both services log in via the platform OAuth flow with fixed client_ids (sandbox-service / browser-service) — they are PKCE public clients with no client_secret. These clients must exist in the control plane’s oauth_clients table, or GET /api/oauth/authorize returns 400 invalid_client at login.

After seeding the admin, install.sh runs a nap-seed-oauth-clients Job that auto-registers these two rows based on the enabled modules — no manual creation on the “applications” page. The registered redirect_uri is the same origin the service computes its own callback from, so they don’t drift:

client_idDefault redirect_uri
sandbox-servicehttp://<NAP_HOST>:<SANDBOX_NODE_PORT>/api/auth/callback
browser-servicehttp://<NAP_HOST>:<BROWSER_NODE_PORT>/api/auth/callback

The Job is idempotent: after changing a NodePort or public URL, re-running install.sh (or install.sh --seed-only) syncs the redirect_uris automatically.

Service addresses are derived from the NodePort by default. When you expose the services through your own ingress / a custom domain (typically INGRESS_MODE=external, see Ingress Integration), the NodePort-form address is neither externally correct nor matches the OAuth callback. Override it with *_PUBLIC_URL:

Terminal window
SANDBOX_PUBLIC_URL=https://sandbox.example.com
BROWSER_PUBLIC_URL=https://browsers.example.com

The override feeds both the service’s own callback address and the registered redirect_uri, keeping them in sync. Leave it blank to keep the original NodePort behavior, which doesn’t affect existing deployments. The address has no trailing slash.

By default agents get their browsers from the Agent Browser service this page installs. To get them from a hosted vendor instead, set the backend and that vendor’s key:

Terminal window
BROWSER_BACKEND=kernel # or browser-use
KERNEL_API_KEY= # BROWSER_USE_API_KEY for browser-use
BackendVendorKey
kernelKernelKERNEL_API_KEY
browser-useBrowser UseBROWSER_USE_API_KEY

The setting applies to the whole platform: every workspace uses the same backend and the same key, and each workspace only sees the browsers it created. The cluster needs outbound access to the vendor.

With a hosted backend, agents no longer use the Agent Browser service, so BROWSER_ENABLED can stay false. The workspace browser panel still talks to that service and does not show browsers created on a hosted backend; users open the live view from the link the agent gives them.

  • Login redirect reports 400 invalid_client — the matching row is missing in oauth_clients. Confirm the seed Job ran and succeeded: kubectl -n <ns> logs job/nap-seed-oauth-clients; the log prints registered "sandbox-service" → .... Re-run manually: install.sh --seed-only.
  • Login callback reports 400 invalid_redirect_uri — the registered redirect_uri doesn’t match the service’s actual callback address. Common when external ingress is configured but *_PUBLIC_URL isn’t set, or a NodePort changed without re-seeding. Set *_PUBLIC_URL and re-run install.sh --seed-only.
  • Browser shows no video / black screen — usually TURN can’t be reached. Verify TURN_HOST is an IP the browser side can actually reach (kubelet auto-detect is unreliable on multi-NIC nodes, so set it explicitly), and that coturn is ready: kubectl -n <ns> get pod -l app=coturn.
  • Sandbox won’t start — first check whether OpenSandbox is installed: kubectl -n <ns> get pod -l app.kubernetes.io/name=opensandbox.