Documentation Index
Fetch the complete documentation index at: https://mintlify.com/opensandbox-group/OpenSandbox/llms.txt
Use this file to discover all available pages before exploring further.
OpenSandbox is built from four cooperating system components. Each component owns a distinct responsibility and communicates with the others over well-defined interfaces: the server manages lifecycle from the outside, execd handles execution from inside the sandbox, ingress routes external HTTP and WebSocket traffic to the right sandbox on Kubernetes, and egress enforces outbound network policy from within the sandbox’s own network namespace. Together they form a layered architecture that separates control, execution, routing, and security concerns cleanly.
Components at a Glance
| Component | Language | Role |
|---|
| Server | Python (FastAPI) | Lifecycle control plane — creates, monitors, and terminates sandboxes across Docker and Kubernetes |
| Execd | Go (Gin) | In-sandbox execution daemon — HTTP APIs for shell, files, PTY, code, and metrics |
| Ingress | Go | HTTP/WebSocket reverse proxy — routes Kubernetes traffic to sandbox instances via header or URI mode |
| Egress | Go | Per-sandbox FQDN egress sidecar — enforces allowlists, credential injection, and network policy |
Component Interaction
┌─────────────┐ ┌─────────────┐
│ SDK/CLI │────▶│ Ingress │──────────────────┐
└─────────────┘ │ (K8s only) │ │
└─────────────┘ │
▼
┌─────────────┐ ┌──────────────────────────────────────────┐
│ Server │────▶│ Sandbox Pod / Container │
│ (Control │ │ │
│ Plane) │ │ ┌──────────────────┐ ┌──────────────┐ │
│ │ │ │ execd :44772 │ │ Egress │ │
│ │ │ │ • /command │ │ :18080 │ │
│ │ │ │ • /session │ │ • /policy │ │
│ │ │ │ • /files │ │ • DNS proxy │ │
│ │ │ │ • /code │ │ • nftables │ │
│ │ │ │ • /pty │ │ │ │
│ │ │ │ • /metrics │ │ │ │
│ │ │ └──────────────────┘ └──────────────┘ │
│ │ │ │
│ │ │ ┌──────────────────────────────────────┐ │
│ │ │ │ User Workload Container │ │
│ │ │ │ (user image + entrypoint) │ │
│ │ │ └──────────────────────────────────────┘ │
└─────────────┘ └──────────────────────────────────────────┘
Server
The server (server/) is the lifecycle control plane for the entire platform. It is a FastAPI application that authenticates incoming requests, validates configuration, persists server-managed metadata, and delegates all runtime work to either a Docker or Kubernetes service implementation.
Key responsibilities
- API layer — HTTP request handling, input validation, and response formatting
- Service layer — business logic for create, pause, resume, renew, and delete across runtimes
- Middleware — API-key authentication via
OPEN-SANDBOX-API-KEY header and request ID propagation
- Runtime selection — routes lifecycle operations to
DockerSandboxService or KubernetesSandboxService based on [runtime].type
- Persistence — stores snapshot metadata and other server-managed records in SQLite (or a configured
[store] backend)
- Proxy and endpoint resolution — returns reachable sandbox endpoints; proxies HTTP and WebSocket traffic at
/sandboxes/{id}/proxy/{port} when use_server_proxy=true
Key API endpoints
| Method | Path | Description |
|---|
GET | /health | Server health check (unauthenticated) |
POST | /v1/sandboxes | Create a new sandbox |
GET | /v1/sandboxes/{id} | Get sandbox state and metadata |
POST | /v1/sandboxes/{id}/pause | Pause a running sandbox |
POST | /v1/sandboxes/{id}/resume | Resume a paused sandbox |
POST | /v1/sandboxes/{id}/renew-expiration | Extend sandbox TTL |
GET | /v1/sandboxes/{id}/endpoints/{port} | Resolve a sandbox service endpoint |
DELETE | /v1/sandboxes/{id} | Delete a sandbox |
GET | /docs | Swagger UI (unauthenticated) |
GET | /redoc | ReDoc reference (unauthenticated) |
See Server Deployment for the full installation and configuration guide.
Execd
execd (components/execd/) is a Go daemon built with the Gin framework. It runs inside every OpenSandbox sandbox and exposes the in-sandbox execution API. It is the bridge between the external SDK or CLI and the processes, files, and code running inside the sandbox container.
Key responsibilities
- Shell commands — execute commands with Server-Sent Events streaming of stdout/stderr
- Background commands — start commands, poll status, and fetch incremental logs
- Persistent bash sessions — stateful shell sessions with input/output streaming
- PTY sessions — interactive terminal over WebSocket (
/pty)
- File and directory operations — read, write, list, stat, delete files and directories
- Code execution — Jupyter-backed code contexts for Python, Java, Node.js, Go, and TypeScript; translates kernel messages into OpenSandbox streaming events
- Metrics — point-in-time CPU/memory snapshot (
/metrics) and 1-second SSE stream (/metrics/watch); optional OTLP metrics export
Default port
execd listens on port 44772 inside the sandbox container. The Docker runtime maps this port to a random host port. In bridge mode, this single mapped port serves as the entry point for all sandbox services via the built-in reverse proxy (see Network Architecture).
Injection mechanism
The server stages the execd binary from the configured execd_image into the container filesystem and installs a bootstrap launcher script before the user entrypoint starts.
An init container copies execd and bootstrap.sh from the execd_image into an emptyDir volume mounted by the main sandbox container. No modification to user images is required.
Execd CLI flags and environment variables
| Flag / Env var | Default | Description |
|---|
--port / — | 44772 | HTTP listen port |
--jupyter-host / JUPYTER_HOST | "" | Jupyter server URL for code execution |
--jupyter-token / JUPYTER_TOKEN | "" | Jupyter authentication token |
--access-token / EXECD_ACCESS_TOKEN | "" | Optional shared API token; enforced via X-EXECD-ACCESS-TOKEN header |
--log-level | 6 (Info) | 0=Emergency … 7=Debug |
--graceful-shutdown-timeout / EXECD_API_GRACE_SHUTDOWN | 1s | SSE tail-drain wait before shutdown |
EXECD_CLONE3_COMPAT | unset | Set 1/true for seccomp clone3 fallback in restricted sandbox environments |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | unset | Enable OTLP metrics export |
Health check
curl http://localhost:44772/ping
Ingress
ingress (components/ingress/) is a Kubernetes-oriented HTTP and WebSocket reverse proxy written in Go. It watches BatchSandbox and AgentSandbox custom resources across all namespaces and routes incoming traffic to the correct sandbox pod based on request headers or URI structure.
Key responsibilities
- Sandbox discovery — watches CRs via informer cache; reads endpoints from the
sandbox.opensandbox.io/endpoints annotation (BatchSandbox) or status.serviceFQDN (AgentSandbox)
- Traffic routing — dispatches each request to the right sandbox pod and port
- Protocol support — HTTP and WebSocket (forwards
Upgrade, Connection, and X-Forwarded-* headers)
- Health check — exposes
GET /status.ok
- Auto-renew integration — optionally publishes renew-intent events to Redis on each proxied request
Routing modes
Error codes
| Condition | HTTP status |
|---|
| Sandbox CR not found | 404 |
| Sandbox not ready (insufficient replicas, missing endpoints) | 503 |
| Kubernetes API error or other internal error | 502 |
Starting ingress
go run main.go \
--provider-type batchsandbox \
--mode header \
--port 28888 \
--log-level info
Egress
egress (components/egress/) is a per-sandbox FQDN egress control sidecar. It runs alongside the user workload container, sharing its network namespace, and enforces outbound network policy via DNS proxying and optional nftables rules.
Key responsibilities
- DNS proxy (Layer 1) — intercepts all port-53 DNS traffic via
iptables redirect; returns NXDOMAIN for denied domains; runs on 127.0.0.1:15353
- Network filter (Layer 2) — in
dns+nft mode, adds nftables rules for resolved IPs of allowed domains with TTL so that default-deny is enforced at the network layer
- Allow/deny rules — FQDN patterns, wildcard domains (
*.pypi.org), IP addresses, and CIDR ranges
- Always-rules — platform-managed
deny.always and allow.always files that cannot be overridden by user policy
- Credential vault — injects bearer, basic, API-key, or custom header credentials into matching outbound HTTPS requests via transparent mitmproxy
- Runtime policy API — HTTP endpoints for inspecting and patching policy at runtime
Egress HTTP API
| Method | Path | Description |
|---|
GET | /policy | Get current policy and enforcement mode |
POST | /policy | Replace policy (empty body resets to deny-all) |
PUT | /policy | Alias for POST /policy |
PATCH | /policy | Append/merge rules (JSON array of egress rule objects) |
DELETE | /policy | Remove rules by target (JSON string array) |
GET | /healthz | Health check — 200 ok when ready |
The egress HTTP API listens on port 18080 by default (configurable via OPENSANDBOX_EGRESS_HTTP_ADDR).
Enforcement modes
| Mode | Description |
|---|
dns | DNS filtering only. Denied domains get NXDOMAIN. IP-based connections are not blocked. |
dns+nft | DNS filtering plus nftables IP enforcement. Recommended for strict default-deny deployments. |
Always-rules files
Static rule files baked into the egress image take precedence over all user-supplied policy and are hot-reloaded every minute.
| File | Priority | Description |
|---|
/var/egress/rules/deny.always | Highest | Always denied; user policy cannot override |
/var/egress/rules/allow.always | High | Always allowed; overrides user deny rules |
/var/egress/rules/log_skip.always | — | Patterns to suppress from denial logs |
Privilege model
- The egress sidecar requires
CAP_NET_ADMIN to set up iptables/nft rules.
- The user workload container runs without
NET_ADMIN — on Kubernetes, this capability is explicitly dropped from the main sandbox container so only the sidecar can mutate network rules.
The egress sidecar conflicts with transparent service mesh sidecars (Istio/Envoy). When both are present in the same pod, iptables redirect order is undefined and can produce double interception or broken TLS. Exclude sandbox pods from automatic mesh injection when using the egress sidecar. See Network Architecture for details.
Quick policy example
# Replace policy: deny all, allow *.pypi.org
curl -X POST http://127.0.0.1:18080/policy \
-d '{"defaultAction":"deny","egress":[{"action":"allow","target":"*.pypi.org"}]}'
# Append a new allow rule
curl -X PATCH http://127.0.0.1:18080/policy \
-d '[{"action":"allow","target":"*.github.com"}]'
# Remove a specific target
curl -X DELETE http://127.0.0.1:18080/policy \
-d '["*.pypi.org"]'