Blog 4 — Docker Sandboxes Series
What We Are Building
By the end of this blog you will turn a one-off sandbox into a reusable, daily development environment.
You will:
- Understand and use custom templates
- Apply kits for extra tools, network rules and startup behaviour
- Publish ports so you can open services from your browser
- Connect VS Code or Cursor to the sandbox over SSH
- Use the interactive TUI and practical day-to-day patterns
After this blog a sandbox should feel like a normal remote development machine — just safer.
Why This Matters
In Blog 3 we successfully ran agents and used Docker inside the sandbox. That is powerful, but repeating the same setup every time is tiring.
You want:
- The same tools pre-installed for every team member
- Easy access to the web app the agent just started
- Your favourite editor (VS Code / Cursor) connected to the isolated environment
- A clean way to start, stop and manage multiple sandboxes
Templates, kits, ports and SSH give you exactly that.
What You Should Know Before Starting
- Blogs 1–3 completed
- A working project (we will reuse
agent-labor create a fresh one) - VS Code or Cursor installed (optional but recommended for the SSH part)
- Docker Desktop is required only if you want to build your own template image
Environment Setup
Clean previous test sandboxes:
sbx ls
sbx stop $(sbx ls -q) 2>/dev/null || true
sbx rm $(sbx ls -q) 2>/dev/null || true
➜ agent-lab git:(main) ✗ sbx ls
No sandboxes found.
Launch one: sbx run claude
➜ agent-lab git:(main) ✗
Go back to the project (or recreate it quickly):
cd agent-lab || (mkdir -p agent-lab && cd agent-lab)
I'm on agent-lab directory
Output
➜ agent-lab git:(main) ✗ pwd
/Users/koti/myFuture/writings/docker/sandboxes/agent-lab
➜ agent-lab git:(main) ✗
Step 1 — Custom Templates (Reusable Base Environments)
Official templates live under docker/sandbox-templates:<variant>.
Most agents already use the -docker variant by default (full Docker Engine inside the microVM).
You can point to any template:
sbx run --name templated --template docker.io/docker/sandbox-templates:shell-docker shell
Building your own template (optional)
If you have Docker Desktop:
# Dockerfile
FROM docker/sandbox-templates:shell-docker
USER root
RUN apt-get update && apt-get install -y \
tree \
jq \
httpie \
&& rm -rf /var/lib/apt/lists/*
USER agent
Build and use it:
# build docker image
docker build -t my-dev-template:v1 .
#run the container
sbx run --name custom-template --template my-dev-template:v1 shell
This error is expected
Docker Sandboxes cannot see images that exist only in your local Docker Desktop / Docker Engine.The sbx runtime has its own separate image store. When you run the following command it tries to pull the image from a registry → gets 403 Forbidden because the image only exists locally.
sbx run --name custom-template --template my-dev-template:v1 shell
Correct way to use a locally built custom template
Follow these exact steps:
1. Save your local image as a tar file
docker image save my-dev-template:v1 -o my-dev-template.tar
2. Load it into the Sandbox runtime
sbx template load my-dev-template.tar
3. Now run the sandbox using the template
sbx run --name custom-template --template my-dev-template:v1 shell
Useful commands after loading
# See templates available to sbx in host terminal
sbx template ls
Output
➜ agent-lab git:(main) ✗ sbx template ls
REPOSITORY TAG IMAGE ID FLAVOR CREATED
docker.io/docker/sandbox-templates claude-code-docker ae8a46a10575 claude-code-docker 3 days ago
docker.io/docker/sandbox-templates shell-docker d86a6cdc105a shell-docker 3 days ago
docker.io/library/my-dev-template v1 b403131ff1e6 shell-docker 2 minutes ago
➜ agent-lab git:(main) ✗
# Remove a template if needed
sbx template rm my-dev-template:v1
Inside the new sandbox you already have tree, jq and httpie without installing them again.
Output
agent@custom-template:agent-lab$ tree
.
|-- Dockerfile
`-- my-dev-template.tar
1 directory, 2 files
agent@custom-template:agent-lab$ jq
jq - commandline JSON processor [version 1.8.1]
Usage: jq [options] <jq filter> [file...]
jq [options] --args <jq filter> [strings...]
jq [options] --jsonargs <jq filter> [JSON_TEXTS...]
jq is a tool for processing JSON inputs, applying the given filter to
its JSON text inputs and producing the filter's results as JSON on
standard output.
The simplest filter is ., which copies jq's input to its output
unmodified except for formatting. For more advanced filters see
the jq(1) manpage ("man jq") and/or https://jqlang.org/.
Example:
$ echo '{"foo": 0}' | jq .
{
"foo": 0
}
For listing the command options, use jq --help.
agent@custom-template:agent-lab$ httpie
usage: httpie [-h] [--debug] [--traceback] [--version] {cli,plugins} ...
httpie: error: Please specify one of these: 'cli', 'plugins'
This command is only for managing HTTPie plugins.
To send a request, please use the http/https commands:
$ http POST pie.dev/post hello=world
$ https POST pie.dev/post hello=world
agent@custom-template:agent-lab$
Template vs Kit Diagram
Explanation
A template is a Docker image — heavy things that rarely change (language runtimes, system packages, Docker itself).
A kit is applied at runtime — lighter, declarative additions (extra tools, network allow-list, startup scripts, files).
Step 2 — Kits (Declarative Extensions)
Kits are YAML files (spec.yaml). They can be local directories, Git URLs or OCI artifacts.
Simple example — create a small kit that adds a useful tool and allows a domain:
mkdir -p my-kit
cat > my-kit/spec.yaml << 'EOF'
schemaVersion: "1"
kind: mixin
name: handy-tools
description: Adds a few everyday tools and allows example.com
commands:
startup:
- command: ["bash", "-c", "sudo apt-get update && sudo apt-get install -y tree jq || true"]
user: "root"
network:
allowedDomains:
- "example.com:443"
EOF
Run with the kit:
sbx run --name with-kit --kit my-kit shell
Inside the sandbox jq is available and example.com is reachable.
You can stack multiple kits with repeated --kit flags.
Step 3 — Publishing Ports
*This we have covered in previous blog but for the simplicity and to get familiarised I'm adding detailed section for ports here. *
Sandboxes are network-isolated by default. To open a service from your host browser you must publish a port.
Start a simple server inside a sandbox (or let the agent do it):
sbx run --name port-demo --clone shell
# inside the sandbox
python3 -m http.server 8000
From the host:
sbx ports port-demo --publish 8000
# or pin a host port
sbx ports port-demo --publish 8080:8000
Check:
sbx ports port-demo
sbx ls
Output
➜ agent-lab git:(main) ✗ sbx ports port-demo --publish 8080:8000
Published 127.0.0.1:8080 -> 8000/tcp
Published [::1]:8080 -> 8000/tcp
➜ agent-lab git:(main) ✗
➜ agent-lab git:(main) ✗
➜ agent-lab git:(main) ✗ sbx ports port-demo
HOST IP HOST PORT SANDBOX PORT PROTOCOL
127.0.0.1 8080 8000 tcp
::1 8080 8000 tcp
127.0.0.1 49156 9418 tcp
127.0.0.1 49157 8000 tcp
::1 49157 8000 tcp
➜ agent-lab git:(main) ✗ sbx ls
SANDBOX AGENT STATUS PORTS WORKSPACE
port-demo shell running 127.0.0.1:8080->8000/tcp, ::1:8080->8000/tcp, 127.0.0.1:49157->8000/tcp, ::1:49157->8000/tcp, 127.0.0.1:49156->9418/tcp /Users/koti/myFuture/writings/docker/sandboxes/agent-lab
with-kit shell stopped /Users/koti/myFuture/writings/docker/sandboxes
➜ agent-lab git:(main) ✗
Open http://localhost:8080 (or the ephemeral port shown).
Unpublish when finished:
sbx ports port-demo --unpublish 8080:8000
Port Publishing Diagram
Explanation
Traffic from your browser hits a port on the host. sbx ports forwards it into the microVM. The app never needs to bind to the host network directly.
Step 4 — SSH Integration (VS Code / Cursor)
One-time setup:
sbx setup ssh
Output
➜ agent-lab git:(main) ✗ sbx setup ssh
SSH ──────────────────────────────────────────────────────
Status ● enabled · signed in as vellankikoti
Access *.sbx -> sandboxd.sock (no port · login-gated)
Connect ──────────────────────────────────────────────────────
Terminal ssh <sandboxname>.sbx
File access sftp <sandboxname>.sbx
Copy files scp myfile.txt <sandboxname>.sbx:/path/to/workspace/
You can safely re-run sbx setup ssh to reconfigure
➜ agent-lab git:(main) ✗
This writes a managed block into your SSH config so any *.sbx host is handled by the sbx daemon.
Create or use a named sandbox:
sbx create --name editor-demo shell .
sbx run --name editor-demo
Output
Connect:
ssh editor-demo.sbx
Output
➜ agent-lab git:(main) ✗ sbx ls
SANDBOX AGENT STATUS PORTS WORKSPACE
editor-demo shell running /Users/koti/myFuture/writings/docker/sandboxes/agent-lab
➜ agent-lab git:(main) ✗
➜ agent-lab git:(main) ✗ sbx run --name editor-demo
Starting shell agent in sandbox 'editor-demo'...
Workspace: /Users/koti/myFuture/writings/docker/sandboxes/agent-lab
agent@editor-demo:agent-lab$ ls
multi_line.txt
agent@editor-demo:agent-lab$
Try SSH to sbx
➜ agent-lab git:(main) ✗ ssh editor-demo.sbx
Connecting to sandbox "editor-demo"…
agent@editor-demo:workspace$
agent@editor-demo:workspace$ pwd
/home/agent/workspace
agent@editor-demo:workspace$ cd /Users/koti/myFuture/writings/docker/sandboxes/agent-lab
agent@editor-demo:agent-lab$ ls
multi_line.txt
agent@editor-demo:agent-lab$
SSH Connection Diagram
Explanation
The editor talks to a local proxy provided by sbx. No inbound port is opened on the microVM. Authentication is tied to your Docker login. The sandbox starts automatically if it was stopped.
Step 5 — Daily Workflow Patterns & TUI
Launch the interactive dashboard:
sbx
You get a live view of all sandboxes (CPU, memory, status). From here you can create, start/stop, attach, open a shell or remove sandboxes. There is also a network panel.
Practical patterns I use every day:
- Named sandboxes per feature:
--name feature-login - Always prefer
--clonefor agent work - Publish only the ports you need
- Connect the editor once and leave it attached
- Clean up with
sbx rmwhen the task is done
Multiple workspaces example:
sbx run --name multi claude ~/main-project ~/shared-libs:ro ~/docs:ro
Let’s Break It
- Publish a port, open the service, then unpublish and confirm the browser can no longer reach it.
- Connect VS Code, make a change, and confirm it appears both in the editor and on the host (or via the clone remote).
- Apply a kit that denies a domain and watch the agent fail to reach it.
Production Thinking
In a real team I would:
- Publish a small set of internal templates to a private registry
- Keep common kits in the project repository (
./kits/) - Document the exact
sbx run ... --kit ...command in the README - Prefer SSH + editor over pure terminal for longer sessions
- Use the TUI for quick overview of resource usage
Security Considerations
- Templates and kits can install packages with root inside the microVM — treat them like any other code you run
- Port publishing intentionally punches a controlled hole from host → sandbox
- SSH access is still subject to the same network policy and workspace rules
- Kits can declare their own network allow-lists; those rules are enforced
Common Mistakes
- Forgetting
sbx setup sshbefore trying to connect an editor - Publishing ports on a stopped sandbox
- Building templates without Docker Desktop
- Putting secrets inside a template image instead of using
sbx secret - Leaving many sandboxes with large Docker image caches
Troubleshooting
| Problem | Check | Fix |
|---|---|---|
*.sbx not resolving |
sbx setup ssh |
Re-run the setup command |
| Port not reachable | sbx ports <name> |
Publish again or check the mapping |
| Editor cannot find folder | Absolute path inside sandbox | Use the host path that was mounted |
| Kit not applying |
sbx ls / logs |
Check kit path and spec.yaml syntax |
| Template pull fails | Image name | Use full docker.io/... reference |
Useful commands:
sbx ports <name>
sbx setup ssh
ssh <name>.sbx
sbx
sbx exec -it <name> bash
Cleanup
sbx stop port-demo editor-demo with-kit custom-template 2>/dev/null || true
sbx rm port-demo editor-demo with-kit custom-template 2>/dev/null || true
What We Learned
- Templates give you reusable base images with tools pre-installed
- Kits add lightweight, declarative capabilities at runtime
-
sbx portsmakes services inside the sandbox reachable from the host - SSH turns the sandbox into a first-class remote development target for VS Code and Cursor
- The combination makes daily agent work feel natural and safe
You now have everything needed for comfortable, repeatable development inside sandboxes.
What’s Next?
In the final blog (Blog 5) we go deep into the security model, realistic troubleshooting, known limitations, organisation governance concepts, and production best practices so you can introduce Docker Sandboxes to a real team with confidence.
References
- https://docs.docker.com/ai/sandboxes/customize/templates/ — templates
- https://docs.docker.com/ai/sandboxes/customize/kits/ — kits overview and examples
- https://docs.docker.com/ai/sandboxes/integrations/ — SSH, VS Code, Cursor
- https://docs.docker.com/ai/sandboxes/usage/ — ports, TUI, workflows
- https://docs.docker.com/reference/cli/sbx/ports/ — port command reference
- https://docs.docker.com/ai/sandboxes/customize/kit-reference/ — full kit spec
All commands and behaviour verified against current official documentation (August 2026).









Top comments (0)