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

Install Docker on Debian 13 with Docker’s signed APT repository, Compose v2, non-root access, a safe container test, and VPS fixes on a fresh VPS.
A polished 3D server rack with glowing container blocks and a subtle orange Debian accent on a midnight-blue background.

Install Docker on Debian 13 with Docker Engine and Compose v2 from Docker’s signed APT repository. In about ten minutes, you can run a verified container and confirm that Docker starts with the server.

Debian 13 is Trixie, so the repository must use the trixie suite. The local web test below binds to loopback only, keeping an unfinished service off the public network.

Prerequisites

  • A 64-bit Debian 13 (Trixie) 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 for package and image downloads.
  • No domain is needed for installation or the local test. You will need a domain later if you put a public application behind HTTPS.
  • A VPSLake Linux VPS if you need a Debian server with root access for containers.

The commands assume a sudo-enabled account. If you are logged in as root, remove sudo. Run the non-root setup as the account that should administer Docker.

Step 1: Confirm Debian 13 and update the host

Checking the release and architecture first prevents you from adding a repository for the wrong Debian suite.

~~~bash 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 say Trixie and a typical VPS should report amd64:

~~~text PRETTY_NAME=”Debian GNU/Linux 13 (trixie)” VERSION_ID=”13″ VERSION_CODENAME=trixie amd64 ~~~

Minor release details and upgrade counts vary. Fix any mirror, DNS, or interrupted-package error before installing Docker.

Step 2: Remove packages that conflict with Docker Engine

Debian’s docker.io package and separately installed runtimes can conflict with the versions bundled by Docker Engine.

On a fresh VPS, remove possible conflicting packages:

~~~bash 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. Removing packages does not automatically erase images, containers, volumes, or networks under /var/lib/docker/, so inspect that directory before changing an existing Docker host.

Step 3: Add Docker’s signed Trixie repository

Docker’s repository supplies Engine, the CLI, containerd, Buildx, and the maintained Compose v2 plugin as one package set.

Install the certificate and download tools, save Docker’s key in APT’s keyring directory, and create a deb822 source file for Trixie:

~~~bash 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: trixie Components: stable Architectures: $(dpkg –print-architecture) Signed-By: /etc/apt/keyrings/docker.asc EOF sudo apt update ~~~

Confirm that APT sees an Engine candidate from Docker’s repository:

~~~bash apt-cache policy docker-ce ~~~

The candidate should come from download.docker.com and use a Debian 13/Trixie package build. Docker’s Debian installation documentation lists Trixie as supported and documents this repository method.

Step 4: Install Engine, Buildx, and Compose v2

These packages install the daemon, command-line client, runtime, image builder, and docker compose integration.

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

Check the service and both Docker command-line components:

~~~bash 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. Docker’s patch versions change as updates are published:

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

Step 5: Run the official smoke test

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

~~~bash sudo docker run –rm hello-world ~~~

Near the end of the output, look for this confirmation:

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

The container exits after printing its message. The –rm option removes its stopped container record, although the downloaded image remains cached.

Step 6: Give one account non-root Docker access

Docker’s Unix socket is root-owned by default. The docker group avoids repeated sudo, but membership grants root-equivalent control over the VPS.

Run this as the normal account that should manage containers:

~~~bash sudo groupadd –force docker sudo usermod -aG docker “$USER” ~~~

Log out of SSH completely and reconnect so the new group membership is loaded. Then test access without sudo:

~~~bash id -nG docker info –format ‘Server {{.ServerVersion}}’ ~~~

The group list should include docker, and the second command should print the Engine version. Use newgrp docker for the current shell if reconnecting is not convenient.

Step 7: Test container networking on loopback

A disposable NGINX container confirms that Docker can publish a port without making the test service reachable from the internet.

~~~bash docker run -d –name debian13-docker-check –publish 127.0.0.1:18081:80 nginx:alpine docker ps –filter name=debian13-docker-check –format ‘table {{.Names}}\t{{.Status}}\t{{.Ports}}’ curl –head –max-time 10 http://127.0.0.1:18081 ~~~

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

~~~text NAMES STATUS PORTS debian13-docker-check Up … 127.0.0.1:18081->80/tcp HTTP/1.1 200 OK ~~~

Because the host binding is loopback-only, you do not need to open port 18081 in UFW. Remove the test after checking it:

~~~bash docker stop debian13-docker-check docker rm debian13-docker-check ~~~

Verify Docker on Debian 13

Run this final check to confirm boot startup, daemon communication, Compose, and local container storage:

~~~bash 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, Docker client/server versions, a Compose v2 version, and commonly overlay2 as the storage driver:

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

For published ports and the way Docker interacts with host filtering, read Docker’s 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 names a suite other than Trixie. Check the release and source, then refresh the package lists:

~~~bash 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 source must show Suites: trixie, and the policy output should show a candidate from download.docker.com. Recreate Step 3 if the file is absent or points to another release.

NO_PUBKEY or an APT signature error

APT cannot read the key associated with the Docker source. Check the key’s permissions and download it again before retrying the update:

~~~bash 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 ~~~

Do not bypass signature checks or mark the repository as trusted; the signature verifies that the package metadata came from the expected source.

Permission denied while trying to connect to the Docker daemon socket

The SSH session started before the account joined the docker group, or the group command targeted a different user. Reconnect and run id -nG, or use newgrp docker; sudo docker info is a temporary workaround.

curl: (7) Failed to connect to 127.0.0.1 port 18081

The test image may still be downloading, the container may have stopped, or another process may already own the port. Inspect the container and listener:

~~~bash docker ps -a –filter name=debian13-docker-check docker logs debian13-docker-check sudo ss -ltnp ‘sport = :18081’ ~~~

If the port is occupied, remove the failed test and repeat it with –publish 127.0.0.1:28081:80, then curl http://127.0.0.1:28081. A loopback binding needs no public firewall rule.

Hardening

  • Keep the Docker API on its Unix socket. Never expose an unauthenticated TCP API on port 2375; remote administration requires deliberate TLS configuration and narrow source-IP rules.
  • Treat membership in the docker group as administrative access. Use rootless Docker if you need a stronger privilege boundary.
  • Publish internal services on 127.0.0.1 and put a TLS reverse proxy in front of them. If an application must be public, open only its required ports and review Docker’s DOCKER-USER chain behavior; published container ports can bypass ordinary UFW filtering. A VPSLake UFW firewall generator can help draft a starting ruleset.
  • Watch /var/lib/docker and container logs. Image layers and default JSON logs can consume disk space even when the host has few running containers.

FAQ

Does Docker support Debian 13?

Yes. Docker’s current Debian instructions list Debian Trixie 13 as a supported release and provide packages through the official Debian APT repository. Use the trixie suite shown in this guide rather than substituting bookworm.

Do I need Docker Desktop on a Debian VPS?

No. Docker Engine is the server-side runtime and is the appropriate choice for a headless VPS. Docker Desktop is a separate desktop application intended for local development environments.

Why not install Debian’s docker.io package?

Debian’s package can be useful when you want distribution-managed versions, but it may not match Docker’s current Engine, Buildx, and Compose release cadence. Docker’s signed repository keeps those components aligned and is the method used here.

How do I expose a container to the public internet safely?

Publish only the ports the application needs, allow those ports in your firewall, and use a domain with TLS for a web service. Review Docker’s packet-filtering behavior first because a published port can be reachable outside the normal UFW rule path.

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

Remmina Remote Desktop: Connect Linux to Windows RDP

Next Article

How to Install Docker on Rocky Linux 10 (Step-by-Step)

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 ✨