Virtualization

Install Docker on an Ubuntu VPS

The first thing most people get wrong when installing Docker on an Ubuntu VPS is reaching for the distro's own docker.io package. It works, but it lags behind the official builds and you will eventually fight a version mismatch with Docker Compose. This guide walks through the proper install on Ubuntu 24.04 LTS: the official apt repository, Docker Engine, the Compose v2 plugin, and the checks you run before trusting it with a real workload. Everything here is copy-paste runnable on a fresh VPS with root or sudo access.

Prerequisites

  • An Ubuntu 24.04 LTS VPS. The same steps apply to Ubuntu 22.04, but 24.04 is the current LTS.
  • Root access or a user with sudo. You will run apt and systemctl, so non-root needs passwordless sudo configured.
  • At least 1 GB of RAM and 2 GB of free disk. Docker itself is small, but images and build cache grow fast.
  • No conflicting packages already installed. If a Docker package exists, this guide removes it cleanly first.

If you do not have a machine yet, you can rent a Linux VPS with full root access and a dedicated IPv4 from the Vietnam range. The install steps are identical regardless of provider.

Why the official repository instead of the Ubuntu package

Ubuntu ships a Docker package named docker.io. It is a snapshot, maintained by the Ubuntu archive team, and it trails the upstream release by months. The official Docker apt repository gives you the current engine, current containerd, and the Compose plugin that matches. For a production server, staying current matters because Docker releases patch container runtime and networking bugs regularly.

There is a second reason. The upstream repo installs docker-compose-plugin, the v2 plugin invoked as docker compose. The old docker-compose binary you see in older tutorials is a separate Python tool. It still exists, but it is no longer the recommended path. If a tutorial from 2022 tells you to pip install docker-compose, treat it as outdated.

Step 1 - Removing old packages and adding the Docker repository

Start clean. If a distribution or third-party Docker package is present, remove it. In most cases there is nothing to remove, but the command is safe on a fresh VPS.

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg; done

Now install the packages needed to work with apt over HTTPS. The key one is ca-certificates and curl for fetching the repository key.

sudo apt-get update
sudo apt-get install -y ca-certificates curl

Create the keyring directory and add Docker's official GPG key. This is what lets apt trust the packages it downloads from the Docker repo.

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

Add the repository itself. The codename matters: Ubuntu 24.04 is noble, and the command below substitutes it automatically.

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

Run apt update so the new repository is visible. If curl failed silently, this is where you will notice it.

sudo apt-get update

Verify: check that the Docker repo shows up in the package cache.

apt-cache policy docker-ce

Expected output shows Candidate with a version like 5:27.x.x, not the distro version. If it prints nothing or shows the Ubuntu archive version, the repo line is wrong.

Step 2 - Installing Docker Engine and the Compose plugin

With the repo in place, install everything in one command. Do not install docker-ce alone and then hunt for docker-compose separately. The plugin comes from the same repository.

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

Here is what each package does:

  • docker-ce, the daemon and the docker CLI.
  • docker-ce-cli, the client binaries.
  • containerd.io, the container runtime that Docker uses under the hood.
  • docker-buildx-plugin, the modern BuildKit builder used by docker build.
  • docker-compose-plugin, the v2 compose binary behind docker compose.

Docker is not started automatically on every install. Enable it and start it now.

sudo systemctl enable --now docker

Verify: confirm the daemon is actually running.

systemctl status docker

Expected output includes active (running). A common failure here is a stale cgroup config, which shows up as failed instead. That is covered in troubleshooting.

Check the installed version and that the Compose plugin is registered as a subcommand.

docker --version
docker compose version

Both print version strings. If docker compose fails with "unknown command", the plugin package did not install, which almost always means the repo was not added correctly.

Step 3 - Running Docker as a non-root user

By default the docker CLI needs root because it talks to the daemon socket owned by root. Adding your user to the docker group avoids typing sudo before every command.

sudo usermod -aG docker $USER

Log out and back in for the group change to take effect. On a pure SSH session, exit and reconnect. Then run a quick test without sudo.

docker run hello-world

Expected output is a short message ending with "This message shows that your installation appears to be working correctly."

将用户加入 docker 组,可免去每条命令前的 sudo。

Adding your user to the docker group removes the need for sudo on every command.

The group approach is the standard trade-off: it is convenient, but anyone in the group effectively has root on the host because they can mount the filesystem into a container. Only add users you trust to have full root. On a single-admin VPS this is fine, on a shared box reconsider it.

Step 4 - Running a real container and testing the network

hello-world proves the daemon works, but it does not exercise the network stack or port mapping. Run a proper web server to make sure containers can bind ports and the host firewall is not silently blocking it.

docker run -d --name nginx-test -p 8080:80 nginx:latest

This pulls the nginx image, starts a container named nginx-test, and maps host port 8080 to the container port 80. The -d flag detaches it to run in the background.

Verify: hit the container over the loopback interface first, then over the host's IP.

curl -I http://127.0.0.1:8080

Expected status line is HTTP/1.1 200 OK. If you are on a VPS behind a firewall like ufw, you need to allow the port before it is reachable from outside.

sudo ufw allow 8080/tcp

Do not skip this check. Every Docker-on-VPS guide lands here eventually and the "container is running but I cannot reach it" problem is almost always ufw, not Docker.

Confirm the container is healthy and then remove it, since it was only a test.

docker ps
docker rm -f nginx-test

docker ps shows the running container with its status and port mapping. The rm -f removes it even while running.

Troubleshooting

apt update fails with "the repository does not have a Release file". This means the codename substitution failed and the repo line points at a nonexistent suite. Check the contents of the file and fix the codename manually.

cat /etc/apt/sources.list.d/docker.list

The line must contain noble for Ubuntu 24.04, not a variable or a different codename. Edit the file and replace the wrong codename, then run sudo apt-get update again.

systemctl status docker shows failed. Look at the daemon log for the real error.

journalctl -u docker --no-pager | tail -50

The most common cause on a VPS is a warning about iptables being unavailable or legacy vs nftables mismatch. The practical fix is to restart the service after a reboot, but if it persists, the containerd config may need attention. In most cases a full restart clears it.

sudo systemctl restart docker

docker compose not found. The plugin is not installed, which means the repository line is pointing at the wrong suite or the package install was partial. Re-run the install command and confirm docker compose version works. Do not fall back to installing docker-compose with pip, that binary is deprecated.

Outbound network inside containers fails. DNS resolution or internet access from inside a container can break if the bridge network is misconfigured. Test it directly.

docker run --rm alpine ping -c 2 8.8.8.8

If ping to an IP works but DNS does not, the issue is /etc/resolv.conf handling. Restarting docker usually recreates the bridge cleanly. On a fresh Ubuntu 24.04 VPS this is rare, but it happens after major kernel updates.

FAQ

Do I need to install Docker Compose separately?

No. The docker-compose-plugin package installs the v2 plugin, and you invoke it as docker compose with a space. The separate docker-compose binary is the old v1 tool and is not needed on Ubuntu 24.04.

Is the docker.io package from Ubuntu the same as Docker CE?

No. docker.io is a distro snapshot that lags upstream. Docker CE from the official repository is the current engine with the current containerd and Compose plugin.

Is it safe to run Docker on a 1 GB RAM VPS?

Yes, for light workloads. The daemon itself uses little memory, but containers and build processes can exceed 1 GB quickly. A WordPress VPS container with MySQL and PHP can fit in 2 GB comfortably. Keep an eye on memory with docker stats.

Should I enable the Docker daemon on boot?

Yes. The systemctl enable --now docker command in this guide does both. Without the enable flag the daemon stops after a reboot.

What does adding a user to the docker group do?

It grants that user access to the Docker socket without sudo. Because the socket allows mounting host filesystems into containers, this is effectively root access. Add only users who need to run docker commands.

Related articles

Ubuntu VPS 安装 Docker 要点

本文介绍了在 Ubuntu 24.04 VPS 上安装 Docker 的完整流程:先移除旧包,添加官方 apt 仓库,再安装 docker-ce 和 Compose v2 插件。安装后需启用 systemd 服务并验证版本。建议将当前用户加入 docker 组以省去 sudo,但需注意该组等同于 root 权限。遇到仓库错误时检查 codename 是否为 noble,容器无法访问时先开放防火墙端口。

Note: This guide is for general reference. Every system and infrastructure has its own specifics, so test each step in a safe environment and consult a qualified engineer before applying it in production.