Installing Docker on Debian / Ubuntu

Covers Debian 12 (Bookworm) and Ubuntu 22.04+. Installs Docker Engine, the Compose plugin, and the Buildx plugin from Docker’s official repository — not the older docker.io package in distro repos.

Install

sudo apt-get update && sudo apt-get upgrade -y

sudo apt-get install -y \
  curl gnupg ca-certificates \
  apt-transport-https software-properties-common

# Add Docker's GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | \
  sudo tee /etc/apt/keyrings/docker.asc > /dev/null
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

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

For Ubuntu, replace debian with ubuntu in the two repository URLs.

Post-install

# Run Docker without sudo
sudo usermod -aG docker $USER
newgrp docker

# Enable on boot
sudo systemctl enable docker containerd

# Verify
docker run --rm hello-world
docker compose version

Daemon configuration

/etc/docker/daemon.json — sensible defaults for a container host:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
sudo systemctl restart docker

Firewall (UFW)

UFW and Docker both manipulate iptables. By default, Docker bypasses UFW rules for published ports — containers are reachable even if UFW would block the port. This is intentional Docker behavior.

# Allow SSH if UFW is enabled
sudo ufw allow 22/tcp
sudo ufw reload

Only expose the Docker API socket (2376) if you need remote access, and always use TLS when doing so.

Troubleshooting

# Service won't start
sudo journalctl -u docker -f
sudo dockerd --validate   # check daemon.json for errors

# Permission denied
groups $USER              # confirm 'docker' appears
sudo usermod -aG docker $USER && newgrp docker

# DNS broken inside containers
# Add to daemon.json:
# "dns": ["1.1.1.1", "8.8.8.8"]
sudo systemctl restart docker

See also