How to Install Docker on Debian

Docker packages applications and their dependencies into portable containers that run identically across development workstations, test servers, and production infrastructure. Whether you need to deploy WordPress in isolated containers, orchestrate microservices with Docker Compose, build automated CI/CD pipelines, or maintain reproducible development environments, Docker provides the container runtime and management tools to handle these workloads.

By the end of this guide, you will have Docker CE installed from the official repository with automatic updates, non-root user access configured for convenience, log rotation enabled to prevent disk exhaustion, and systemd service management ready for production use. You will also understand Docker’s security model, including when to use the docker group versus rootless mode for privilege isolation.

Docker CE supports Debian 11 (Bullseye), Debian 12 (Bookworm), and Debian 13 (Trixie) on amd64, arm64, and armhf architectures. This guide uses the modern DEB822 repository format, which works on all supported Debian versions.

Docker Pre-Installation Steps

Before installing Docker CE, first remove any conflicting packages and ensure your system packages are current. These preparation steps prevent installation conflicts and establish a clean foundation.

Remove Previous Docker Instances

Unofficial Docker packages from Debian repositories or previous installations can conflict with the official Docker CE packages. Therefore, remove any existing Docker-related packages before proceeding:

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt remove $pkg; done

APT reports which packages were removed or confirms none were installed. This command also removes containerd and runc because Docker Engine bundles its own versions of these dependencies. Additionally, uninstalling Docker does not delete images, containers, volumes, or networks stored in /var/lib/docker/.

To start with a completely clean slate and remove all existing Docker data, you can optionally run the following commands. Skip this step if you want to preserve existing containers and images from a previous installation.

The following commands permanently delete all Docker images, containers, volumes, and networks. Back up any important data before proceeding.

sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

Update Debian Packages Before Docker Installation

Next, after removing older Docker versions, ensure your Debian system is fully updated. Updating promotes system stability and ensures your system packages are at their latest versions, thereby minimizing potential conflicts and vulnerabilities.

To update the list of available packages and upgrade the installed ones, run the following command:

sudo apt update && sudo apt upgrade

This command will first refresh the list of available packages (apt update), followed by the upgrade of any outdated packages (apt upgrade).

Import Docker CE APT Repository

Debian offers two approaches for configuring the Docker CE repository. Both methods install identical Docker packages from the official Docker repository and receive the same updates. Choose the method that best fits your workflow.

MethodComplexityBest For
extrepo (Recommended)SimpleQuick setup, automatic GPG key management
Manual RepositoryModerateFull control, custom configurations, scripted deployments

Method 1: Use extrepo for Simplified Setup (Recommended)

The extrepo tool manages third-party Debian repositories with a single command. It automatically handles GPG key downloads, repository configuration, and version detection. This method requires fewer steps and reduces the chance of configuration errors.

First, install extrepo if not already present:

sudo apt install extrepo

Then enable the Docker CE repository:

sudo extrepo enable docker-ce

Finally, refresh the package cache to make Docker packages available:

sudo apt update

Verify the Docker repository is configured correctly:

apt-cache policy docker-ce

Expected output shows the Docker package available from the official repository:

docker-ce:
  Installed: (none)
  Candidate: 5:29.x.x-1~debian.[version]~[codename]
     500 https://download.docker.com/linux/debian [codename]/stable amd64 Packages

The version number and codename (bullseye, bookworm, or trixie) will match your Debian release.

Because extrepo manages the repository configuration automatically, you can skip directly to the firewall section and then proceed with installation. If you prefer manual control over the repository configuration, continue with Method 2 below.

Method 2: Configure Repository Manually

Manual repository configuration gives you full control over GPG key placement and repository settings. This approach is useful for scripted deployments, air-gapped systems, or when you need to customize the configuration. The process involves installing prerequisites, importing the GPG key, and creating the repository file.

Install Initial Packages for Docker CE

Install the required packages for managing HTTPS repositories, GPG keys, and version detection. The lsb-release package provides the lsb_release command used to automatically detect your Debian version during repository configuration:

sudo apt install ca-certificates curl lsb-release

Add Docker CE GPG Key

Then, create the keyrings directory and download the Docker GPG key. This key verifies the authenticity of packages downloaded from the Docker 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

Add Docker CE APT Repository

Add the Docker repository using the modern DEB822 format. This configuration automatically detects your Debian version and system architecture:

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(lsb_release -cs)
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Specifically, the repository configuration uses $(lsb_release -cs) to automatically match your Debian version (bookworm, trixie, etc.) and $(dpkg --print-architecture) to detect your system architecture (amd64, arm64, etc.).

Plan for Docker Firewall Behavior

Before installing Docker, it is important to understand how it interacts with your firewall. Docker manipulates iptables rules directly to enable container networking, which has significant security implications.

Docker bypasses UFW and firewalld rules when you publish container ports. Even if your firewall blocks port 8080, running docker run -p 8080:80 nginx exposes that port to the network. Docker is also only compatible with iptables-nft and iptables-legacy. Firewall rules created with nft directly are not supported. If you need to restrict Docker port access, add rules to the DOCKER-USER iptables chain.

For production servers exposed to the internet, therefore, audit which container ports you publish and consider binding to 127.0.0.1 instead of 0.0.0.0 for services that should not be publicly accessible (for example, -p 127.0.0.1:3306:3306 for MySQL).

Finalize Docker Installation

Now that the repository is configured, install the Docker packages and verify the installation works correctly.

Update Debian APT Cache After Docker CE Repository Import

Refresh your system package lists to include the newly added Docker repository:

sudo apt update

Install Docker via APT Command

Next, install Docker CE and its plugins. This command installs Docker Engine, the CLI interface, containerd runtime, Docker Buildx for multi-platform builds, and Docker Compose V2 (integrated as a plugin):

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

Then, verify the installed Docker version:

docker --version

The expected output shows the Docker CE version:

Docker version 29.x.x, build xxxxxxx

Your specific version number may differ as Docker releases updates regularly. Any version 24.0 or newer includes all features covered in this guide.

Verify Docker CE Installation on Debian

Finally, test your Docker installation by running the hello-world container:

sudo docker run hello-world

This command downloads a test image, creates a container, and runs it. As a result, successful output confirms Docker is working correctly:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:d211f485f2dd1dee407a80973c8f129f00d54604d2c90732e8e320e5038a0348
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

Configure Docker for Non-Root User

By default, Docker requires root privileges because the daemon binds to a Unix socket owned by root. However, you can add your user account to the docker group to run Docker commands without sudo:

The docker group grants root-equivalent privileges. Docker allows containers to mount any host directory, meaning a user in the docker group can start a container with -v /:/host and gain unrestricted access to the entire filesystem. Only add trusted users to this group. For true privilege isolation without root-equivalent access, use Docker rootless mode instead.

sudo usermod -aG docker $USER

Afterward, log out and log back in for group membership changes to take effect. Alternatively, you can activate the new group membership in your current session:

newgrp docker

Then, verify your user can run Docker commands without sudo:

docker run hello-world

If successful, you will see the Docker welcome message without any permission errors. This confirms that your user has proper Docker access.

Managing Docker via Systemd

Docker installs a systemd service that starts automatically after installation. Accordingly, use these commands to manage the Docker service lifecycle:

Check Docker Service Status

First, verify the Docker service is running:

systemctl status docker.service

Active services display output similar to the following:

● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: active (running) since Tue 2025-11-26 10:15:32 UTC; 5min ago
       Docs: https://docs.docker.com
   Main PID: 1234 (dockerd)
      Tasks: 8
     Memory: 45.2M
        CPU: 523ms

Start, Stop, and Restart Docker Service

Manually start the Docker service (only needed if disabled or stopped):

systemctl start docker.service

Similarly, stop the Docker service:

systemctl stop docker.service

Alternatively, restart the Docker service to apply configuration changes:

systemctl restart docker.service

Enable or Disable Docker Service on Boot

On Debian, Docker automatically starts on boot after installation. The service is enabled by default, so no manual configuration is needed for most users. However, to manually control this behavior:

First, enable Docker and containerd to start automatically at boot:

sudo systemctl enable docker.service containerd.service

Conversely, disable automatic startup at boot (useful for development machines or when using rootless mode):

sudo systemctl disable docker.service containerd.service

Docker Configuration Examples

After installation, you can further customize Docker behavior through daemon configuration and user management settings.

Configure Log Rotation

Docker uses json-file logging by default, which can grow indefinitely and exhaust disk space. Therefore, enable log rotation to prevent disk issues. Create or edit /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json

Add log rotation configuration:

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

This configuration limits each container log to 10MB with a maximum of 3 rotated files. Then, restart Docker to apply the changes:

sudo systemctl restart docker.service

Configure User Permissions for Docker

For additional users who need Docker access, simply repeat the usermod command with their username:

sudo usermod -aG docker username

Replace username with the actual account name. The user must log out and back in for changes to take effect.

Using Docker Compose V2

Additionally, the installation includes Docker Compose V2 as an integrated plugin. Use it with the docker compose command (note the space, not a hyphen):

docker compose version

Expected output confirms the Compose plugin version:

Docker Compose version v2.x.x

Compose V2 is the current standard and replaces the standalone docker-compose command from V1. It offers improved performance, better BuildKit integration, and tighter coupling with the Docker CLI. If you have existing projects using V1 syntax, Compose V2 maintains backward compatibility with most docker-compose.yml files.

Docker Command Examples

Docker provides commands for managing containers, images, networks, and volumes. The examples below cover the most common operations you will use when working with containers.

Fundamentals of Docker Commands

These core commands handle container lifecycle, image management, and resource cleanup:

  • docker run: Launches a new container from an image.
  • docker ps: Displays all currently running containers.
  • docker images: Lists all locally available images.
  • docker build: Constructs a new image from a Dockerfile.
  • docker stop: Halts a currently running container.
  • docker rm: Eliminates a container.
  • docker rmi: Deletes an image.
  • docker network: Administers Docker networks.
  • docker volume: Manages Docker volumes.

Each command has a unique set of options that allow you to modify its behavior to meet your needs. In the following sections, we explore each command and its respective options.

The docker run Command

The docker run command creates a new container from a specified image. For instance, to initiate a container from the Debian image and open an interactive shell within it, use the following command:

docker run -it debian:latest /bin/bash

The docker ps Command

Similarly, the docker ps command is deployed to list all currently active containers. It reveals valuable information about each container, including container ID, associated image, and running status. To get a list of all running containers, simply type:

docker ps

The docker images Command

Likewise, the docker images command is tasked with listing all locally available Docker images. It returns information about each image, including its ID, associated repository, and tag:

docker images

The docker build Command

The docker build command creates a new Docker image from a Dockerfile. A Dockerfile contains instructions for constructing a Docker image. For example, to build a new image named myimage using the Dockerfile in the current directory:

docker build -t myimage:latest .

The docker stop Command

The docker stop command gracefully terminates a running Docker container. You can target the desired container using its ID. For instance, to stop a container with ID ‘abcdefg,’ you would use:

docker stop abcdefg

The docker rm Command

Similarly, use the docker rm command to delete a Docker container. As with the stop command, specify the container ID of the container you wish to delete. For example:

docker rm abcdefg

The docker rmi Command

In the same way, use the docker rmi command to remove Docker images. Identify the image you want to delete by its ID. For example:

docker rmi 1234567

The docker network Command

Moreover, the docker network command is a versatile tool for creating, listing, and removing Docker networks. For instance, to create a new network named mynetwork, use:

docker network create mynetwork

The docker volume Command

Finally, the docker volume command offers functionalities to manage Docker volumes. For instance, to create a new volume named myvolume, use:

docker volume create myvolume

Navigating Docker Container Management

Effectively managing Docker containers significantly influences the functionality and longevity of a Docker environment. The docker command provides a variety of crucial sub-commands for manipulating Docker containers. These sub-commands facilitate container creation, operation, modification, and deletion. Whether you are a seasoned developer or a beginner in containerization, understanding these commands can enhance your Docker interaction substantially.

Core Commands for Docker Container Management

The docker ps command lists all running containers. The output shows each container’s image, status, and unique container ID:

docker ps

To terminate a currently active Docker container, the docker stop command is deployed. You append the unique ID or name of the container you want to stop.

docker stop abcdefg

The docker rm command is used to eradicate a Docker container. This command, like docker stop, accepts either the container’s unique ID or name as an argument.

docker rm abcdefg

It’s crucial to note that deleting a container discards any modifications made. You must create a new image from the modified container using the ‘docker commit’ command to retain changes.

Retaining Container Changes using docker commit

While working with Docker containers, you might need to customize a container and preserve these alterations as a new image. This can be accomplished using the docker commit command.

Initiate a new container using a base image and make the necessary alterations within this container. For instance, consider starting a new container from the Debian image and opening a shell inside the container:

docker run -it --name mycontainer debian:latest /bin/bash

You can perform various tasks in this new container, such as modifying configuration files or installing new software. After making the desired changes, use the docker commit command to produce a new image encapsulating these alterations. To create a new image named myimage with the changes made in the mycontainer container, execute the following command:

docker commit mycontainer myimage:latest

You now possess an image named myimage, incorporating changes made in the mycontainer container. Use this new image to generate and operate new containers with updated configurations or software.

The docker commit command only saves modifications to the container’s filesystem; it does not preserve networking or storage changes. To persist those configurations, use docker network and docker volume commands instead.

Troubleshooting Common Docker Issues

If you encounter problems with Docker, the following diagnostic steps help identify and resolve common issues.

Permission Denied Error

If Docker commands fail with a socket permission error:

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock

This error occurs when your user account is not in the docker group. First, verify group membership:

groups

If the output does not include docker, then add your user to the group and activate it:

sudo usermod -aG docker $USER
newgrp docker

Finally, verify the fix worked by running a test container:

docker run hello-world

Docker Config Permission Error

If you see a permission error about the Docker config file after adding your user to the docker group:

WARNING: Error loading config file: /home/user/.docker/config.json - stat /home/user/.docker/config.json: permission denied

This error occurs when Docker commands were previously run with sudo, creating the directory with incorrect ownership. To fix the permissions:

sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
sudo chmod g+rwx "$HOME/.docker" -R

Alternatively, you can remove the ~/.docker directory (Docker recreates it automatically, but custom settings will be lost).

Docker Service Not Starting

If Docker fails to start, check the service logs for specific error details:

sudo journalctl -xeu docker.service

A common error from invalid /etc/docker/daemon.json syntax looks like:

unable to configure the Docker daemon with file /etc/docker/daemon.json: invalid character '}' after object key

Therefore, validate the JSON syntax if you have custom configuration:

cat /etc/docker/daemon.json | python3 -m json.tool

Subsequently, after fixing any errors, restart Docker and verify it is running:

sudo systemctl restart docker.service
systemctl status docker.service

Repository GPG Key Errors

If APT reports GPG signature verification failures during updates, simply re-download the Docker GPG key:

sudo rm /etc/apt/keyrings/docker.asc
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
sudo apt update

Container DNS Resolution Fails

If containers cannot access the internet and show “Temporary failure in name resolution” when running apt update:

Err:1 http://deb.debian.org/debian bookworm InRelease
  Temporary failure resolving 'deb.debian.org'

First, test container network connectivity by pinging an external IP and checking DNS resolution:

docker run --rm alpine ping -c 3 8.8.8.8
docker run --rm alpine nslookup google.com

If ping succeeds but DNS fails, Docker’s embedded DNS resolver may have issues. In this case, configure Docker to use a specific DNS server by editing /etc/docker/daemon.json:

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

Then, restart Docker to apply the DNS configuration:

sudo systemctl restart docker.service

Network Bridge IP Conflicts

Docker creates bridge networks that may conflict with your local network subnets. First, check existing Docker networks:

docker network ls
ip addr show | grep "br-"

If Docker bridge networks overlap with your LAN subnet (commonly 172.17.0.0/16 or 172.18.0.0/16), then configure a different default address pool in /etc/docker/daemon.json:

{
  "default-address-pools": [
    {"base": "10.200.0.0/16", "size": 24}
  ]
}

Finally, restart Docker and prune unused networks to apply the new address pool:

sudo systemctl restart docker.service
docker network prune

Reset Docker Installation

If Docker behaves unexpectedly after a failed installation or upgrade, a clean reset of the Docker data directory often resolves persistent issues.

The following commands remove all Docker images, containers, volumes, and networks. Back up any important container data before proceeding.

First, stop Docker before removing the data:

sudo systemctl stop docker.service docker.socket
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
sudo systemctl start docker.service

Docker recreates the directory structure on startup.

Afterward, verify Docker is running correctly after the reset:

docker run --rm hello-world

Docker Rootless Mode Alternative

Rootless mode runs the Docker daemon and containers without root privileges, eliminating the security risks of the docker group. This approach provides true privilege isolation because even if an attacker compromises a container, they cannot gain root access to the host system.

Prerequisites for Rootless Mode

First, install the uidmap package and verify your user has subordinate UID/GID ranges configured:

sudo apt install uidmap

Then, verify your user has at least 65,536 subordinate UIDs and GIDs allocated:

grep "^$(whoami):" /etc/subuid /etc/subgid

Expected output shows allocated ranges:

/etc/subuid:username:100000:65536
/etc/subgid:username:100000:65536

Install Rootless Docker

If the system-wide Docker daemon is running, consider disabling it before setting up rootless mode:

sudo systemctl disable --now docker.service docker.socket

Next, install the rootless extras package:

sudo apt install docker-ce-rootless-extras

Then, run the rootless setup script as your non-root user:

dockerd-rootless-setuptool.sh install

Subsequently, add the environment variable to your shell configuration to use rootless Docker by default:

echo 'export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock' >> ~/.bashrc
source ~/.bashrc

Finally, verify rootless mode is active by checking for the “rootless” security option:

docker info | grep -i rootless

Expected output confirms rootless operation:

 rootless

Rootless mode has limitations: it cannot bind to privileged ports below 1024 without additional configuration, overlay network performance may be reduced, and some storage drivers are not available. For most development and testing workloads, these limitations are acceptable trade-offs for improved security.

Upgrade Docker CE

Docker packages from the official repository receive automatic updates through APT. However, to manually upgrade to the latest version:

sudo apt update
sudo apt upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Then, verify the new version after upgrading:

docker --version

Uninstall Docker CE

To completely remove Docker CE from your Debian system, you must uninstall the packages, remove data directories, and clean up repository configuration.

Remove Docker Packages

First, uninstall all Docker-related packages and clean up orphaned dependencies:

sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
sudo apt autoremove

The apt autoremove command cleans up packages that were automatically installed as dependencies but are no longer required after removing Docker.

Remove Docker Data

Next, delete all images, containers, volumes, and configuration data. This step is optional if you plan to reinstall Docker and want to preserve your existing containers and images.

The following commands permanently delete all Docker images, containers, volumes, and networks. Back up any important data before proceeding.

sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

Remove Repository Configuration

Finally, remove the Docker repository configuration. The cleanup commands depend on which installation method you used. For manual repository configuration:

sudo rm -f /etc/apt/sources.list.d/docker.sources
sudo rm -f /etc/apt/keyrings/docker.asc
sudo rm -f /etc/docker/daemon.json

If you installed Docker using extrepo, disable the repository with the following command. This adds an Enabled: no directive to the repository file rather than deleting it, allowing easy re-enablement later:

sudo extrepo disable docker-ce
sudo rm -f /etc/docker/daemon.json

To completely remove the extrepo configuration file instead of just disabling it:

sudo rm -f /etc/apt/sources.list.d/extrepo_docker-ce.sources
sudo rm -f /etc/docker/daemon.json

After removing the repository files, refresh the package cache to prevent stale repository information:

sudo apt update

Verify Docker Removal

Confirm Docker has been completely removed by checking package availability:

apt-cache policy docker-ce

Expected output confirms the package is no longer available:

N: Unable to locate package docker-ce

This output confirms the Docker repository has been removed and the package is no longer indexed by APT.

Conclusion

You now have Docker CE running on Debian with automatic repository updates, non-root user access through the docker group, log rotation to prevent disk exhaustion, and systemd service management. For security-sensitive environments, rootless mode provides true privilege isolation without granting users root-equivalent access. Build custom images with Dockerfiles, orchestrate multi-container applications with Docker Compose, or deploy containerized web services behind SSL certificates using Nginx with Let’s Encrypt on Debian or Apache with Let’s Encrypt on Debian. Harden your container host with UFW firewall rules on Debian, protect exposed services with Fail2ban intrusion prevention on Debian, and secure remote access with SSH configuration on Debian. For multi-user server environments, configure sudo access on Debian to control which administrators can manage the Docker daemon and deploy containers.

Leave a Comment