docker-bastion/examples/docker-mailserver-vps/README.md

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

  1. Paths are preset to /srv/docker-mailserver (host and in-jail, identical). If your directory is elsewhere, edit the two paths in docker-compose.yml and keep both sides of the : identical — a different in-jail path still lets you read/edit files, but docker compose from 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.
  2. Add your key:
    mkdir -p docker-data/bastion/users.d
    cp ~/.ssh/id_ed25519.pub docker-data/bastion/users.d/me.pub
    
  3. 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.