Bring Your Own Container
Run a sandbox with a custom container image. This example includes a ready-to-use Python REST API that you can build, deploy, and reach from your local machine through port forwarding.
Prerequisites
- A running OpenShell gateway (
mise run gateway:dockerfor local development) - Docker or Podman running, matching the gateway driver
What's in this example
| File | Description |
|---|---|
Dockerfile |
Builds a Python 3.12 image that starts a REST API |
app.py |
Minimal HTTP server with /hello and /health routes |
Quick start
1. Build the image and create a sandbox with port forwarding
# Docker gateway
docker build -t openshell-byoc:latest examples/bring-your-own-container
openshell sandbox create \
--from openshell-byoc:latest \
--forward 8080 \
-- python /sandbox/app.py
# Podman gateway
podman build -t localhost/openshell-byoc:latest examples/bring-your-own-container
openshell sandbox create \
--from localhost/openshell-byoc:latest \
--forward 8080 \
-- python /sandbox/app.py
Build the Dockerfile with the container engine used by your local gateway
before creating the sandbox, then pass its image reference to --from. For a
remote gateway, push the image to a registry that the gateway can pull from.
The --forward 8080 flag opens an SSH tunnel so localhost:8080 on your
machine reaches the REST API inside the sandbox.
Important: The image's CMD / ENTRYPOINT does not run automatically.
OpenShell replaces it with the sandbox supervisor (which manages SSH access,
network policy, etc.). You must pass your application's start command
after -- so it is executed via SSH once the sandbox is ready.
2. Hit the API
curl http://localhost:8080/hello
# {"message": "hello from OpenShell sandbox!"}
curl http://localhost:8080/hello/world
# {"message": "hello, world!"}
curl http://localhost:8080/health
# {"status": "ok"}
Running your own app
Replace app.py and the Dockerfile with your own application. The
key requirements are:
- Pass your start command explicitly — use
-- <command>on the CLI. The image'sCMD/ENTRYPOINTis replaced by the sandbox supervisor at runtime. - Declare a non-root OCI
USERfor Docker and Podman. Use a named account such asapp, a numeric UID with a passwd entry that supplies its primary GID, or a numeric pair such as1500:1500. You can instead set bothprocess.run_as_userandprocess.run_as_groupexplicitly in policy. - Prepare
/sandboxas the workspace. Until OCI working-directory support is added, create/sandboxand make it writable by the selected identity. The example does this withinstall -d -o app -g app /sandbox. - Install
iproute2for full network namespace isolation. - Use a standard Linux base image — distroless and
FROM scratchimages are not supported.
How it works
OpenShell handles all the wiring automatically. You build a standard
Linux container image — no OpenShell-specific dependencies or
configuration required. When you create a sandbox with --from,
OpenShell ensures that sandboxing (network policy, filesystem isolation,
SSH access) works the same as with the default image.
Port forwarding is entirely client-side: the CLI spawns a background
ssh -L tunnel through the gateway. The sandbox's embedded SSH daemon
bridges the tunnel to 127.0.0.1:<port> inside the container.
Cleanup
Delete the sandbox when you're done (this also stops port forwards):
openshell sandbox delete <sandbox-name>