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.

bash
apt remove docker.io docker-doc docker-compose podman-docker containerd runc

On Ubuntu, remove the distribution's Compose package too:

bash
apt remove docker-compose-v2

Add Docker's repository

The commands are nearly identical for the two distributions, but the URL differs, so use the right block.

Ubuntu 24.04:

bash
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.list

Debian 12:

bash
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.list

That long last line fills in noble or bookworm for you, so you don't have to.

Install it

Same on both:

bash
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Check it:

bash
docker run --rm hello-world
docker compose version

You 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:

bash
docker run -d -p 127.0.0.1:8080:80 nginx

In a Compose file:

yaml
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):

bash
usermod -aG docker deploy

Be 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.list says ubuntu or debian to match your system, with the right codename, then apt update again.
  • NO_PUBKEY during apt update: the key file is missing or unreadable. Repeat the curl and chmod a+r steps.
  • Cannot connect to the Docker daemon: start it with systemctl start docker, and read journalctl -u docker to find out why it stopped.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.