2.8 KiB
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.