Single-service image for browser-mode ZCode: SPA + password login + same-origin /git-proxy.
Remote REH/terminal is optional and not baked into the default image (platform-specific multi-GB artifact). Use zcode serve with a local dist/server for full remote IDE.
| Rule | How |
|---|---|
| Non-root | Image USER 10001:10001 (zcode) |
| No secrets in URL | Login cookie only (KD12) |
| Stateless git-proxy | In-process /git-proxy |
| Multi-arch | linux/amd64 + linux/arm64 via scripts/docker-build.sh --platforms … |
# Host arch
bash scripts/docker-build.sh
# or:
docker build -f deploy/docker/Dockerfile.server -t zcode:local .
# Multi-arch → registry (buildx)
bash scripts/docker-build.sh \
--platforms linux/amd64,linux/arm64 \
--push \
--tag ghcr.io/spinupdev/zcode:devcd deploy/docker
export ZCODE_PASSWORD='change-me'
docker compose up --build -d
curl -sS http://127.0.0.1:8080/healthz
# open http://127.0.0.1:8080/ → login → SPAWorkspace data: named volume zcode-workspace → /home/workspace.
docker run --rm -p 8080:8080 \
-e ZCODE_PASSWORD=change-me \
-v zcode-ws:/home/workspace \
--user 10001:10001 \
--security-opt no-new-privileges \
zcode:localGET /healthzandGET /readyz→{ ok: true, … }- Image
HEALTHCHECKprobes loopback/healthz
- Base:
node:22-bookworm-slim(official multi-arch). - Default
docker buildproduces the host architecture only. - Cross-build needs Docker Buildx + binfmt (Docker Desktop /
tonistiigi/binfmt). - Do not commit REH binaries into the image context; fetch/package per platform.
- Non-root UID/GID 10001
-
tinias PID 1 -
no-new-privilegesin compose - Healthcheck
- Workspace volume not root-owned in image
-
.dockerignoreexcludesvendor/, REH, node_modules - Optional: read-only rootfs + tmpfs (breaks some Node paths — deferred)
- Optional: distroless runtime (needs more packaging work)
- docs/hosting.md — topologies
- docs/hosting-production.md — Cloudflare Pages+Worker (H3)
- docs/building-vscode.md — REH compile if layering remote