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.
| Method | Complexity | Best For |
|---|---|---|
| extrepo (Recommended) | Simple | Quick setup, automatic GPG key management |
| Manual Repository | Moderate | Full 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 nginxexposes that port to the network. Docker is also only compatible withiptables-nftandiptables-legacy. Firewall rules created withnftdirectly are not supported. If you need to restrict Docker port access, add rules to theDOCKER-USERiptables 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 /:/hostand 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
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.