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.
- Lifecycle APIs: Standardized REST interfaces for create, start, pause, resume, delete
- Pluggable runtimes:
- Docker: Production-ready
- Kubernetes: Production-ready (see
../kubernetes/README.mdfor deployment)
- Lifecycle cleanup modes: Configurable TTL with renewal, or manual cleanup with explicit delete
- 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
- 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
Metadata keys under the reserved prefix opensandbox.io/ are system-managed
and cannot be supplied by users.
- Python: 3.10 or higher
- Package Manager: uv (recommended) or pip
- Runtime Backend:
- Docker Engine 20.10+ (for Docker runtime)
- Kubernetes 1.21.1+ (for Kubernetes runtime)
- Operating System: Linux, macOS, or Windows with WSL2
Install from PyPI. For local development, clone the repo and run uv sync in server/.
uv pip install opensandbox-serverThe server reads a TOML file. Default path: ~/.sandbox.toml. Override with SANDBOX_CONFIG_PATH or opensandbox-server --config /path/to/sandbox.toml.
- Generate a starter file (see
opensandbox-server -hfor all flags):
opensandbox-server init-config ~/.sandbox.toml --example docker
# Kubernetes: --example k8s (deploy the operator / CRDs per ../kubernetes/ first)
# Locales: docker-zh | k8s-zh | omit --example for a schema-only skeleton | add --force to overwrite-
Edit the file for your environment. Full reference: configuration.md (all keys, defaults, validation, env vars).
Topics covered there include: Docker
network_mode/host_ip(e.g. server in Docker Compose),[egress]when clients sendnetworkPolicy,[ingress],[secure_runtime], Kubernetesworkload_provider/batchsandbox_template_file,[agent_sandbox], TTL caps,[renew_intent].
Also useful: Secure container runtime · Manual cleanup / optional fields · Egress component · docker-compose.example.yaml · Experimental features
opensandbox-server
# opensandbox-server --config /path/to/sandbox.tomlListens on server.host / server.port from your TOML (defaults in configuration.md).
Health check (adjust host/port if you changed them):
curl http://127.0.0.1:8080/health
# → {"status": "healthy"}If startup, Docker/Kubernetes, or connectivity fails, see Troubleshooting.
Once the server is running, interactive API documentation is available:
- Swagger UI: http://localhost:8080/docs
- ReDoc: http://localhost:8080/redoc
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 -H "OPEN-SANDBOX-API-KEY: your-secret-api-key" http://localhost:8080/v1/sandboxesCreate 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"]
}Other lifecycle calls (same OPEN-SANDBOX-API-KEY header): GET /v1/sandboxes/{id}, GET /v1/sandboxes/{id}/endpoints/{port} (append ?use_server_proxy=true when needed), POST .../renew-expiration, DELETE /v1/sandboxes/{id}. Full request/response shapes: Swagger UI above or OpenAPI under specs/.
- API Layer (
opensandbox_server/api/): HTTP request handling, validation, and response formatting - Service Layer (
opensandbox_server/services/): Business logic for sandbox lifecycle operations - Middleware (
opensandbox_server/middleware/): Cross-cutting concerns (authentication, logging) - Configuration (
opensandbox_server/config.py): Centralized configuration management - Runtime Implementations: Platform-specific sandbox orchestration
create()
│
▼
┌─────────┐
│ Pending │────────────────────┐
└────┬────┘ │
│ │
│ (provisioning) │
▼ │
┌─────────┐ pause() │
│ Running │───────────────┐ │
└────┬────┘ │ │
│ resume() │ │
│ ┌────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────┐ │
├─│ Paused │ │
│ └────────┘ │
│ │
│ delete() or expire() │
▼ │
┌──────────┐ │
│ Stopping │ │
└────┬─────┘ │
│ │
├────────────────┬────────┘
│ │
▼ ▼
┌────────────┐ ┌────────┐
│ Terminated │ │ Failed │
└────────────┘ └────────┘
Single source of truth for TOML: configuration.md (includes SANDBOX_CONFIG_PATH, DOCKER_HOST, PENDING_FAILURE_TTL).
Optional 🧪 experimental behavior; off by default in example.config.toml (and mirrored copies under opensandbox_server/examples/). See release notes before production.
Extends sandbox TTL when traffic is observed (lifecycle proxy and/or ingress + optional Redis queue). Design and operations: OSEP-0009. TOML keys ([renew_intent], including nested redis.*): see configuration.md and example.config.toml.
Per-sandbox: on create, set extensions["access.renew.extend.seconds"] (string integer 300–86400). Clients using the server proxy: request endpoints with use_server_proxy=true (REST) or SDK ConnectionConfig(..., use_server_proxy=True) — details in OSEP-0009.
Run linter:
uv run ruff checkAuto-fix issues:
uv run ruff check --fixFormat code:
uv run ruff formatRun all tests:
uv run pytestRun with coverage:
uv run pytest --cov=opensandbox_server --cov-report=htmlRun specific test:
uv run pytest tests/test_docker_service.py::test_create_sandbox_requires_entrypointThis project is licensed under the terms specified in the LICENSE file in the repository root.
Contributions are welcome. Follow the repository CONTRIBUTING.md (Conventional Commits, PR expectations). Typical 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
- Troubleshooting: TROUBLESHOOTING.md — common failures (config, Docker, networking, K8s) and fixes
- Development: DEVELOPMENT.md
- Issues: Report defects via GitHub Issues
- Discussions: GitHub Discussions for Q&A and ideas