How to Install Docker on Debian 12 (Bookworm)

Why Debian 12 for Docker

Debian is what Ubuntu is built on, but without the extras. No snap packages, no Ubuntu Pro nag screens, no Canonical telemetry, no systemd-resolved stub resolver causing DNS headaches in containers. It’s a leaner, more predictable base for a Docker host, and there’s a reason it’s the default choice for most serious self-hosting deployments.

From the homelab: Debian is my go-to server OS for anything that needs to be rock-solid. Most of my Proxmox LXC containers run Debian, and Docker on Debian just works once it is set up correctly.

I run Debian 12 on most of my Proxmox VMs that serve as Docker hosts. Proxmox itself is Debian-based, so if you’re running Proxmox and creating VMs or LXC containers for Docker workloads, Debian 12 keeps your entire stack on the same foundation. No surprises when you’re troubleshooting at 2am.

This guide covers installing Docker Engine from Docker’s official repository on Debian 12 (Bookworm), the post-install configuration you shouldn’t skip, and the specific differences from our Ubuntu 24.04 Docker guide. If you’re coming from Ubuntu, I’ll call out where things differ so you’re not caught off guard.

Debian 12 terminal with Docker Engine installed and running, showing docker version output

Why Not Ubuntu?

Ubuntu is perfectly fine for Docker. I have an entire guide on it. But Debian has specific advantages for a dedicated Docker host:

  • No snap. Ubuntu’s push towards snap packages adds complexity and resource overhead. Docker via snap is particularly problematic, with sandboxing that breaks volume mounts and networking. Debian doesn’t have snap at all.
  • Lighter footprint. A minimal Debian 12 server install uses less RAM and disk than Ubuntu Server. On a VM where you’re allocating resources deliberately, that matters.
  • No systemd-resolved stub. Ubuntu’s DNS stub resolver on 127.0.0.53 is the single most common cause of DNS issues inside Docker containers. Debian doesn’t enable this by default, so DNS just works out of the box.
  • Longer track record for stability. Debian’s release cycle is slower and more conservative. Packages are older but thoroughly tested. For a Docker host where you want the platform to be boring and reliable, this is a feature.
  • Proxmox alignment. If your hypervisor is Proxmox, your VMs being Debian means one set of knowledge, one set of package management patterns, one set of troubleshooting skills.

The trade-off is that Debian’s base packages are older than Ubuntu’s. The kernel, systemd, and other system components will be behind Ubuntu LTS. For a Docker host this rarely matters because your workloads run inside containers with their own dependencies. The host OS just needs to run Docker reliably, and Debian excels at that.

Prerequisites

  • A machine running Debian 12 (Bookworm), either bare metal, VM, or LXC container
  • Root access or a user with sudo privileges
  • A working internet connection
  • At least 2 GB RAM and 20 GB disk space

If you’re running Docker inside a Proxmox LXC container rather than a VM, you need to enable specific container features. In the Proxmox web UI, go to the container’s Options > Features and enable keyctl and nesting. Without these, Docker won’t be able to manage its own containers inside the LXC. Some people also need to enable fuse depending on their storage driver. VMs don’t have this issue.

Step 1: Remove Debian’s Default Docker Packages

Debian 12 ships docker.io in its default repositories. This is an older, Debian-maintained build of Docker that lags behind the official releases. Remove it, even if you don’t think it’s installed:

sudo apt remove docker docker.io containerd runc 2>/dev/null
sudo apt autoremove -y

Unlike Ubuntu, you don’t need to worry about removing snap packages here. Debian doesn’t ship snap.

Step 2: Install Prerequisites

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

These may already be installed on a Debian 12 system, but it’s worth running to be sure. The gnupg package is needed for verifying Docker’s repository signing key.

Step 3: Add Docker’s Official Repository

This is where the process diverges from Ubuntu. The repository URL uses debian instead of ubuntu, and the codename will be bookworm.

Add Docker’s GPG key

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

Add the repository

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

Update the package index:

sudo apt update

You should see download.docker.com appear in the apt output. If the codename detection doesn’t work (rare, but possible on minimal installs), you can hardcode bookworm in place of the $(. /etc/os-release && echo "${VERSION_CODENAME}") substitution.

Step 4: Install Docker Engine

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

This installs the same set of packages as on Ubuntu:

  • docker-ce – Docker Engine daemon
  • docker-ce-cli – The docker command-line tool
  • containerd.io – The container runtime
  • docker-buildx-plugin – Extended build capabilities
  • docker-compose-plugin – Docker Compose v2 as docker compose

Step 5: Verify the Installation

sudo systemctl status docker

Look for Active: active (running). Then test with hello-world:

sudo docker run hello-world

If you see the “Hello from Docker!” message, the installation is complete. Check your versions:

docker version
docker compose version

Post-Install Configuration

These steps apply regardless of which Linux distro you’re running Docker on, but I’ll note where Debian behaves differently from Ubuntu.

Add your user to the docker group

sudo usermod -aG docker $USER

Log out and back in, then test without sudo:

docker run hello-world

On a fresh Debian 12 install, your user might not have sudo access by default. If sudo isn’t found or your user isn’t in the sudoers file, log in as root and run: apt install sudo && usermod -aG sudo yourusername. Then log back in as your user. This is a Debian-specific gotcha that Ubuntu users won’t expect, since Ubuntu configures sudo during installation.

Enable Docker on boot

sudo systemctl enable docker.service
sudo systemctl enable containerd.service

Configure log rotation

This is critical on any Docker host. Without it, container logs grow without limit and will eventually fill your disk. I’ve seen it happen on production servers, and it’s always at the worst possible time.

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
EOF

sudo systemctl restart docker

This caps each container’s log at 10 MB with 3 rotated files. Adjust to suit your disk space.

Configure DNS (usually not needed on Debian)

This is where Debian shines compared to Ubuntu. On Ubuntu, you almost always need to add explicit DNS servers to daemon.json because systemd-resolved listens on 127.0.0.53, which is unreachable from inside containers.

Debian 12 doesn’t enable the stub resolver by default. Your containers will inherit the host’s DNS settings from /etc/resolv.conf, and those settings will typically point to your network’s actual DNS server, not a loopback address. DNS inside containers just works.

If you do experience DNS issues (unlikely but possible depending on your network configuration), add DNS servers to your daemon.json:

{
  "dns": ["1.1.1.1", "8.8.8.8"]
}

If you run your own DNS server (Pi-hole, AdGuard Home), point Docker at that instead of public resolvers. That way your containers benefit from the same ad blocking and local DNS resolution as the rest of your network.

Differences from the Ubuntu Guide

If you’ve already followed the Ubuntu 24.04 guide and are now setting up a Debian host, here’s a quick reference of what’s different:

Aspect Ubuntu 24.04 Debian 12
Snap removal May need sudo snap remove docker Not applicable, no snap
Repository URL download.docker.com/linux/ubuntu download.docker.com/linux/debian
Codename noble bookworm
DNS in containers Often broken due to systemd-resolved stub Works out of the box
sudo access Configured during install May need manual setup
Base footprint ~1.2 GB RAM idle ~400-600 MB RAM idle

For Proxmox Users

If you’re running Proxmox and creating Docker hosts, Debian 12 is the natural choice since Proxmox itself is Debian-based. Here are some specific considerations:

VM vs LXC for Docker

Both work, but VMs are simpler. Docker in an LXC container requires the keyctl and nesting features enabled, and some storage backends can be problematic. If you’re not constrained on resources, a VM avoids these issues entirely.

For an LXC container, use a privileged container or ensure the unprivileged container has the right feature flags. In the Proxmox UI: Container > Options > Features > check keyctl, nesting, and optionally fuse.

Recommended VM sizing for Docker

  • Light use (1-5 containers): 2 CPU cores, 2 GB RAM, 32 GB disk
  • Medium use (5-15 containers): 4 CPU cores, 4 GB RAM, 64 GB disk
  • Heavy use (15+ containers): 4-8 CPU cores, 8 GB RAM, 100+ GB disk

Use virtio for both disk and network interfaces in Proxmox. The performance difference over IDE or E1000 emulation is significant, particularly for the I/O patterns Docker generates.

Create a Debian 12 VM template in Proxmox with Docker pre-installed. Then you can clone new Docker hosts in seconds. I have a template called “debian12-docker” that I clone whenever I need a new host. It has Docker installed, log rotation configured, and my SSH key already deployed. A new Docker host goes from zero to running containers in under two minutes.

Firewall Configuration

Debian 12 doesn’t ship with a firewall enabled by default, which means all your container ports are exposed to your network. If this Docker host is accessible from the internet, or even from an untrusted network segment, configure a firewall.

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable

Docker modifies iptables directly and bypasses UFW rules by default. This means a container publishing port 8080 will be reachable even if UFW doesn’t allow port 8080. This is a well-documented issue. The simplest mitigation is to bind container ports to 127.0.0.1 (e.g., -p 127.0.0.1:8080:80) and use a reverse proxy like Nginx to control external access. Alternatively, set "iptables": false in daemon.json, but be aware this breaks container-to-internet networking unless you add your own iptables rules.

Unattended Security Updates

For a server that runs continuously, enable automatic security updates so you’re not manually patching every Debian host in your fleet:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

This configures Debian to automatically install security patches. It won’t upgrade Docker itself (that comes from Docker’s repo, not Debian’s), but it keeps the base OS patched without intervention.

Debian is the dominant Linux distribution in enterprise server environments and the foundation for most container-optimised operating systems. If you’re building infrastructure skills for your career, being comfortable with Debian gives you a broader base than knowing only Ubuntu. The differences are subtle but they come up in interviews: “Why would you choose Debian over Ubuntu for a server?” is a question I’ve been asked twice. Having an answer that references resource overhead, DNS behaviour, and release stability demonstrates real operational experience.

Practitioner tip: If you are running inside a Proxmox LXC container, enable nesting in the container options first. Without it, Docker will not start and the error messages will not tell you why.

Key Takeaways

  • Debian 12 is a lighter, more predictable Docker host than Ubuntu, with no snap, no DNS stub resolver issues, and a smaller resource footprint
  • The installation process is nearly identical to Ubuntu, with debian replacing ubuntu in the repository URL and bookworm as the codename
  • Always install from Docker’s official repository, never from Debian’s default docker.io package
  • DNS inside containers works out of the box on Debian, unlike Ubuntu where you often need to configure daemon.json
  • Proxmox users should prefer Debian 12 for Docker VMs to keep the entire stack on the same distribution
  • For Docker in Proxmox LXC containers, enable keyctl and nesting features
  • Configure log rotation immediately and be aware that Docker bypasses UFW firewall rules by default
  • Create a Proxmox VM template with Docker pre-installed to spin up new hosts in minutes

Related Guides

If you found this useful, these guides continue the journey:

The RTM Essential Stack - Gear I Actually Use

Enjoyed this guide?

New articles on Linux, homelab, cloud, and automation every 2 days. No spam, unsubscribe anytime.

Scroll to Top