Debian is a favourite base for Docker hosts: small, stable and predictable. Debian’s own docker.io package works, but Docker’s official repository gives you current releases plus the Compose and Buildx plugins. Here’s the clean way to set it up on Debian 12 (bookworm) and Debian 13 (trixie).
Run the commands as root, or prefix them with sudo if your user has it.
1. Remove old or conflicting packages
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
apt-get remove -y $pkg
done
It’s fine if none of them are installed.
2. Add the Docker repository
apt-get update
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
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" \
> /etc/apt/sources.list.d/docker.list
apt-get update
Note the URL path is /linux/debian, not /linux/ubuntu — mixing them up is the most common installation error on Debian. If Docker hasn’t published packages for a brand-new Debian release yet, apt-get update reports a missing Release file; wait for upstream support rather than pointing at the previous codename.
3. Install
apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Verify:
systemctl is-active docker
docker run --rm hello-world
docker compose version
4. Let a regular user run Docker
usermod -aG docker youruser
Log out and back in for the group to apply. Remember that the docker group grants root-equivalent access to the host — add only administrators.
5. Limit container log size
Debian VPS images often have modest disks, and container logs grow forever by default. Create /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
systemctl restart docker
New containers get the limit; recreate existing ones to apply it.
6. Firewalls: Docker vs UFW and nftables
Debian 12 and 13 use nftables under the hood, and Docker programs its own rules (through the iptables-nft compatibility layer). The effect matters for security:
- A port published with
-p 8080:80is reachable from outside even if UFW or your own nftables rules block 8080, because Docker inserts its rules first. - Publish internal services on localhost only —
-p 127.0.0.1:8080:80— and expose them through a reverse proxy. - To filter traffic to containers, add rules to the
DOCKER-USERchain, which Docker leaves for you and evaluates before its own rules.
Example: allow access to published container ports only from one office IP:
iptables -I DOCKER-USER -i eth0 ! -s 203.0.113.10 -j DROP
(Replace eth0 with your public interface from ip -br addr.) Save such rules with iptables-persistent or a systemd unit, since they don’t survive a reboot otherwise.
7. Where Docker keeps data
Everything — images, containers, volumes — lives under /var/lib/docker. If your VPS has a separate, larger data disk, move it there before you pull many images:
{
"data-root": "/srv/docker"
}
Stop Docker, copy the old directory with rsync -aP /var/lib/docker/ /srv/docker/, add the setting to daemon.json, then start Docker again.
Keeping Docker up to date
Docker updates arrive with normal system updates:
apt-get update && apt-get upgrade
If you use unattended upgrades, note that by default only the Debian security archive is upgraded automatically; Docker’s repository is not included unless you add it to the allowed origins. Many admins prefer updating Docker by hand, since a daemon restart restarts all containers.
Troubleshooting
E: Package 'docker-ce' has no installation candidate— the repository line is wrong (often Ubuntu URL or a typo in the codename). Check/etc/apt/sources.list.d/docker.list.docker.servicefails to start — runjournalctl -u docker -n 50. Invalid JSON indaemon.jsonis the usual culprit; validate it withpython3 -m json.tool /etc/docker/daemon.json.- Containers have no internet access — check that IP forwarding wasn’t disabled by a hardening script:
sysctl net.ipv4.ip_forwardshould be1while Docker runs.
What to read next
- Docker Compose tutorial — define multi-container apps.
- Docker commands cheat sheet — the everyday commands.
- Debian initial server configuration — users, SSH and firewall before you add Docker.
Prefer Ubuntu? The steps are almost identical: install Docker on Ubuntu. Our Debian VPS images are minimal installs, ideal as Docker hosts.