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.
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
- Linux VPS Performance Tuning: sysctl & swap 2026
- Systemd Service Hardening: Sandbox a Unit (2026)
- Fail2ban on Ubuntu VPS: Stop SSH Brute Force 2026
- UFW Firewall Rules for a Public VPS: 2026 Setup
- How to Harden SSH on an Ubuntu VPS (2026 Guide)
- Automated Backups with Rsync and Cron on Linux 2026
- TLS Certificates with Certbot on an Ubuntu VPS 2026
- Harden Nginx on Ubuntu: Headers, TLS & Limits 2026
- Automatic Security Updates on Ubuntu: 2026 Setup
- Logrotate for Nginx and App Logs on a Linux VPS
- Systemd Timers: Replace Cron Jobs on a Linux VPS
- Manage Linux Users and sudo Permissions on a VPS
- Linux VPS Disk and Inode Cleanup: du, find, lsof
- journald Logs: Retention, Size Limits and Queries
- How to Install Docker on a Linux VPS