- Python 89.4%
- Shell 9.1%
- Dockerfile 1.5%
| gateway | ||
| .gitignore | ||
| compose.yaml | ||
| containers.json | ||
| deploy.sh | ||
| Dockerfile | ||
| network.py | ||
| README.md | ||
| requirements.txt | ||
| server.py | ||
| ssh_config | ||
Lab in a box
From a clone of this repo:
./deploy.sh
Open http://localhost:3000/. Exit, disconnect, refresh or expiry deletes the lab and its files. Redeployment ends existing sessions.
Needs ip and either Podman with podman-compose and user systemd, or Docker
with Compose and socket access. Podman is preferred when installed; override
with CONTAINER_ENGINE=docker. Use CONTAINER_SOCKET for a nonstandard socket.
For a reverse proxy:
ALLOWEDORIGINS=https://terminal.example.com ./deploy.sh
Only localhost HTTP is published. The coordinator’s SSH port stays internal. No authentication or TLS is included.
Configuration
Edit containers.json, then redeploy.
default: definition opened automatically. Omit it for a numbered menu./ssh/<name>opens a definition directly.max_sessions,max_starts_per_minute: global caps, currently 32 and 60.- Each definition sets
image, optional prettylabel,memory_mb,cpus,pids_limitandmax_lifetime_seconds. internet: defaults tofalse;trueenables IPv4 TCP/UDP through a separate firewall gateway. Private/reserved networks and captured host routes are blocked.- Optional
disk_mb: writable-layer quota, e.g.1024. Unsupported quotas fail the session; omitting it leaves disk usage unlimited. log_sessionandlog_environment: optional booleans, both defaultfalse. The first records terminal input/output; the second records the SSH environment received by the coordinator, not the browser service's environment or cookies. Neither changes the student container's environment. Each logged session writessession-logs/<container-name>.jsonlon the host, with UTC timestamps and the container name assession. SetLAB_LOG_DIRto change the host folder. Terminaldatais base64;bytesis the original chunk size. Input chunks are received SSH data, not individual keystrokes or definitive paste detection. Files persist after sessions and redeployments until you remove them. A start event marks the launch attempt; end follows its cleanup attempt.forward_environment: optional list of SSH environment variables to pass into the lab, e.g.["LAB_USERNAME", "LAB_SESSION_ID"]; defaults to[]. Missing variables are skipped;TERMstays controlled by the terminal settings. Values are passed as engine environment entries, never shell commands. Only list variables the image should receive; students can change their copies.
Custom images must already exist in the engine and provide /bin/bash.
Set their USER and WORKDIR. Deployment pulls Debian and builds the gateway
and coordinator. Set LAB_CONFIG=/absolute/path/to/containers.json for an
external config. Toolbox images need no networking modifications.
Limits
Internet needs rootless Podman 6+ with Netavark, or Docker 28+. Redeploy after VPN, interface or route changes; blocked routes are a deployment-time snapshot. Podman forwarding and isolation tests passed; physical host/LAN positive-control coverage is incomplete. Docker has not been runtime-tested.
Coordinator compromise grants engine-socket access to the host. Bound engine storage separately to cover images, logs and labs without quotas. Session caps are global and can be occupied by one user.
Startup and shutdown remove labeled leftovers. Run one coordinator per engine. Coordinator logs record cleanup requests, failures and completion.