SSH into a fresh Docker container. Every connection gets a new Alpine shell; disconnect and the container is gone.
![]() disconnect, and the container is gone |
![]() a real pty -- history and vi work, not just piped text |
It's a single static binary and one TOML file. Point it at a Docker socket and it works.
Give it to a friend, a co-worker, or just test something out in a disposable environment -- they get a real Alpine box, and it's gone the moment they disconnect, nothing left running that you forgot about.
Handy for home-server setups too: point people at it and they get instant Linux access, no real account and no container to remember to clean up afterward.
sshbox accepts any username and password -- authentication is left to whatever sits in front of it (Tailscale, a VPN, a bastion). Don't expose port 2222 straight to the internet.
Every connection gets its own container: nothing from the host mounted in, no network access by default, capped at 256MB memory and half a CPU, killed the moment you disconnect. That isolates sessions from each other and from the host, but it's not a hardened sandbox against someone actively trying to break out.

rm -rf / inside the container -- disconnect, reconnect, like it never happened
Docker needs to be running first (docker info should succeed) -- brew install --cask docker on macOS, curl -fsSL https://get.docker.com | sh on Linux, or Docker Desktop on Windows. No Go required if you're using a prebuilt binary.
Grab the archive for your platform from the latest release and extract it, e.g.:
curl -LO https://github.com/kknxzz/sshbox/releases/download/v1.1.0/sshbox_1.1.0_linux_amd64.tar.gz
tar -xzf sshbox_1.1.0_linux_amd64.tar.gz
cd sshbox_1.1.0_linux_amd64
(swap the filename for your OS/arch -- Windows ships as a .zip)
Optional -- verify the download against checksums.txt from the same release:
shasum -a 256 -c checksums.txt --ignore-missing # sha256sum on Linux
Run it, then connect from another terminal:
./bin/sshbox
ssh -p 2222 anyone@localhost
Any username and password gets in. Exit or disconnect and the container is destroyed -- docker ps -a won't show it. Worth skimming the archive's README.txt too -- quick reference for flags and config.
Building from source instead: git clone the repo (needs Go) and go run ., or grab the source-only archive from the release (sshbox_1.1.0_source.tar.gz, no docs or media) and go build ..
sshbox reads config.toml from the current directory by default. Every field has a matching flag that overrides the file if passed; point at a different file with --config path/to/file.toml.
| Field | Flag | Default | Meaning |
|---|---|---|---|
listen_addr |
--listen |
:2222 |
address the SSH server binds to |
image |
--image |
alpine:latest |
image to run per session |
shell |
--shell |
/bin/sh |
command run inside the container |
network |
--network |
none |
Docker network mode |
memory |
--memory |
256m |
Docker memory limit |
cpus |
--cpus |
0.5 |
Docker CPU limit |
idle_timeout |
--idle-timeout |
10m |
disconnect after this long with no activity |
host_key_path |
--host-key |
host_key |
where the ssh host key is stored, generated on first run |
runtime |
--runtime |
docker |
container runtime binary -- docker or podman |
- No authentication -- see Security model above.
- Single node only, no clustering, no remote Docker hosts.
- No persistent storage -- nothing carries between sessions.
- No SFTP, SCP, or port forwarding.
- No Docker Compose -- one image, one container, per session.
- Linux containers only.
alpine:latestis barebones -- no curl, no sudo, no bash, just busybox andapk.apk add curlworks fine manually, it just doesn't persist. Pointimageat something fuller if that's annoying.- PTY support covers normal interactive shells: colors, resize, history. Full-screen apps with unusual escape sequences aren't tested exhaustively.
PRs welcome -- see CONTRIBUTING.md for style notes. Issues labeled good-first-issue are a good place to start. Star it if you find it useful.
MIT

