Updated: 2026-07-07

Installing Docker on Debian 12 looks like a mechanical errand: copy four commands and done. But hidden inside that process are decisions that shape the next twelve months of operation. Which repository to use, how to manage permissions, and what to put in daemon.json from the very first boot are questions with real consequences once the machine graduates from experiment to exposed service.

Key takeaways

  • Debian’s docker.io package trails several minors behind; the official Docker repository is the only reasonable choice for production.

  • The standard install requires five packages: docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, and docker-compose-plugin.

  • Membership in the docker group is practically equivalent to root on the machine; evaluate rootless Docker on shared servers.

  • Configure log rotation and live-restore in daemon.json from day one to avoid the most common problems.

  • The docker run hello-world that prints the green message is the beginning, not the end.

Why Not the Debian Package

Debian ships docker.io in its repositories, and for tinkering on a laptop that is fine. Once the machine does real work, the distribution package falls short:

  • The packaged version trails Docker’s stable branch by several minors.

  • Security patches take longer to land.

  • Components (engine, CLI, containerd, BuildKit) are not updated as a coordinated set.

Docker’s official repository solves all three: you get the current version, patches arrive the day they are released, and components move together. This tutorial follows the official installation guide for Debian[1] on Debian 12 "Bookworm", released June 10, 2023 according to the official release page[2]. The Debian wiki’s Docker page[3] draws the same line: docker.io is Debian’s own package, docker-ce is the upstream equivalent. The docker compose v2 plugin also comes packaged alongside the engine, ending the historical dance between hyphenated docker-compose and space-separated docker compose.

Preparing the Ground

Before adding anything new, remove any previous install:

sudo apt-get remove docker docker-engine docker.io containerd runc

This cleans the binaries without touching images or volumes in /var/lib/docker and /var/lib/containerd. With the system clean, update APT and install the minimum dependencies for adding a signed repository:

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

GPG Key and Repository

Debian’s modern method for repository keys is to drop them into /etc/apt/keyrings/ as individual files. The old apt-key add has been deprecated for years because a globally installed key implicitly signs any repository, breaking APT’s isolation.

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | 
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo 
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] 
  https://download.docker.com/linux/debian 
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | 
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

The signed-by= directive makes the key exclusive to that repository: APT will only accept Docker signatures for packages from download.docker.com.

Bash logo, the command interpreter used to run all Docker installation steps on DebianBash logo, the command interpreter used to run all Docker installation steps on Debian

Installing the Right Packages

Docker is not a single binary but a collection of pieces:

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io 
  docker-buildx-plugin docker-compose-plugin

What each does:

  • docker-ce: the dockerd daemon listening on the Unix socket and orchestrating containers.

  • docker-ce-cli: the docker client that talks to the daemon.

  • containerd.io: the low-level runtime that launches containers.

  • docker-buildx-plugin: multi-platform builds with BuildKit.

  • docker-compose-plugin: declarative v2 orchestrator.

After the install, systemd starts the service and leaves it enabled.

Verification and the docker Group

Three commands confirm everything is in place:

docker --version
docker compose version
docker run hello-world

If the last fails but the first two succeed, the problem is usually DNS or the registry, not the install.

Adding your user to the docker group looks cosmetic but carries serious security implications, something the Debian wiki[3] puts bluntly: group membership is more dangerous than sudo access. Group membership is practically equivalent to root on that machine: anyone who can run docker run can mount the root filesystem inside a privileged container. On a shared server, evaluate rootless Docker[4] instead. On a personal box, the group is acceptable if you understand the trade-off.

sudo usermod -aG docker $USER
newgrp docker

Configuration that prevents surprises

The file /etc/docker/daemon.json is empty by default. Leaving it that way is the first production mistake almost everyone makes. Two parameters that deserve to be set from day one:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true
}

Without log rotation, a chatty container fills the disk in days: the example above caps each file at 10 MB and keeps a maximum of 3 in rotation. With live-restore[5], containers survive a daemon restart, so Docker upgrades stop taking services down. Apply changes with sudo systemctl reload docker.

Prometheus logo, the metrics tool you can use to monitor the Docker daemon state in productionPrometheus logo, the metrics tool you can use to monitor the Docker daemon state in production

Problems that always show up

  • permission denied without sudo: the group change hasn’t applied to the session. newgrp docker fixes it.

  • Cannot connect to the Docker daemon: dockerd isn’t running. systemctl status docker and journalctl -u docker -n 100 reveal the cause.

  • Slow pulls: Docker Hub limits anonymous pulls[6] to 100 every 6 hours, or DNS issues. A local registry-mirrors is the remedy.

  • Disk full: docker system prune -a --volumes frees space aggressively, including anonymous volumes: be careful.

Conclusion

What separates a viable install from one that will bite you in six months is not any command in the official repo, but the decisions you make right after. Configure log rotation from day one. Enable live-restore. Understand what the docker group implies. None of these shows up in five-minute tutorials, and all matter more than the exact order of the packages.

With the daemon running, the natural next step is often a management interface: how to install Portainer with Docker Compose v2. If the plan is to run the server with Docker Swarm, the next step is when Docker Swarm still makes sense.

This article is also available in Spanish: Como instalar Docker en Debian 12 paso a paso.

Frequently asked questions

Do I need to remove docker.io before installing Docker CE on Debian 12?

Yes. Run sudo apt-get remove docker docker-engine docker.io containerd runc before adding the official repository. The two packages compete for the same socket and the same service files, so leaving them side by side causes inconsistent startups.

Why is being in the docker group a security risk?

Because any account with access to the Docker socket can mount the root filesystem inside a privileged container, which is effectively root on the machine. On a shared server, the reasonable alternative is rootless Docker.

What do I do if docker run hello-world fails after installation?

If docker --version and docker compose version respond fine but hello-world fails, the problem is almost always network-related (DNS or registry access), not the package installation itself.

Sources

  1. official installation guide for Debian
  2. official release page
  3. Docker page
  4. rootless Docker
  5. live-restore
  6. limits anonymous pulls