A disposable jail container that bind-mounts only one directory; the bastion's FORCE_COMMAND drops every SSH session into an interactive shell inside it. The jail's own root fs is throwaway image data, so the only host data reachable over the session is the mounted directory. Documents the docker-socket tradeoff and the read-only / no-socket hardened variants. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Dockerfile | ||
| README.md | ||
| docker-compose.yml | ||
README.md
docker-mailserver "fake VPS" (one directory, nothing else)
A copy-paste setup that gives an operator (or an agent) an interactive SSH
shell that feels like a VPS — but the only real host data on it is your
docker-mailserver directory. The rest of the server's filesystem isn't
mounted, so there's nothing else to see.
Contrast with the sibling ../docker-mailserver/
example: that one is broker mode — a fixed menu of setup email …
commands, no shell. This one is the opposite — a full shell, scoped to one
directory, for when you want to edit configs and drive docker compose
yourself.
What you get
ssh -p 2222 agent@your-host
└─ bastion-vps key auth; forces every session into the jail
└─ docker exec -it dms-jail bash
└─ dms-jail disposable alpine + docker/compose/editors/git
ONLY real mount: your docker-mailserver directory
you land in it, read-write
Inside the shell you can vim mailserver.env, docker compose up -d,
docker exec mailserver setup email add …, git pull, etc.
Setup
- Paths are preset to
/srv/docker-mailserver(host and in-jail, identical). If your directory is elsewhere, edit the two paths indocker-compose.ymland keep both sides of the:identical — a different in-jail path still lets you read/edit files, butdocker composefrom the jail would resolve the stack's bind mounts to a host path that doesn't exist and bring the mailserver up with empty data. - Add your key:
mkdir -p docker-data/bastion/users.d cp ~/.ssh/id_ed25519.pub docker-data/bastion/users.d/me.pub - Launch:
docker compose up -d --build ssh -p 2222 agent@your-host
Security note — the docker-socket tradeoff
To let you run docker compose / restart the mailserver from the shell, the
jail is given the host docker socket. A docker socket is host-root
equivalent — from inside the shell, docker run -v /:/host alpine sh would
expose the whole host. So this is a practical one-directory VPS for trusted
operators, not a hard sandbox an adversary can't escape.
Want a real "only this directory exists" boundary instead? Remove the
/var/run/docker.sock mount from both services in the compose file. You
lose in-shell docker compose/restart (manage the stack from a separate
broker-mode bastion — see ../docker-mailserver/),
but the shell then genuinely cannot reach anything but the mounted directory.
The auth boundary is your SSH key (users.d/*.pub) plus the bastion's
ForceCommand, which clients cannot bypass — a session can only ever become
the jail shell, never anything else.