- docker-30/zot: add Zot OCI registry with on-demand sync to docker.io, registry.k8s.io, ghcr.io, quay.io - kubernetes-kvm-terraform: wire Kanidm OIDC via structured AuthenticationConfiguration; add reference apiserver manifest and join-node-02 helper - servers: reorganize shadow/ under servers/, add saint vhost config and utility-101 VM definition, add shadow hrajfrisbee.cz vhost and storage-23 notes - experiments: add notes and configs for e2b dev VM, kata + firecracker on kube, microsandbox, orb-stack k3s (terraform + cloud-init), rke2 - vms/docker: document tailscale + node-exporter setup - blog: stub post on Gateway API - chore: gitignore tmp/, smtp_password, and the two local-only credential caches; add per-project .claude/settings.json Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
281 lines
6.5 KiB
Markdown
281 lines
6.5 KiB
Markdown
# E2B Sandbox Usage Guide
|
|
|
|
A practical guide for creating, observing, and using E2B sandboxes via the API.
|
|
|
|
## Prerequisites
|
|
|
|
### Local Dev Setup
|
|
|
|
Seed the database to create a test team and API key:
|
|
|
|
```bash
|
|
make -C packages/local-dev seed-database
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
E2B_API_KEY=e2b_53ae1fed82754c17ad8077fbc8bcdd90
|
|
E2B_ACCESS_TOKEN=sk_e2b_89215020937a4c989cde33d7bc647715
|
|
E2B_API_URL=http://localhost:3000
|
|
E2B_SANDBOX_URL=http://localhost:3002
|
|
```
|
|
|
|
All examples below use `$E2B_API_URL` and `$E2B_API_KEY` — export them in your shell for convenience:
|
|
|
|
```bash
|
|
export E2B_API_URL=http://localhost:3000
|
|
export E2B_API_KEY=e2b_53ae1fed82754c17ad8077fbc8bcdd90
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Create a Sandbox
|
|
|
|
```bash
|
|
curl -X POST $E2B_API_URL/sandboxes \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"templateID": "base",
|
|
"timeout": 300
|
|
}'
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"sandboxID": "i1234567890abcdef",
|
|
"templateID": "base",
|
|
"envdVersion": "0.5.8",
|
|
"domain": "i1234567890abcdef.your-domain"
|
|
}
|
|
```
|
|
|
|
Save the `sandboxID` and `domain` from the response for subsequent commands.
|
|
|
|
### Optional Parameters
|
|
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `secure` | bool | Returns an `envdAccessToken` for authenticated envd access |
|
|
| `envVars` | object | Inject environment variables into the VM |
|
|
| `metadata` | object | Tag the sandbox for filtering (e.g. `{"purpose": "test"}`) |
|
|
| `autoPause` | bool | Pause instead of kill on timeout |
|
|
| `allow_internet_access` | bool | Allow internet egress from the VM |
|
|
| `network.allowPublicTraffic` | bool | Allow inbound public traffic |
|
|
| `network.allowOut` | array | Allowed egress destinations (IPs, CIDRs, domains) |
|
|
| `network.denyOut` | array | Denied egress destinations (IPs/CIDRs only) |
|
|
| `volumeMounts` | array | Mount persistent volumes (`{"name": "vol", "path": "/data"}`) |
|
|
|
|
**Example with options:**
|
|
|
|
```bash
|
|
curl -X POST $E2B_API_URL/sandboxes \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"templateID": "base",
|
|
"timeout": 300,
|
|
"secure": true,
|
|
"envVars": {"MY_VAR": "hello"},
|
|
"metadata": {"purpose": "demo"}
|
|
}'
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Observe Sandbox State
|
|
|
|
### Get details of a specific sandbox
|
|
|
|
```bash
|
|
curl $E2B_API_URL/sandboxes/{sandboxID} \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
Returns state (`running`/`paused`), CPU/memory/disk config, network settings, and TTL (`endAt`).
|
|
|
|
### List all sandboxes
|
|
|
|
```bash
|
|
# Running only
|
|
curl "$E2B_API_URL/v2/sandboxes?state=running" \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
|
|
# Running and paused
|
|
curl "$E2B_API_URL/v2/sandboxes?state=running&state=paused" \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
|
|
# Filter by metadata
|
|
curl "$E2B_API_URL/v2/sandboxes?metadata=purpose%3Ddemo" \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
### Get resource metrics (CPU, memory, disk)
|
|
|
|
```bash
|
|
curl "$E2B_API_URL/sandboxes/{sandboxID}/metrics?start=$(date -v-5M +%s)&end=$(date +%s)" \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
[
|
|
{
|
|
"timestampUnix": 1234567890,
|
|
"cpuCount": 2,
|
|
"cpuUsedPct": 25.5,
|
|
"memUsed": 268435456,
|
|
"memTotal": 536870912,
|
|
"diskUsed": 1073741824,
|
|
"diskTotal": 5368709120
|
|
}
|
|
]
|
|
```
|
|
|
|
### Get sandbox logs
|
|
|
|
```bash
|
|
curl "$E2B_API_URL/v2/sandboxes/{sandboxID}/logs?limit=100&direction=backward" \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
Optional query parameters: `cursor` (ms timestamp), `level` (min log level), `search` (substring match).
|
|
|
|
---
|
|
|
|
## 3. Use the Sandbox
|
|
|
|
The in-VM daemon (**envd**) runs on port 49983 inside each sandbox, exposed via the sandbox's `domain`.
|
|
|
|
### Upload a file
|
|
|
|
```bash
|
|
curl -X POST https://{domain}/files \
|
|
-H "Content-Type: multipart/form-data" \
|
|
-F "file=@script.py" \
|
|
-F "path=/home/user/script.py"
|
|
```
|
|
|
|
### Using the E2B Python SDK
|
|
|
|
Point the SDK at your local API:
|
|
|
|
```python
|
|
from e2b import Sandbox
|
|
|
|
sbx = Sandbox("base", api_url="http://localhost:3000")
|
|
|
|
# Run a command
|
|
result = sbx.commands.run("echo 'Hello from Firecracker VM!'")
|
|
print(result.stdout)
|
|
|
|
# Write and execute a file
|
|
sbx.files.write("/home/user/hello.py", "print('Hello world')")
|
|
result = sbx.commands.run("python3 /home/user/hello.py")
|
|
print(result.stdout)
|
|
|
|
# List files
|
|
files = sbx.files.list("/home/user")
|
|
for f in files:
|
|
print(f.name)
|
|
|
|
sbx.kill()
|
|
```
|
|
|
|
### Envd Connect RPC API
|
|
|
|
The envd daemon exposes Connect RPC services for programmatic access:
|
|
|
|
**Process Service:**
|
|
- `Start(ProcessConfig)` — start a new process
|
|
- `List()` — list running processes
|
|
- `Connect(ProcessSelector)` — connect to process stdio
|
|
- `Signal(ProcessSelector, Signal)` — send signal to process
|
|
|
|
**Filesystem Service:**
|
|
- `ListDir(Path)` — list directory contents
|
|
- `Stat(Path)` — get file metadata
|
|
- `WatchDir(Path)` — watch for changes
|
|
- `Move(Source, Dest)` — move/rename file
|
|
- `RemoveDir(Path)` — remove directory
|
|
|
|
---
|
|
|
|
## 4. Lifecycle Management
|
|
|
|
### Extend timeout
|
|
|
|
```bash
|
|
# Add 60 seconds to the TTL
|
|
curl -X POST $E2B_API_URL/sandboxes/{sandboxID}/refreshes \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"duration": 60}'
|
|
|
|
# Or set an absolute timeout (seconds from now)
|
|
curl -X POST $E2B_API_URL/sandboxes/{sandboxID}/timeout \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"timeout": 120}'
|
|
```
|
|
|
|
### Pause (snapshot to disk)
|
|
|
|
```bash
|
|
curl -X POST $E2B_API_URL/sandboxes/{sandboxID}/pause \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
### Resume / reconnect
|
|
|
|
```bash
|
|
curl -X POST $E2B_API_URL/sandboxes/{sandboxID}/connect \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"timeout": 300}'
|
|
```
|
|
|
|
Returns `200` if already running, `201` if resumed from paused state.
|
|
|
|
### Kill
|
|
|
|
```bash
|
|
curl -X DELETE $E2B_API_URL/sandboxes/{sandboxID} \
|
|
-H "X-API-Key: $E2B_API_KEY"
|
|
```
|
|
|
|
### Create a snapshot (template from running sandbox)
|
|
|
|
```bash
|
|
curl -X POST $E2B_API_URL/sandboxes/{sandboxID}/snapshots \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "my-snapshot"}'
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Network Configuration
|
|
|
|
Update network rules on a running sandbox:
|
|
|
|
```bash
|
|
curl -X PUT $E2B_API_URL/sandboxes/{sandboxID}/network \
|
|
-H "X-API-Key: $E2B_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"allowOut": ["8.8.8.8", "example.com"],
|
|
"denyOut": ["0.0.0.0/0"]
|
|
}'
|
|
```
|
|
|
|
**Rules:**
|
|
- If `allowOut` contains domain names, `denyOut` must include `0.0.0.0/0`
|
|
- Domain names are not supported in `denyOut` (IPs/CIDRs only)
|
|
- `allowOut` entries take precedence over `denyOut`
|
|
- Omitting both fields clears all rules
|