Fall 2026brianmars.comBuilt at EGBT Technologies
ReferenceContainers

Docker Engine on Debian

Docker Engine and the Compose plugin on a headless Debian 13 box, with storage on a separate data volume and DNS that works behind Tailscale.

Names and addresses are placeholders. The list says what each one stands for.

What it does here

Every service on the box runs as a container. Docker Engine with the Compose v2 plugin is the only runtime on the host, so the host itself stays small and replaceable.

From the manual

Canonical setup

This follows Docker's own Debian instructions. Use the official repository, not Debian's docker.io package, so Compose v2 and Buildx come along and versions track upstream.

Add the repository
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg \
  -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
Install the engine and plugins
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin
Run without sudo, start at boot
sudo usermod -aG docker youruser
sudo systemctl enable --now docker

Upstream: Install Docker Engine on Debian and Linux post-installation steps.

Edited for this build

In this build

  1. Storage moved to /srv/data/dockerImages and volumes live on the data disk, so an OS reinstall leaves them alone.
  2. DNS pinned to 1.1.1.1 and 1.0.0.1Bridge containers can't reach Tailscale's MagicDNS resolver. See the MagicDNS seam below.
  3. Logs capped at 3 × 10 MB per containerDefault json-file logs grow without limit and fill the disk quietly.
  4. Docker waits for the /srv mountWithout it, Docker can start before the data volume is mounted.

Changes 1 to 3 are one file. It's root-owned, so write it with sudo.

/etc/docker/daemon.json
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
  "data-root": "/srv/data/docker",
  "dns": ["1.1.1.1", "1.0.0.1"],
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}
EOF

Change 4 is a systemd drop-in that orders Docker after the mount.

docker.service.d/wait-for-srv.conf
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/wait-for-srv.conf \
  >/dev/null <<'EOF'
[Unit]
RequiresMountsFor=/srv/data/docker
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Where it breaks

Seams

Where this meets the rest of the build. Each one leads with what you will actually see.

Docker meets Tailscale MagicDNS

Symptomserver misbehaving

A bridge-networked container inherits the host's resolver, which on a tailnet is 100.100.100.100. That address isn't reachable from inside the container, so external lookups fail. Pinning dns in daemon.json fixes every bridge container at once. Host-network containers use the host resolver directly and are unaffected.

Docker meets the separate data volume

Symptomno error, and no containers after a reboot

With data-root on /srv, Docker can win the race at boot and start against an empty mountpoint. The RequiresMountsFor drop-in closes the race. Only a reboot test catches this one.

The docker group meets an open shell

Symptompermission denied while trying to connect to the Docker daemon socket

Group membership applies to new login sessions only. Run newgrp docker for the current shell, or log out and back in.

The docker group meets tmux

Symptomthe same error, in panes opened after newgrp

A tmux server started before the group change keeps the old groups, and every new pane inherits them, even after you reconnect. Run tmux kill-server once. Containers keep running.

Verify

Checks
docker run --rm hello-world
docker info | grep "Docker Root Dir"   # /srv/data/docker
id -nG                                  # includes docker

Then reboot and confirm docker ps shows your containers without intervention.

Corrections and updates
  1. 17 Oct 2026First published. Verified on Debian 13.6.