How to Install Docker on a Linux VPS

A stock Ubuntu install ships an ancient Docker package under a different name entirely — docker.io — if it ships one at all, and that package trails months or years behind what Docker actually maintains. The reliable path on a VPS is Docker's own apt repository, which tracks Docker Engine releases directly and gets you the current version, the Compose plugin, and the Buildx plugin in one coherent install. This walkthrough sets that up from a clean Ubuntu server, end to end.

Quick Verdict
Skip apt install docker.io and the convenience script. Add Docker's official GPG key and apt repository, then install docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, and docker-compose-plugin together. Verify with docker run hello-world, then add your user to the docker group so you stop typing sudo before every command. The steps below apply unchanged across Ubuntu 22.04, 24.04, and 26.04 LTS.

Why the Apt Repository, Not the Default Package

Ubuntu's own repositories carry Docker under the name docker.io, packaged and versioned on Ubuntu's release cadence rather than Docker's. It works, but it lags, and it does not include the Compose v2 plugin or Buildx by default — both of which most modern Docker workflows assume are present. Docker also publishes a get-docker.sh convenience script, but that script is meant for quick disposable environments, not a server you intend to run for years and patch methodically through your normal apt upgrade cycle.

Adding Docker's own apt repository gives you the best of both: current Docker Engine releases, and updates that flow through the same apt update && apt upgrade you already run on the rest of the box. It is the method Docker's own documentation recommends for Ubuntu, and it is what the rest of this guide sets up.


Step 1: Remove Conflicting Packages and Prep Apt

If an old Docker-adjacent package is already on the box, clear it first so the new install has nothing to collide with:

1sudo apt-get remove docker docker-engine docker.io containerd runc

It is normal for this command to report that some or all of those packages are not installed — that is fine. Next, refresh the package index and install the two prerequisites the repository setup needs: ca-certificates for HTTPS verification and curl to fetch the signing key.

1sudo apt-get update
2sudo apt-get install ca-certificates curl

Step 2: Add Docker's Official GPG Key

Docker signs its repository, and apt needs the corresponding public key before it will trust packages from it. Create the keyring directory and download the key into it:

1sudo install -m 0755 -d /etc/apt/keyrings
2sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
3sudo chmod a+r /etc/apt/keyrings/docker.asc

install -m 0755 -d creates the directory with the right permissions in one step, and chmod a+r on the key file makes sure apt — running as a non-root helper process during index refreshes — can actually read it. Skipping either step is the usual cause of a confusing "NO_PUBKEY" error later.


Step 3: Add the Repository

With the key in place, register the repository itself. This one-liner reads your CPU architecture and your Ubuntu release codename automatically, so the same command works unmodified whether the box is running 22.04 ("Jammy"), 24.04 ("Noble"), or the newer 26.04 ("Resolute Raccoon") LTS:

1echo \
2  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
3  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
4  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

The signed-by= flag scopes trust to exactly this key for exactly this repository, rather than adding it to apt's global trusted-key ring — a tighter, more auditable pattern than the old apt-key add approach it replaces. Refresh the index so apt picks up the new source:

1sudo apt-get update

If this step errors, double-check the key file's permissions from Step 2 before anything else — that is the most common failure point.


Step 4: Install Docker Engine

With the repository trusted and indexed, install the full set of packages in one command:

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

Each package has a distinct job. docker-ce is the Docker Engine daemon itself. docker-ce-cli is the docker command you type. containerd.io is the lower-level container runtime Docker Engine delegates to. docker-buildx-plugin adds the modern docker buildx build image-building backend. docker-compose-plugin adds docker compose (no hyphen) as a first-class subcommand, replacing the old standalone docker-compose binary. Installing all five together means every part of a normal Docker workflow — build, run, and compose — works immediately without a second install pass.

Apt starts and enables the docker service automatically as part of the install on a systemd-based Ubuntu system, so there is no separate systemctl enable step required here.


Step 5: Verify the Install

Confirm the daemon is actually running and reachable:

1sudo systemctl status docker

Then run Docker's standard smoke test, a tiny image that prints a confirmation message and exits:

1sudo docker run hello-world

If it downloads the image, runs it, and prints a "Hello from Docker!" message, the engine, the CLI, and the container runtime are all wired correctly. Check the installed version at any point with:

1docker --version
2docker compose version

Step 6: Run Docker Without sudo

By default, only root and members of the docker group can talk to the Docker daemon's socket, which means every docker command needs sudo in front of it until you fix that. Add your own user to the group:

1sudo usermod -aG docker $USER

The -aG flag matters — -a appends the group rather than replacing your existing group memberships, a mistake that quietly strips other access if you drop it. The new membership does not apply to your current shell session; log out and back in, or run:

1newgrp docker

to pick it up without a fresh login. Confirm it worked by running a Docker command with no sudo:

1docker ps

An empty table (no containers running yet) with no permission error means the group change took effect. Be aware of what you just granted: membership in the docker group is effectively root-equivalent, since a container can mount the host filesystem — treat it with the same caution as handing out sudo access.


Which Ubuntu Versions This Covers

The apt-repository method above is version-agnostic by design — the $VERSION_CODENAME substitution in Step 3 is what makes it work unchanged across releases. It's the same procedure Docker's install documentation describes for Ubuntu 22.04 LTS ("Jammy"), 24.04 LTS ("Noble"), and 26.04 LTS ("Resolute Raccoon"), so a fresh VPS running any of the three current LTS releases follows these exact steps without modification.


A Clean, Update-Friendly Docker Install

The apt-repository route takes a few more commands than apt install docker.io, but every one of them buys something real: a current Docker Engine release instead of a stale distro snapshot, the Compose and Buildx plugins bundled in from the start, and future updates that arrive through your normal apt upgrade routine rather than a manual reinstall. Once docker run hello-world succeeds and docker ps works without sudo, the VPS is ready for whatever you're actually deploying — a single container, a Compose stack, or a CI runner building images on demand.

References

Posts in this series