docker-bastion/examples/docker-mailserver-vps/docker-compose.yml

94 lines
4.8 KiB
YAML
Raw Normal View History

# ===========================================================================
# docker-mailserver "fake VPS" — one directory, nothing else
# ===========================================================================
# Goal: hand someone (or an agent) an SSH session that *feels* like a VPS, but
# the only real thing on it is your docker-mailserver directory. The rest of
# the host filesystem is simply not there — there is nothing else mounted to
# see.
#
# How it works:
# ssh agent@your-host
# └─ bastion-vps (key auth; forces every session into the jail)
# └─ docker exec -it dms-jail bash (interactive login shell)
# └─ dms-jail container
# • base image = disposable alpine + tooling (NOT your host)
# • ONLY host data mounted: the docker-mailserver directory
# • lands you in that directory with a real shell
#
# ─── SECURITY NOTE — READ THIS ────────────────────────────────────────────
# This setup gives the jail the docker socket so you can run `docker compose`
# / restart the mailserver from inside. A docker socket is *host-root
# equivalent*: from that shell, `docker run -v /:/host alpine ...` would expose
# the entire host. So this is a *practical* one-directory VPS for trusted
# operators, NOT a hard security sandbox. If you ever want a true "only this
# directory exists, no escape" jail, drop the docker.sock mount from BOTH
# services below — you lose `docker compose`/restart but gain a real boundary,
# and manage the stack from a separate broker-mode bastion instead (see
# ../docker-mailserver/).
# ───────────────────────────────────────────────────────────────────────────
#
# Setup:
# 1. Paths are preset to /srv/docker-mailserver (host AND in-jail, identical).
# If your directory lives elsewhere, change BOTH occurrences below and keep
# the two sides of the colon IDENTICAL — that is what lets `docker compose`
# inside the jail find the stack's bind mounts at the paths the host daemon
# expects. A different in-jail path (e.g. .../dms-vps) still lets you read
# and edit files, but `docker compose up` from the jail would create empty
# dirs on the host at the wrong path and bring the stack up with no data.
# 2. Drop your SSH public key:
# mkdir -p docker-data/bastion/users.d
# cp ~/.ssh/id_ed25519.pub docker-data/bastion/users.d/me.pub
# 3. docker compose up -d --build
# 4. ssh -p 2222 agent@your-host # you land in the directory, in bash
# ===========================================================================
services:
# ---- The jail: a disposable shell box -----------------------------------
dms-jail:
build: .
image: dms-vps-jail:latest
container_name: dms-jail
restart: unless-stopped
working_dir: /srv/docker-mailserver
volumes:
# THE one directory. Host path : in-jail path — keep them identical.
# This is the ONLY real host data the SSH session can touch (read-write).
- /srv/docker-mailserver:/srv/docker-mailserver
# Docker control: the host daemon socket, so `docker compose up/down`,
# `docker exec mailserver setup …`, logs, restarts all work from the
# shell. Host-root-equivalent — see the SECURITY NOTE above.
- /var/run/docker.sock:/var/run/docker.sock
networks: [web]
# ---- The bastion: SSH front door, forces every session into the jail ----
bastion-vps:
image: blaxsoftware/bastion:latest
restart: unless-stopped
depends_on: [dms-jail]
environment:
# Every authenticated SSH session becomes an interactive bash shell
# inside the jail, in the docker-mailserver directory. `-it` allocates a
# TTY (this is an interactive shell → use SSH, not the HTTP path).
FORCE_COMMAND: "docker exec -it -w /srv/docker-mailserver dms-jail bash"
volumes:
# The bastion needs the socket too — only to `docker exec` into the jail.
- /var/run/docker.sock:/var/run/docker.sock
# Authorized clients — drop one *.pub per identity. Read live, no restart.
- ./docker-data/bastion/users.d:/etc/bastion/users.d
# Persist the SSH host identity across rebuilds (bind mount, never a
# named volume — `down -v` would wipe it and clients would see a changed
# host key).
- ./docker-data/bastion/keys:/etc/ssh/keys
ports:
# SSH on host port 2222. Bind to 127.0.0.1 and front with a tunnel/VPN
# if you don't want it on the public internet.
- "2222:22"
networks: [web]
networks:
web:
external: true