Skip to main content
Outcome: a long-running service in a sandbox, reachable at http://127.0.0.1:<PORT> from your frontend or browser. Level: beginner+ · Time: ~15 minutes · Pattern: the box is a tool the model calls.

When to use this

“AI app builder” products all share one shape: a model writes a Flask, FastAPI, or Next.js fragment, and the user sees it running in a browser seconds later. That needs more than “execute code, return stdout”:
  • a long-lived process listening on a port inside the isolated environment,
  • its HTTP endpoints reachable from the host frontend,
  • and a guarantee that if that service crashes, gets injected, or tries to read host files, nothing escapes.
Running a user-supplied web server with subprocess puts a listening, arbitrary-logic process inside your trust boundary. Port forwarding moves it out: the service listens on 0.0.0.0:<PORT> in the box, and the host reaches it at 127.0.0.1:<PORT>.

Architecture

Two consequences follow from that path:
  • Your exposed surface is exactly the ports you declare. Anything not listed in ports= is invisible to the host.
  • The service must bind 0.0.0.0. Forwarded traffic arrives at the guest’s network interface, not its loopback. A server bound to 127.0.0.1 inside the box is unreachable from the host — the connection is reset.

Prerequisites

  • BoxLite installed and a working virtualization host — see Installation.
  • Any image with Python. This guide uses python:alpine, whose standard library is enough — no packages to install.
No LLM credentials are needed: port forwarding is pure BoxLite. Swapping in model-generated code is covered under Next steps.

Build it

The app code is a plain string here — in production it is whatever your model generated or your user uploaded. It is written into the box base64-encoded, which avoids shell quoting problems entirely.
The ports parameter table — including the Node shape, which uses objects rather than tuples — lives on Network access.

Run it

All three responses, including the 404, came from the server running inside the microVM. Point a browser or an iframe at the same http://127.0.0.1:8080/... to get live preview.

Trust and limits

  • What the boundary covers. The service runs on its own kernel and filesystem with its own resource budget. Injection, rm -rf /, or an attempt to read host environment variables all stay inside the box; the host only ever receives HTTP on the ports you declared.
  • Your attack surface is the port list. Keep ports= as small as the scenario allows. This is the main security lever in this guide.
  • Binding 0.0.0.0 is a hard requirement. Traffic is forwarded to the guest’s network interface, not its loopback. Bind 127.0.0.1 inside the box and the host gets Connection reset by peer. That is topology, not a defect.
  • Nothing health-checks the background process for you. exec returns as soon as the command is launched. Confirm the service is up yourself — a short sleep plus a first request against /api/health, as above. Remember too that a non-zero exec exit does not raise; check result.exit_code.
  • Startup failures are catchable. No hypervisor or a failed image pull raises RuntimeError, not a crash.

Troubleshooting

Next steps

  • Turn it into an AI app builder. Replace APP_CODE with a model-generated fragment and embed the forwarded URL in an iframe. The LLM call skeleton is in Build a code interpreter.
  • Run a real framework. Use an image with your dependencies (or pip install flask in the box) and start it with flask run --host 0.0.0.0 --port <PORT>. Declare one ports pair per service.
  • Serve many tenants. For remote, multi-box backends behind one API, use the REST runtime — Manage remote sandboxes over REST.
  • Retrieve build artifacts. copy_out("/app/dist", "./dist") — see Moving files without a mount.