How to Install Docker on Ubuntu 25.10 (Step-by-Step)

Install Docker on Ubuntu 25.10 from Docker’s signed APT repository, enable Compose v2, run a safe container test, and fix common VPS errors fast.
A polished 3D server rack with glowing container blocks and a subtle orange Ubuntu accent on a midnight-blue background.

Install Docker on Ubuntu 25.10 from Docker’s signed APT repository and finish with Compose v2, non-root CLI access, and a working container. A fresh VPS takes about ten minutes, and the test service remains private to the server.

Prerequisites

  • A 64-bit Ubuntu 25.10 (Questing) VPS with at least 2 GB of RAM and 10 GB of free disk space.
  • SSH access as root, or a regular account with working sudo privileges.
  • Outbound HTTPS access to Docker’s package repository and Docker Hub.
  • No domain is needed for installation or the local test. You need a domain later if a public web application will use HTTPS.
  • A VPSLake Linux VPS if you need a root-access Ubuntu server for Docker workloads.

These commands use sudo for a normal SSH account. If you are logged in as root, omit sudo. Ubuntu uses APT and UFW; do not substitute DNF or firewalld commands from an Enterprise Linux guide.

Step 1: Confirm Ubuntu 25.10 and update the VPS

Checking the release and architecture first prevents you from configuring the Docker source for the wrong Ubuntu suite.

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

The output should identify Ubuntu 25.10, use the questing codename, and normally report amd64 on a VPS:

PRETTY_NAME="Ubuntu 25.10"
VERSION_ID="25.10"
VERSION_CODENAME=questing
UBUNTU_CODENAME=questing
amd64

The minor package updates will vary. Resolve any DNS, mirror, or interrupted-package error before changing the Docker repositories.

Step 2: Remove packages that conflict with Docker Engine

Ubuntu’s docker.io package, its Compose package, and separately installed runtimes can conflict with the versions bundled by Docker Engine.

On a fresh VPS, remove possible conflicts:

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

APT may say that one or more packages are not installed. That is harmless. This command does not remove images, containers, volumes, or networks already stored under /var/lib/docker/, so inspect existing workloads before changing an active Docker host.

Step 3: Add Docker’s signed Questing 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, store Docker’s key in APT’s keyring directory, and create a deb822 source file. The command reads Ubuntu’s codename instead of hard-coding a different release:

sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update

Confirm that APT sees a Docker Engine candidate from the questing repository:

apt-cache policy docker-ce

The candidate should reference download.docker.com and an Ubuntu 25.10/Questing package build. Docker’s Ubuntu installation documentation describes this repository format and package set.

Step 4: Install Docker Engine and Compose v2

Installing the daemon and plugins together keeps the client, runtime, image builder, and Compose integration aligned.

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:

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

Successful output includes an active, enabled service and version strings. Docker’s patch numbers change as new builds are published:

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

Step 5: Run Docker’s installation test

The official 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 this confirmation:

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

The container exits after printing its message. --rm removes the stopped container record, while the small 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 SSH account that should manage containers. Replace YOUR_LINUX_USER with that account’s login name:

sudo groupadd --force docker
sudo usermod -aG docker YOUR_LINUX_USER

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

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 a temporary current-shell refresh if reconnecting is inconvenient.

Step 7: Test container networking on loopback

A disposable NGINX container confirms that Docker can publish a port while binding only to the VPS itself, so you do not need a public firewall rule or DNS record.

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

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

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

Remove the disposable test after checking it:

docker stop ubuntu2510-docker-check
docker rm ubuntu2510-docker-check

Verify Docker on Ubuntu 25.10

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

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}}'

The result should contain active, enabled, Docker 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 published ports and their interaction 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 uses a suite other than questing. Check the release, source, and candidate:

grep -E '^(VERSION_ID|VERSION_CODENAME|UBUNTU_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: questing, and the policy output should show a candidate from download.docker.com. Recreate Step 3 if the file is missing or points to another release.

NO_PUBKEY or The repository ... is not signed

APT cannot read the key associated with the Docker source. Download the key again and restore its readable permission before refreshing package metadata:

sudo curl -fsSL https://download.docker.com/linux/ubuntu/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 source as trusted; APT’s signature validation is what protects the package metadata.

permission denied while trying to connect to the Docker daemon socket

The current SSH session was opened before the account joined the docker group, or the group command targeted another user. Reconnect, run id -nG, and retry. sudo docker info is only a temporary diagnostic while you correct the account setup.

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

The image may still be downloading, the container may have exited, or another process may own port 18085. Inspect the container and local listener:

docker ps -a --filter name=ubuntu2510-docker-check
docker logs ubuntu2510-docker-check
sudo ss -ltnp 'sport = :18085'

If the port is occupied, remove the failed test and repeat it with --publish 127.0.0.1:28085:80, then request http://127.0.0.1:28085. A loopback-only binding needs no public UFW rule.

Hardening

  • Keep Docker’s API on its Unix socket. Never expose an unauthenticated Docker API on TCP port 2375; remote administration needs deliberate TLS configuration and narrow source-IP rules.
  • Treat membership in the docker group as administrative access. Use Docker rootless mode when the workload needs a stronger privilege boundary.
  • Keep internal services on 127.0.0.1 until they sit behind a TLS reverse proxy. If an application must be public, allow only SSH, HTTP, and HTTPS in UFW, and review Docker’s DOCKER-USER chain because published container ports can bypass ordinary UFW filtering. The VPSLake UFW firewall generator can help draft a starting ruleset.
  • Monitor /var/lib/docker and container logs. Image layers and the default JSON logging driver can consume disk space even when few containers are running.

FAQ

Why does the repository use questing?

Ubuntu 25.10’s codename is Questing, and Docker publishes Ubuntu 25.10 package builds under that suite. The deb822 source in Step 3 reads the codename from the operating system so APT selects matching repository metadata.

Do I need Docker Desktop on an Ubuntu VPS?

No. Docker Engine is the headless daemon and CLI intended for server workloads. Docker Desktop is a separate desktop application and is not needed for containers managed over SSH.

Do I need to open port 18085 in UFW?

No. The NGINX test binds to 127.0.0.1, so it accepts connections only from the VPS itself. When you later publish a real application, expose only its required ports and review Docker’s firewall behavior before relying on UFW rules alone.

Where does Docker store images and containers?

Docker normally stores its data under /var/lib/docker, with runtime data under /var/lib/containerd. Leave enough space on that filesystem for image layers, writable container data, and logs, and inspect volumes before pruning anything.

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

MT5 on Mac: Run EAs 24/7 From Your Mac

Next Article

Best CPU for Minecraft Server: Single-Core Speed Explained

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 ✨