code-runner
Self-Hosting

The Local Stack

What docker compose brings up, and the Make targets you'll use.

The repo ships a docker-compose.yml that runs the whole system locally. A plain docker compose up is a true no-op for optional features — no telemetry, no extra services — so the default experience is minimal.

Services

ServiceImageRoleExposed
redisredis:7-alpineJob queue, stdin/control pub-sub, job metadata.internal
soketiquay.io/soketi/soketi:latest-16-alpinePusher-compatible WebSocket fan-out.6001
apiapps/api/DockerfileHono gateway.8080
workerapps/worker/DockerfileGo worker; mounts the host Docker socket.internal
miniominio/minioS3-compatible artifact storage (dev).9000/9001
stubapps/stub/DockerfileInteractive E2E driver.profile stub
otel-collectorotel/opentelemetry-collector-contribOTLP receiver.profile observability
jaegerjaegertracing/all-in-oneTrace UI at :16686.profile observability

All services share the code-runner bridge network. The worker mounts /var/run/docker.sock — sandboxes run on your host daemon (no Docker-in-Docker).

Build the language images first

The sandbox images (executor/python:3.12, etc.) are not built by compose — they must already exist on the host daemon. Run make build-images before your first job, or you'll get image-not-found errors at execution time.

Compose profiles

Optional services sit behind profiles so the default up stays lean:

docker compose up                              # core: redis, soketi, api, worker, minio
docker compose --profile stub up               # + the interactive E2E stub
docker compose --profile observability up      # + otel-collector + jaeger
docker compose up --scale worker=2             # run two worker nodes

Make targets

TargetWhat it does
make build-imagesBuild all four language images on the host daemon.
make python-image / rust-image / r-image / sqlite-imageBuild one image.
make updocker compose up --build.
make downdocker compose down -v.
make e2eFull interactive "hello World" round-trip via the stub.
make artifacts-e2eArtifacts pull-loop E2E (writes a PNG, uploads, pulls).
make abuseThe adversarial safety suite (Docker cgroup v2 + redis:7 on :6381).
make testAll unit/integration tests (Go + JS).
make contractRegenerate the wire contract (TS + Zod + Go).
make contract-checkFail if generated contract artifacts drifted.
make helpList every target.

Helper scripts

ScriptPurpose
scripts/e2e.shWhat make e2e runs: brings up the stack, runs the stub, tears down.
scripts/artifacts-e2e.shPhase-9 artifact capture/upload/pull demo.
scripts/observability-e2e.shBrings up the observability profile and proves one connected trace in Jaeger.
scripts/try-fly.shA zero-checkout demo against a deployed Fly.io gateway (TOKEN=… bash scripts/try-fly.sh).

Typical first run

cp .env.example .env
make build-images
docker compose up        # leave running
make e2e                 # in another terminal — expect "E2E PASS"

From here, head to Configuration to understand every knob, or Scaling for the production topology.

On this page