94 lines
4.8 KiB
YAML
94 lines
4.8 KiB
YAML
# ===========================================================================
|
|
# 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
|