LinuxAugust 27, 2026 17 views

Install Docker on a Linux VPS (2026)

Install Docker on a Linux VPS (2026)

Prerequisites

Before starting, the following should be in place:

  • Key-based SSH access: SSH key guide
  • UFW firewall configured: UFW guide (also read the Docker and UFW section below before exposing any ports)
  • A non-root user with sudo privileges, or direct root access
  • OS: Debian 13 (Trixie) or Ubuntu 24.04 LTS

Step 1: Add the official Docker repository

Do not install the docker.io package shipped by Debian/Ubuntu: it lags behind the official releases. Use the Docker Inc. repository to get docker-ce, the actively maintained version.

On Debian 13

Source: docs.docker.com/engine/install/debian/

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg \
  -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update

On Ubuntu 24.04

Source: docs.docker.com/engine/install/ubuntu/

sudo apt update
sudo apt install -y ca-certificates curl
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

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update

Step 2: Install Docker Engine and Docker Compose

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

This command installs the following packages at once:

  • docker-ce: the Docker engine
  • docker-ce-cli: the command line interface
  • containerd.io: the container runtime
  • docker-buildx-plugin: the multi-platform build plugin
  • docker-compose-plugin: Docker Compose v2 (the docker compose command, without a hyphen)

Verify the installation:

docker --version
docker compose version

Important note about Docker Compose: the v2 plugin is invoked as docker compose (two words, no hyphen). The old standalone docker-compose binary (with a hyphen) is the v1 version, deprecated since July 2023 and not installed here. Source: docs.docker.com/compose/migrate/

Enable Docker at system startup:

sudo systemctl enable docker.service
sudo systemctl enable containerd.service

Source: docs.docker.com/engine/install/linux-postinstall/

Step 3: Set up non-root access

Add your user to the docker group

By default, Docker commands require sudo. To run them without sudo, add your user to the docker group:

sudo usermod -aG docker $USER
newgrp docker

The newgrp docker command applies the change in the current session without logging out. Source: docs.docker.com/engine/install/linux-postinstall/

Security warning about the docker group

Step 4: First test container

Verify that the installation works with the official hello-world image:

docker run hello-world

Docker downloads the image from Docker Hub if it is not present locally, starts a container, prints a confirmation message and stops. Output containing "Hello from Docker!" confirms that the installation is working.

Docker and UFW: the trap you need to know about

What actually happens

Starting a container with docker run -p 8080:80 nginx opens port 8080 on all network interfaces of the VPS, including the public IP, even if UFW does not allow that port. Source: docs.docker.com/engine/network/packet-filtering-firewalls/

Best practice: bind to 127.0.0.1

To expose a port locally only (reachable from the VPS but not from the Internet), bind it to the loopback interface:

# docker run command
docker run -p 127.0.0.1:8080:80 nginx

# In a compose.yml
ports:
  - "127.0.0.1:8080:80"

Port 8080 is then reachable only from the VPS itself (through an Nginx reverse proxy, for example), and not from the outside.

For ports that must stay public

Use the iptables DOCKER-USER chain to filter traffic before Docker processes it. Add a rule in /etc/ufw/after.rules or configure iptables directly. The official documentation details this approach: Restrict connections to the Docker host.

Practical recommendation

For a VPS hosting web services through Docker:

  • Bind all containers to 127.0.0.1 by default
  • Put an Nginx reverse proxy in front (ports 80 and 443 handled by Nginx, not by Docker directly)
  • Open only ports 80 and 443 in UFW (UFW guide)
  • Never expose database ports (3306, 5432, 6379) directly on the public IP

Container maintenance

Clean up unused resources

Docker accumulates images, stopped containers, volumes and orphaned networks. Clean up regularly:

# Remove all stopped containers, unused images and orphaned networks
docker system prune

# Also include unused volumes (warning: permanent deletion)
docker system prune --volumes

View a container's logs

# Display the container logs
docker logs container_name

# Follow in real time
docker logs -f container_name

# Limit the number of lines displayed
docker logs --tail 100 container_name

Update Docker Engine

sudo apt update
sudo apt upgrade docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

Update a Docker image

# Pull the latest version of the image
docker pull image_name:tag

# Recreate the container with the new image
docker compose pull
docker compose up -d

Which VPS configuration for Docker?

Use case Recommended RAM OuiHeberg plan
1 to 3 lightweight containers (website, bot, API) 4 GB VPS Linux 04G: €7.00 incl. VAT/month
Full stack (app + database + cache) 8 GB See the Linux VPS range
Multiple projects or heavy services 16 GB+ See the Linux VPS range

These estimates assume standard production containers. Actual needs vary depending on the images used and concurrent traffic.

Frequently asked questions

What is the difference between docker.io and docker-ce?

docker.io is the Docker package provided by the Debian/Ubuntu repositories. It often lags behind the official releases and does not receive updates as quickly. docker-ce (Community Edition) is the package maintained directly by Docker Inc. through its official repository. This guide uses docker-ce.

Is Docker Compose v2 compatible with older docker-compose.yml files?

Yes. The compose.yml (or docker-compose.yml) file format is compatible between v1 and v2. The only visible difference is the command: docker compose (v2, plugin) replaces docker-compose (v1, standalone binary). The file syntax remains identical for the vast majority of use cases.

How do I check that Docker is running after a VPS reboot?

sudo systemctl status docker

If Docker was enabled with systemctl enable docker.service, it starts automatically. Also make sure your containers are configured with the appropriate restart policy in the compose.yml: restart: unless-stopped or restart: always.

Can Docker be used without root access?

Yes, through rootless mode. Docker can run entirely without root privileges, which reduces the attack surface. The setup is more involved and documented here: docs.docker.com/engine/security/rootless/

How can I further protect the Docker daemon?

Setting up Fail2ban to protect SSH access to the VPS is a first step: see the Fail2ban guide. For Docker itself, never expose the Docker socket (/var/run/docker.sock) to untrusted containers, and do not enable the Docker TCP API without mutual TLS.

Docker is installed? Before going to production, walk through securing your VPS from A to Z.