Container image used as a sandbox for a chat bot. Debian + Node, with python3-pip
and nano installed, plus two static web servers over the mounted /workspace.
| Port | Root | Behaviour |
|---|---|---|
| 8080 | /workspace/public_html |
Plain static server. Missing paths return 404. |
| 8081 | /workspace/public_spa |
Same, but unknown paths fall back to index.html. |
Both serve index.html for directories, send Cache-Control: no-cache so edits
show up on reload, and reject path traversal outside their root.
docker run -d \
-p 8080:8080 -p 8081:8081 \
-v /path/to/workspace:/workspace \
ghcr.io/xeonr/bot-sandbox:latestThe entrypoint stays in the foreground supervising both servers, restarting
either one if it exits, so the container stays up on its own. Terminal commands
get their own ttys — docker exec -it <container> bash for a shell. Passing a
command (docker run -it <image> bash) overrides the wait but still starts both
servers first.
Both document roots are created at startup if the mount does not already have
them. If a root is empty, a placeholder index.html is copied in from
/usr/local/share/bot-sandbox/ so the port shows something on first boot —
the SPA placeholder has buttons that demonstrate the index.html fallback on a
hard refresh. A root that already has files in it is left completely alone.
.github/workflows/docker.yml builds the image,
smoke tests it against a real container (static 404s, SPA fallback, asset serving,
path traversal), then pushes linux/amd64 and linux/arm64 to GHCR. Pull requests
build and test but do not push.
Tags: latest on main, the branch name, sha-<short>, and semver on v* tags.