OpenSandbox Server
English | 中文
A production-grade, FastAPI-based service for managing the lifecycle of containerized sandboxes. It acts as the control plane to create, run, monitor, and dispose isolated execution environments across container platforms.
Features
Core capabilities
- Lifecycle APIs: Standardized REST interfaces for create, start, pause, resume, delete
- Pluggable runtimes:
- Docker: Production-ready
- Kubernetes: Supported (see
kubernetes/for deployment)
- Automatic expiration: Configurable TTL with renewal
- Access control: API Key authentication (
OPEN-SANDBOX-API-KEY); can be disabled for local/dev - Networking modes:
- Host: shared host network, performance first
- Bridge: isolated network with built-in HTTP routing
- Resource quotas: CPU/memory limits with Kubernetes-style specs
- Observability: Unified status with transition tracking
- Registry support: Public and private images
Extended capabilities
- Async provisioning: Background creation to reduce latency
- Timer restoration: Expiration timers restored after restart
- Env/metadata injection: Per-sandbox environment and metadata
- Port resolution: Dynamic endpoint generation
- Structured errors: Standard error codes and messages
Requirements
- Python: 3.10 or higher
- Package Manager: uv (recommended) or pip
- Runtime Backend:
- Docker Engine 20.10+ (for Docker runtime)
- Kubernetes 1.21+ (for Kubernetes runtime)
- Operating System: Linux, macOS, or Windows with WSL2
Quick Start
Installation
-
Clone the repository and navigate to the server directory:
cd server
-
Install dependencies using
uv:uv sync
Configuration
The server uses a TOML configuration file to select and configure the underlying runtime.
Create configuration file:
cp example.config.toml ~/.sandbox.toml
**[optional] Create K8S configuration file: The K8S version of the Sandbox Operator needs to be deployed in the cluster, refer to the Kubernetes directory.
cp example.config.k8s.toml ~/.sandbox.toml
cp example.batchsandbox-template.yaml ~/batchsandbox-template.yaml
[optional] Edit ~/.sandbox.toml for your environment:
Option A: Docker runtime + host networking (default)
[server]
host = "0.0.0.0"
port = 8080
log_level = "INFO"
api_key = "your-secret-api-key-change-this"
[runtime]
type = "docker"
execd_image = "opensandbox/execd:v1.0.5"
[docker]
network_mode = "host" # Containers share host network; only one sandbox instance at a time
Option B: Docker runtime + bridge networking
[server]
host = "0.0.0.0"
port = 8080
log_level = "INFO"
api_key = "your-secret-api-key-change-this"
[runtime]
type = "docker"
execd_image = "opensandbox/execd:v1.0.5"
[docker]
network_mode = "bridge" # Isolated container networking
Security hardening (applies to all Docker modes)
[docker]
# Drop dangerous capabilities and block privilege escalation by default
drop_capabilities = ["AUDIT_WRITE", "MKNOD", "NET_ADMIN", "NET_RAW", "SYS_ADMIN", "SYS_MODULE", "SYS_PTRACE", "SYS_TIME", "SYS_TTY_CONFIG"]
no_new_privileges = true
apparmor_profile = "" # e.g. "docker-default" when AppArmor is available
# Limit fork bombs and optionally enforce seccomp / read-only rootfs
pids_limit = 512 # set to null to disable
seccomp_profile = "" # path or profile name; empty uses Docker default
Further reading on Docker container security: https://docs.docker.com/engine/security/
(Optional) Egress sidecar for networkPolicy
- Configure the sidecar image (used only when requests include
networkPolicy):[runtime] type = "docker" execd_image = "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/execd:v1.0.3" egress_image = "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/egress:latest"
- Supported only in Docker bridge mode; requests with
networkPolicyare rejected whennetwork_mode=host. - Main container shares the sidecar netns and explicitly drops
NET_ADMIN; the sidecar keepsNET_ADMINto manage iptables. - IPv6 is disabled in the shared namespace when the egress sidecar is injected to keep policy enforcement consistent.
- Sidecar image is pulled before start; delete/expire/failure paths attempt to clean up the sidecar as well.
- Request example (
CreateSandboxRequestwithnetworkPolicy):{ "image": {"uri": "python:3.11-slim"}, "entrypoint": ["python", "-m", "http.server", "8000"], "timeout": 3600, "resourceLimits": {"cpu": "500m", "memory": "512Mi"}, "networkPolicy": { "defaultAction": "deny", "egress": [ {"action": "allow", "target": "pypi.org"}, {"action": "allow", "target": "*.python.org"} ] } }
- When
networkPolicyis empty or omitted, no sidecar is injected (allow-all at start).
Run the server
Start the server using uv:
uv run python -m src.main
The server will start at http://0.0.0.0:8080 (or your configured host/port).
Run the server (installed package)
After installing the package (wheel or PyPI), you can use the CLI entrypoint:
opensandbox-server --config ~/.sandbox.toml
Health check
curl http://localhost:8080/health
Expected response:
{"status": "healthy"}
API documentation
Once the server is running, interactive API documentation is available:
- Swagger UI: http://localhost:8080/docs
- ReDoc: http://localhost:8080/redoc
Further reading on Docker container security: https://docs.docker.com/engine/security/
API authentication
Authentication is enforced only when server.api_key is set. If the value is empty or missing, the middleware skips API Key checks (intended for local/dev). For production, always set a non-empty server.api_key and send it via the OPEN-SANDBOX-API-KEY header.
All API endpoints (except /health, /docs, /redoc) require authentication via the OPEN-SANDBOX-API-KEY header when authentication is enabled:
curl http://localhost:8080/v1/sandboxes
Example usage
Create a Sandbox
curl -X POST "http://localhost:8080/v1/sandboxes" \
-H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"image": {
"uri": "python:3.11-slim"
},
"entrypoint": [
"python",
"-m",
"http.server",
"8000"
],
"timeout": 3600,
"resourceLimits": {
"cpu": "500m",
"memory": "512Mi"
},
"env": {
"PYTHONUNBUFFERED": "1"
},
"metadata": {
"team": "backend",
"project": "api-testing"
}
}'
Response:
{
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"status": {
"state": "Pending",
"reason": "CONTAINER_STARTING",
"message": "Sandbox container is starting.",
"lastTransitionAt": "2024-01-15T10:30:00Z"
},
"metadata": {
"team": "backend",
"project": "api-testing"
},
"expiresAt": "2024-01-15T11:30:00Z",
"createdAt": "2024-01-15T10:30:00Z",
"entrypoint": ["python", "-m", "http.server", "8000"]
}
Get Sandbox Details
curl -H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
http://localhost:8080/v1/sandboxes/a1b2c3d4-5678-90ab-cdef-1234567890ab
Get Service Endpoint
curl -H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
http://localhost:8080/v1/sandboxes/a1b2c3d4-5678-90ab-cdef-1234567890ab/endpoints/8000
# execd (agent) endpoint
curl -H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
http://localhost:8080/v1/sandboxes/a1b2c3d4-5678-90ab-cdef-1234567890ab/endpoints/44772
Response:
{
"endpoint": "sandbox.example.com/a1b2c3d4-5678-90ab-cdef-1234567890ab/8000"
}
Renew Expiration
curl -X POST "http://localhost:8080/v1/sandboxes/a1b2c3d4-5678-90ab-cdef-1234567890ab/renew-expiration" \
-H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
-H "Content-Type: application/json" \
-d '{
"expiresAt": "2024-01-15T12:30:00Z"
}'
Delete a Sandbox
curl -X DELETE \
-H "OPEN-SANDBOX-API-KEY: your-secret-api-key" \
http://localhost:8080/v1/sandboxes/a1b2c3d4-5678-90ab-cdef-1234567890ab
Architecture
Component responsibilities
- API Layer (
src/api/): HTTP request handling, validation, and response formatting - Service Layer (
src/services/): Business logic for sandbox lifecycle operations - Middleware (
src/middleware/): Cross-cutting concerns (authentication, logging) - Configuration (
src/config.py): Centralized configuration management - Runtime Implementations: Platform-specific sandbox orchestration
Sandbox lifecycle states
create()
│
▼
┌─────────┐
│ Pending │────────────────────┐
└────┬────┘ │
│ │
│ (provisioning) │
▼ │
┌─────────┐ pause() │
│ Running │───────────────┐ │
└────┬────┘ │ │
│ resume() │ │
│ ┌────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────┐ │
├─│ Paused │ │
│ └────────┘ │
│ │
│ delete() or expire() │
▼ │
┌──────────┐ │
│ Stopping │ │
└────┬─────┘ │
│ │
├────────────────┬────────┘
│ │
▼ ▼
┌────────────┐ ┌────────┐
│ Terminated │ │ Failed │
└────────────┘ └────────┘
Configuration reference
Server configuration
| Key | Type | Default | Description |
|---|---|---|---|
server.host |
string | "0.0.0.0" |
Interface to bind |
server.port |
integer | 8080 |
Port to listen on |
server.log_level |
string | "INFO" |
Python logging level |
server.api_key |
string | null |
API key for authentication |
Runtime configuration
| Key | Type | Required | Description |
|---|---|---|---|
runtime.type |
string | Yes | Runtime implementation ("docker" or "kubernetes") |
runtime.execd_image |
string | Yes | Container image with execd binary |
runtime.egress_image |
string | No | Container image with egress binary |
Docker configuration
| Key | Type | Default | Description |
|---|---|---|---|
docker.network_mode |
string | "host" |
Network mode ("host" or "bridge") |
Agent-sandbox configuration
| Key | Type | Default | Description |
|---|---|---|---|
agent_sandbox.template_file |
string | null |
Sandbox CR YAML template for agent-sandbox (used when kubernetes.workload_provider = "agent-sandbox") |
agent_sandbox.shutdown_policy |
string | "Delete" |
Shutdown policy on expiry ("Delete" or "Retain") |
agent_sandbox.ingress_enabled |
boolean | true |
Whether ingress routing is expected to be enabled |
Environment variables
| Variable | Description |
|---|---|
SANDBOX_CONFIG_PATH |
Override config file location |
DOCKER_HOST |
Docker daemon URL (e.g., unix:///var/run/docker.sock) |
DOCKER_API_TIMEOUT |
Docker client timeout in seconds (default: 180) |
PENDING_FAILURE_TTL |
TTL for failed pending sandboxes in seconds (default: 3600) |
Development
Code quality
Run linter:
uv run ruff check
Auto-fix issues:
uv run ruff check --fix
Format code:
uv run ruff format
Testing
Run all tests:
uv run pytest
Run with coverage:
uv run pytest --cov=src --cov-report=html
Run specific test:
uv run pytest tests/test_docker_service.py::test_create_sandbox_requires_entrypoint
License
This project is licensed under the terms specified in the LICENSE file in the repository root.
Contributing
Contributions are welcome. Suggested flow:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for new functionality
- Ensure all tests pass (
uv run pytest) - Run linting (
uv run ruff check) - Commit with clear messages
- Push to your fork
- Open a Pull Request
Support
- Documentation: See
DEVELOPMENT.mdfor development guidance - Issues: Report defects via GitHub Issues
- Discussions: Use GitHub Discussions for Q&A and ideas
Metadata
Release files for sandbox-server 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sandbox_server-0.1.0.tar.gz | 54.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sandbox_server-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 127.1 kB
Release files / sandbox_server-0.1.0.tar.gz
| Download URL | sandbox_server-0.1.0.tar.gz |
|---|---|
| Size | 54.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
64b47fa5feac677122befe1dd0f4d7df002b2ad1cf68a7bfd5c167e0729c8572
|
|
BLAKE2b-256 checksum How to use checksums |
ba276180a1e1aaa91f8ebd33988c70ba31e0bb0fd5d9c9dd534b16a0682e349e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.29 {"installer":{"name":"uv","version":"0.9.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sandbox_server-0.1.0-py3-none-any.whl
| Download URL | sandbox_server-0.1.0-py3-none-any.whl |
|---|---|
| Size | 72.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cc651dc83f0529b8b080631085e1da29c7a247dbf12275d050f5443437bdb9f5
|
|
BLAKE2b-256 checksum How to use checksums |
2e723660703424c1d31870c56e6d4a2840633252d41b5fbb8ca7bb47bf6281e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.29 {"installer":{"name":"uv","version":"0.9.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|