How to Install Docker on Debian 12 (Step-by-Step)

Install Docker on Debian 12 from Docker’s signed APT repository, enable Compose v2, test a container, and fix common VPS errors quickly on fresh VPS hosts.
A polished 3D server rack with glowing container blocks and a subtle deep-red Debian accent on a midnight-blue background.

Install Docker on Debian 12 using Docker Engine, Compose v2, and a non-root command workflow. In roughly ten minutes, you can pull an image, run a container, and confirm that the daemon will start after a reboot.

Debian 12 is Bookworm, so this guide uses Docker’s official Bookworm-compatible APT repository instead of Debian’s older docker.io package. The test binds only to localhost, which lets you validate networking without placing an unfinished service on the internet.

Prerequisites

  • A 64-bit Debian 12 (Bookworm) VPS with at least 2 GB of RAM and 10 GB of free disk space.
  • SSH access as root, or a normal Linux account with working sudo privileges.
  • Outbound HTTPS access to download.docker.com and Docker Hub so APT can download packages and Docker can pull images.
  • No domain is needed for the installation or local test. You need a domain later only if you put a public web application behind a TLS reverse proxy.
  • A VPSLake Linux VPS if you need a Debian server with root access for containers.

The commands below assume a sudo-enabled account. If you are logged in as root, remove sudo; for the non-root setup, replace $USER with the existing account that should manage Docker.

Step 1: Confirm Debian 12 and refresh APT

Checking the release first prevents you from adding a repository for another Debian codename or architecture.

grep -E '^(PRETTY_NAME|VERSION_ID|VERSION_CODENAME)=' /etc/os-release
dpkg --print-architecture
sudo apt update
sudo apt full-upgrade -y

The release should identify Bookworm and the architecture should normally be amd64 on a VPS:

PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
VERSION_ID="12"
VERSION_CODENAME=bookworm
amd64

The minor release and package counts will vary. Resolve any DNS, mirror, or interrupted-package error before continuing.

Step 2: Remove packages that conflict with Docker Engine

Debian’s docker.io package and separately installed container runtimes can conflict with the versions Docker ships in its repository.

On a fresh VPS, run:

sudo apt remove -y docker.io docker-compose docker-doc docker-buildx podman-docker containerd runc

APT may report that some packages are not installed. This command does not remove images, containers, volumes, or networks already stored under /var/lib/docker/; inspect existing workloads before changing a server that already runs containers.

Step 3: Add Docker’s signed Bookworm repository

The repository gives you Docker Engine, its CLI, containerd, Buildx, and the maintained Compose v2 plugin as one compatible package set.

Install the certificate and download tools, store Docker’s key in the dedicated APT keyring directory, then create a deb822 source file:

sudo apt install -y ca-certificates curl
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
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: bookworm
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update

Confirm APT can see Docker packages for Bookworm before installing them:

apt-cache policy docker-ce

The candidate should come from https://download.docker.com/linux/debian and include a Debian 12/Bookworm package build. Docker’s Debian installation guide documents this repository method and supported architectures.

Step 4: Install Docker Engine and Compose v2

This package set installs the daemon, CLI, container runtime, image builder, and the docker compose subcommand.

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

Check that systemd is running Docker and that the command-line tools can reach the daemon:

sudo systemctl is-active docker
sudo systemctl is-enabled docker
sudo docker version --format 'Client {{.Client.Version}} / Server {{.Server.Version}}'
sudo docker compose version

Expected output has an active, enabled service and version strings. Exact patch numbers change as Docker publishes releases:

active
enabled
Client 29.x.y / Server 29.x.y
Docker Compose version v2.x.y

Step 5: Run Docker’s built-in smoke test

The hello-world image checks the complete path from the CLI to the daemon, registry, image cache, container creation, and process startup.

sudo docker run --rm hello-world

Near the end, look for the following confirmation:

Hello from Docker!
Your installation appears to be working correctly.

The test container exits on its own, and --rm removes its stopped container record. Its small image remains cached until you remove it.

Step 6: Allow one account to use Docker without sudo

Docker’s Unix socket is root-owned by default. The docker group removes repeated sudo prompts, but membership is administrative access because a Docker user can effectively control the host.

Run this as the account that should operate containers:

sudo groupadd --force docker
sudo usermod -aG docker "$USER"

Sign out of SSH completely and reconnect, or activate the new group in the current shell with newgrp docker. Then check the account’s access:

id -nG
docker info --format 'Server {{.ServerVersion}}'

The group list should contain docker, and the second command should print the Engine version. Keep using sudo docker until the new group is loaded if you prefer not to start a child shell.

Step 7: Test container networking on loopback

A temporary NGINX container verifies port publishing while binding only to the VPS itself, so the test does not require a firewall rule or a public DNS record.

docker run -d --name debian12-docker-check --publish 127.0.0.1:18080:80 nginx:alpine
docker ps --filter name=debian12-docker-check --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
curl --head --max-time 10 http://127.0.0.1:18080

You should see a running container and an HTTP success response:

NAMES                  STATUS        PORTS
debian12-docker-check  Up ...        127.0.0.1:18080->80/tcp
HTTP/1.1 200 OK

Remove the disposable test when the response is confirmed:

docker stop debian12-docker-check
docker rm debian12-docker-check

Verify Docker on Debian 12

Use this final check to confirm startup, daemon access, Compose, and the local storage driver:

systemctl is-active docker
systemctl is-enabled docker
docker version --format 'Client {{.Client.Version}} / Server {{.Server.Version}}'
docker compose version
docker info --format 'Containers {{.Containers}} | Images {{.Images}} | Storage {{.Driver}}'

Successful output includes active, enabled, client/server versions, a Compose v2 version, and commonly overlay2 as the storage driver:

active
enabled
Client 29.x.y / Server 29.x.y
Docker Compose version v2.x.y
Containers 0 | Images 2 | Storage overlay2

For Docker’s interaction with published ports and host firewall rules, read the official packet-filtering and firewall guidance.

Troubleshooting

E: Package 'docker-ce' has no installation candidate

APT has not loaded Docker’s repository, or the source file uses a suite that does not match Debian 12. Check the release and source, then refresh the package lists:

grep -E '^(VERSION_ID|VERSION_CODENAME)=' /etc/os-release
grep -E '^(Types|URIs|Suites|Components|Architectures|Signed-By):' /etc/apt/sources.list.d/docker.sources
sudo apt update
apt-cache policy docker-ce

The suite must be bookworm, and the policy output should show a candidate from download.docker.com. Recreate Step 3 if the file is missing or has a different suite.

NO_PUBKEY or a signature verification error

APT cannot read the key used by the Docker source. Check that /etc/apt/keyrings/docker.asc exists and is readable, then run the key download and chmod commands from Step 3 again before retrying sudo apt update.

permission denied while trying to connect to the Docker daemon socket

Your current SSH process was created before the account joined the docker group, or the group command targeted another username. Reconnect and run id -nG; newgrp docker is a temporary current-shell fix. You can also use sudo docker info while correcting the account setup.

WARNING: Error loading config file ... permission denied

Running Docker with sudo can create a root-owned ~/.docker directory in your user’s home. If you do not need settings stored there, remove that directory; otherwise repair its ownership and permissions:

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

bind: address already in use during the NGINX test

Another local process owns port 18080. Find the listener and choose another loopback port, such as 28080:

sudo ss -ltnp 'sport = :18080'
docker run -d --name debian12-docker-check --publish 127.0.0.1:28080:80 nginx:alpine
curl --head --max-time 10 http://127.0.0.1:28080

Stop and remove the test container afterward as shown in Step 7.

Hardening

  • Do not publish Docker’s API on TCP port 2375. Keep administration on the Unix socket unless you have deliberately configured TLS and restricted the source IPs.
  • Bind internal applications to 127.0.0.1 and place a TLS reverse proxy in front of them. When a service must be public, allow only its required ports and review Docker’s DOCKER-USER chain guidance; published container ports can bypass ordinary ufw filtering. A VPSLake UFW firewall generator can help create a starting ruleset.
  • Treat the docker group as root-equivalent access. For a stronger privilege boundary, evaluate Docker rootless mode before adding users to the group.
  • Monitor /var/lib/docker and container logs. Image layers and default JSON logs can consume disk even when the host itself looks lightly used.

FAQ

Is Docker Engine available for Debian 12?

Yes. Docker’s current Debian instructions list Bookworm 12 as a supported release and provide packages through Docker’s Debian repository. The repository is preferable here because it supplies Docker Engine and the maintained Compose plugin together.

Do I need docker-compose on Debian 12?

No. The old docker-compose package is a legacy standalone command. Install docker-compose-plugin and use docker compose with a space; this is the current Compose v2 interface.

Should I open port 18080 in UFW?

No. The example publishes 127.0.0.1:18080, so it accepts connections only from the VPS itself and needs no public firewall rule. If you later publish an application on 0.0.0.0, review Docker’s firewall behavior before assuming a normal UFW allow or deny rule protects that container.

Where does Docker store its images and containers?

The default Docker data root is /var/lib/docker, while containerd keeps runtime data under /var/lib/containerd. Make sure the filesystem has room before pulling large images, and do not prune volumes or images until you have identified which workloads still need them.

Samrat Ghosh
Written by

Samrat Ghosh

Founder & Infrastructure Engineer

Samrat Ghosh is the founder of VPSLake, where he builds and runs the remote desktop and VPS hosting infrastructure the company is built on. He writes hands-on guides about RDP, Windows Server, VPS management and secure remote access - the practical documentation he wishes had…

Previous Article

Cheap VPS for WordPress in 2026: RAM and Setup

Next Article

Remmina Remote Desktop: Connect Linux to Windows RDP

Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨