cd /news/ai-infrastructure/self-hosted-dev-sandboxes-with-previ… Β· home β€Ί topics β€Ί ai-infrastructure β€Ί article
[ARTICLE Β· art-20757] src=github.com pub= topic=ai-infrastructure verified=true sentiment=↑ positive

Self-hosted dev sandboxes with preview URLs (Docker, Go, no K8s)

The open-source project sandboxed provides a self-hosted platform that turns a single Linux machine into a fleet of isolated, on-demand development sandboxes with built-in AI coding agents and live preview URLs. The system, built with Go and Docker and requiring no Kubernetes, allows users to spin up containers via an HTTP API, automatically stops idle environments to conserve memory, and wakes them on the next request. This infrastructure enables developers to run AI app-builder products on their own hardware with one command, offering multi-tenant isolation, per-user preview URLs, and cost control without vendor lock-in.

read9 min publishedJun 3, 2026

The open-source engine for AI app-builder products.

Give every user an isolated cloud dev environment, a built-in coding agent, and a live preview URL β€” self-hosted, on one machine, in one command.

sandboxed turns one Linux box into a fleet of isolated, on-demand dev sandboxes β€” each with a real shell, the common toolchains, a coding agent, and its own preview URL. You drive it with a small HTTP API:

POST /sandbox          β†’ an isolated container spins up
POST .../tasks         β†’ an AI agent builds an app inside it
http://<id>.preview... β†’ the running app, live, on a shareable URL

Sandboxes stop when idle to free memory and wake on the next request, so a modest server can host many of them. Workspaces persist on disk across stops and reboots. The whole thing is a single Go control plane that drives the Docker daemon, fronted by Traefik β€” no Kubernetes, no database server, no message bus.

This is the infrastructure that sits behind "describe an app β†’ watch it get built β†’ see it running" products. sandboxed gives you that core, open source, on your own hardware.

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ your host (just needs Docker) ────────────────┐
 browser ──▢│  Traefik  ──▢  sandbox  (coding agent + dev server :3000)      β”‚
            β”‚     β–²              β–²   β–²                                        β”‚
 API/CLI ──▢│  sandboxd β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   └─ workspace dir (persists)             β”‚
            │     │  SQLite (source of truth) · idle→stop · request→wake      │
            └─────┴────────────────────────────────────────────────────────-β”€β”˜

If you're building an AI app-builder, an agent platform, a coding playground, or a per-user preview product, the hard part isn't the prompt β€” it's the infrastructure underneath it:

Multi-tenant isolation so one user's code can't touch another's.Per-user preview URLs with automatic routing and TLS.Cost controlβ€” idle environments must release memory, or your bill explodes.** Agent orchestration**β€” run a coding agent against a workspace, stream its progress, capture the result.** Persistence, wake-on-demand, reconciliation after a crash or reboot.**

That's months of platform work. sandboxed is that platform, distilled to one command:

  • ⚑ One-command install../install.sh

and you have a working API + previews. - 🧠 Agents included. The OpenCode and Claude Code CLIs ship in every sandbox; hand a sandbox a prompt and it builds. - πŸ’Έ Dense by design. Stop-on-idle + wake-on-request means dozens of sandboxes share one box instead of one VM each β€” the difference between a $20 server and a $2,000 cluster. - πŸ”“ Yours. Self-hosted, MIT-licensed, no vendor lock-in. Own your data, your margins, and your roadmap. - πŸͺΆ Boring on purpose. SQLite + thedocker

CLI + Traefik. A reconciler converges Docker back to the database on every boot. You can read the whole control plane in an afternoon.

Requirements: Docker Engine + the Compose plugin, on Linux. That's it.

git clone https://github.com/tastyeffectco/sandboxes.git
cd sandboxes
./install.sh

install.sh

checks Docker, writes a .env

, builds the sandbox base image + the control plane, and starts the stack. The API is then live at http://127.0.0.1:9090

(verify: curl http://127.0.0.1:9090/healthz

β†’ ok

).

The base image already includes the OpenCode and Claude Code CLIs. Hand a sandbox a prompt and watch it build (OpenCode runs on its free plan out of the box; pass your own provider key via env

to use your account):

API=http://127.0.0.1:9090

ID=$(curl -s -XPOST $API/sandbox -H 'content-type: application/json' \
       -d '{"ports":[3000]}' | sed -E 's/.*"id":"([^"]+)".*/\1/')
echo "sandbox: $ID"

curl -s -XPOST $API/v1/sandboxes/$ID/tasks -H 'content-type: application/json' -d '{
        "prompt":"create a Vite app that shows a todo list and run it on port 3000",
        "agent":"opencode"
     }'

curl -N $API/v1/sandboxes/$ID/tasks/<taskId>/events

To use your own model account instead of the free plan, inject a key at create time β€” it's available to the agent and any shell in the sandbox:

curl -s -XPOST $API/sandbox -d '{"ports":[3000],"env":{"ANTHROPIC_API_KEY":"sk-ant-..."}}'

Once the app serves on port 3000, it's reachable at its preview URL β€” the sandbox self-registered the route, nothing else to wire:

http://s-<id>-3000.preview.localhost

*.localhost

resolves to 127.0.0.1

in every modern browser, so it works locally with zero DNS and zero certificates (add :$HTTP_PORT

if you changed it from 80). The first request to a stopped sandbox wakes it automatically. On a real domain you get https://s-<id>-3000.preview.yourdomain.com

(see Production / TLS).

Just want a shell, no agent?Skip step 2 and run anything via the exec API:curl -XPOST $API/sandbox/$ID/exec -d '{"cmd":["bash","-lc","cd ~/workspace/app && python3 -m http.server 3000"]}'

then open the same preview URL.

Base URL = http://127.0.0.1:9090

(set by SANDBOXED_API_BIND

). Auth is off by default for local use; with SANDBOXD_API_AUTH_DISABLED=false

SANDBOXD_API_TOKENS

, send -H "Authorization: Bearer <secret>"

.

Method & path Body Purpose
POST /sandbox
{"ports":[3000],"env":{...}}
create β€” id optional (ULID auto); env injects vars (e.g. API keys)
GET /sandboxes
β€” list all sandboxes
GET /sandbox/{id}
β€” get one (status, ports, container id…)
POST /sandbox/{id}/exec
{"cmd":["bash","-lc","…"]}
run a command (non-interactive)
POST /sandbox/{id}/keepalive
β€” postpone the idle reaper
POST /v1/sandboxes/{id}/stop
β€” stop now to free RAM (wakes on next preview hit)
DELETE /sandbox/{id}
β€” destroy the container, keep the workspace
POST /sandbox/{id}/purge
β€” destroy and delete the workspace
POST /v1/sandboxes/{id}/tasks
{"prompt":"…","agent":"opencode"}
run a coding agent headlessly
GET /v1/sandboxes/{id}/tasks/{taskId}
β€” task result
GET /v1/sandboxes/{id}/tasks/{taskId}/events
β€” live task event stream (SSE)
GET/PUT /v1/sandboxes/{id}/files
{"path","content","append"}
list / read / write workspace files
GET /healthz , GET /readyz
β€” liveness / readiness

A complete, copy-pasteable runbook (including driving it from your own agent) is in .

AGENTS.md

Concern Choice
Container runtime Docker + hardened runc (cap-drop ALL, no-new-privileges , read-only rootfs)
Workspace storage one bind-mounted directory per sandbox under the data dir (persists)
Edge / preview Traefik v3 Docker provider β€” sandboxes self-register their routes
Idle management stop-on-idle (docker stop ) + wake-on-request; no warm pool
State SQLite (WAL); a reconciler converges Docker to the DB on boot
Control plane one Go binary, shells out to the docker CLI over the mounted socket

The control plane runs in a container with the host Docker socket mounted and launches each sandbox as a sibling container on a shared network so Traefik can route to it. Full design: ARCHITECTURE.md.

Everything is in .env

(created from .env.example on install). The defaults run a complete local stack. The knobs you'll touch most:

Variable Default What it does
PREVIEW_DOMAIN
localhost
domain preview URLs hang off
HTTP_PORT
80
host port Traefik listens on
SANDBOXED_DATA_DIR
/var/lib/sandboxed
where workspaces + state live
SANDBOXED_API_BIND
127.0.0.1:9090
where the control-plane API is published
SANDBOXD_API_AUTH_DISABLED
true
open API for local use; set false + tokens for prod

For a public deployment on a real wildcard domain:

  • Point *.preview.yourdomain.com

at the host. - In traefik/traefik.yml

, enable thewebsecure

entrypoint and add a certificate resolver (Let's Encrypt DNS-01 is ideal β€” one wildcard cert covers every preview host, so you never hit per-host ACME limits). - In .env

:PREVIEW_DOMAIN=yourdomain.com

,PREVIEW_ENTRYPOINT=websecure

,PREVIEW_TLS=true

, andenable authβ€”SANDBOXD_API_AUTH_DISABLED=false

withSANDBOXD_API_TOKENS=name:secret

. docker compose up -d

.

./uninstall.sh            # stop the stack + remove all sandboxes + network (keeps your data)
./uninstall.sh --images   # also remove the built Docker images
./uninstall.sh --data     # also DELETE all workspaces + state (asks to confirm)
./uninstall.sh --all      # full removal: images + data

Safe by default β€” it removes only what sandboxed created (containers labelled sandboxed.managed=true

, the compose stack, the network) and keeps your workspaces unless you pass --data

/--all

.

sandboxed v1 optimizes for "runs anywhere with just Docker." A few things are deliberately simple β€” none affect the core loop (create β†’ build β†’ preview β†’ idle β†’ wake β†’ persist), and each is a known place to harden:

No hard per-workspace disk quota. Workspaces are plain directories on a shared filesystem. Add fs/volume quotas if you need them.Soft memory throttle off by default. The hard per-sandbox--memory

ceiling still applies; the gentler cgroupmemory.high

is opt-in.Egress is default-allow, unlogged. Add host firewall rules / a proxy for egress control.Snapshots/templates are experimental on directory storage.

Contributions toward any of these β€” and toward more agent backends β€” are very welcome. See CONTRIBUTING.md.

Be deliberate before exposing this to the open internet. Honest notes:

Sandboxes run real user code under hardened(dropped capabilities,runc

no-new-privileges

, read-only rootfs, memory/PID/file-descriptor limits) β€” but this iscontainer isolation, not VM isolation. It's designed for** authenticated, accountable users running their own code**, not anonymous hostile multi-tenancy. If you need to run untrusted strangers' code, put each trust domain on its own VM, or add a stronger runtime (gVisor/Kata/Firecracker).The control plane holds the Docker socket, which is root-equivalent on the host. Treat the host as part of your trust boundary, keep it patched, and don't co-locate unrelated sensitive workloads.The API ships with auth disabled for a smooth local start.Enable it before any non-local deployment(SANDBOXD_API_AUTH_DISABLED=false

+SANDBOXD_API_TOKENS

) and never publish the API port to the internet unauthenticated.Egress is unrestricted by defaultβ€” a sandbox can reach the network freely. Add firewall/egress controls if that's a concern for your users.** Preview URLs are unauthenticated by default**(anyone with the URL can view a public sandbox). Private sandboxes gate access via a forward-auth hook; wire it up before serving sensitive previews.

None of this is exotic β€” it's the standard "you're running a server that executes code" checklist. Follow it and sandboxed is a solid base.

Yes β€” that's exactly the point. If you want to ship an AI app-builder or agent SaaS without first spending months building multi-tenant isolation, preview routing, idle/wake cost control, and agent orchestration, sandboxed gives you that core on day one, on a single inexpensive server, with margins you control. It's a strong, honest starting point β€” beta-quality, MIT-licensed, and designed to be read and extended. Launch lean on it, harden the items above as you grow, and contribute the improvements back.

MIT. Use it, ship it, sell what you build on it.

── more in #ai-infrastructure 4 stories Β· sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/self-hosted-dev-sand…] indexed:0 read:9min 2026-06-03 Β· β€”