Install Docker
Install Docker Engine and the Compose plugin from Docker's official apt repository on Ubuntu 24.04 or Debian 12, and keep ports private.
VPSNine servers are KVM, so Docker runs just as it would on a physical machine. We'll install Docker Engine and the Compose plugin from Docker's own apt repository, which is newer than the docker.io package your distribution ships. Then we'll keep your containers' ports off the public internet, which Docker doesn't do for you.
Clear out old packages
If anything Docker-related came from the distribution, remove it. On a fresh server this does nothing, and apt just skips what isn't there.
apt remove docker.io docker-doc docker-compose podman-docker containerd runcOn Ubuntu, remove the distribution's Compose package too:
apt remove docker-compose-v2Add Docker's repository
The commands are nearly identical for the two distributions, but the URL differs, so use the right block.
Ubuntu 24.04:
apt update
apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
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" > /etc/apt/sources.list.d/docker.listDebian 12:
apt update
apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.listThat long last line fills in noble or bookworm for you, so you don't have to.
Install it
Same on both:
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginCheck it:
docker run --rm hello-world
docker compose versionYou should get Hello from Docker! and a Compose version number. Docker starts at boot on its own; systemctl is-enabled docker says enabled.
Keep published ports private
Docker writes its own firewall rules, and a port published with -p 8080:80 is reachable from the whole internet even if ufw doesn't allow it. ufw status won't mention it either. People find this out the hard way, usually with an open database.
If a container only needs to be reached from the server itself (say, behind nginx), bind it to localhost:
docker run -d -p 127.0.0.1:8080:80 nginxIn a Compose file:
services:
app:
image: nginx
ports:
- "127.0.0.1:8080:80"Then put a reverse proxy in front. Serve a site with nginx and HTTPS covers the HTTPS side.
Docker without root
To let a normal user run docker, add them to the docker group and have them log in again (replace deploy):
usermod -aG docker deployBe clear about what that means: anyone in the docker group can get root on the server. Only add people you'd give root to anyway.
When it goes wrong
Unable to locate package docker-ce: the repository line is off. Check that/etc/apt/sources.list.d/docker.listsaysubuntuordebianto match your system, with the right codename, thenapt updateagain.NO_PUBKEYduringapt update: the key file is missing or unreadable. Repeat thecurlandchmod a+rsteps.Cannot connect to the Docker daemon: start it withsystemctl start docker, and readjournalctl -u dockerto find out why it stopped.