Docker Engine packages an application and all its dependencies into an image and runs it as an isolated container on any Linux server. In this tutorial you will install Docker Engine, the Docker Compose plugin and Buildx from Docker's official repository on Ubuntu 24.04, with the differences you need for Debian 12 and Rocky Linux 9. By the end, Docker will run as a system service with log rotation enabled, and you will have published a test container on a port.

Prerequisites

To follow this guide you need:

  • A 64-bit server (x86_64 or arm64) running Ubuntu 24.04 LTS, Debian 12 or Rocky Linux 9, for example a CubePath VPS.
  • A non-root user with sudo privileges.
  • At least 1 GB of RAM and about 10 GB of free disk space for images and containers.

Steps 1 to 4 are for Ubuntu 24.04. If you use Debian 12 or Rocky Linux 9, follow the matching section further down and then continue with Step 5.

Step 1 - Removing conflicting packages

Ubuntu ships its own Docker-related packages (docker.io, docker-compose-v2, podman-docker) that conflict with the official ones. Remove them if they are installed; apt will simply report the ones that are not:

sudo apt remove docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc

Existing images and volumes in /var/lib/docker/ are not deleted by this command.

Step 2 - Adding Docker's official repository

Install the tools needed to download the repository key:

sudo apt update
sudo apt install ca-certificates curl

Download Docker's GPG key into /etc/apt/keyrings, the standard directory for third-party repository keys:

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

Create the repository file in deb822 format. The release codename (noble on Ubuntu 24.04) is read from /etc/os-release:

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

Refresh the package index and confirm that docker-ce now comes from Docker's repository:

sudo apt update
apt-cache policy docker-ce
docker-ce:
  Installed: (none)
  Candidate: 5:28.4.0-1~ubuntu.24.04~noble
  Version table:
     5:28.4.0-1~ubuntu.24.04~noble 500
        500 https://download.docker.com/linux/ubuntu noble/stable amd64 Packages

Your version number will differ; what matters is that the source is download.docker.com.

Step 3 - Installing Docker Engine

Install the engine, the CLI, containerd and the Buildx and Compose plugins:

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

On Ubuntu and Debian the service is enabled and started automatically. Check it:

sudo systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: active (running) since Fri 2026-09-25 10:12:41 UTC; 20s ago

Press q to exit.

Step 4 - Testing the installation

Run the hello-world image, which pulls a tiny image, starts a container and prints a message:

sudo docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.

Also check that the Compose plugin is available. It is now invoked as docker compose (with a space), not as the old standalone docker-compose binary:

docker compose version
Docker Compose version v2.39.2

Installing on Debian 12

On Debian the process is the same as on Ubuntu except for the repository URL and codename. Remove conflicting packages:

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

Add the key and point the repository at linux/debian:

sudo apt update
sudo apt install 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 > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Install the packages as in Step 3:

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

Then run sudo docker run hello-world as in Step 4.

Installing on Rocky Linux 9

Some Rocky Linux 9 images come with Podman and Buildah, whose dependencies conflict with containerd.io. Remove them if you do not use them:

sudo dnf remove podman buildah runc

Add Docker's official RHEL repository, which is the one that applies to Rocky Linux:

sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo

Install the packages. dnf asks you to accept the GPG key; check that the fingerprint matches 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35:

sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Unlike on Ubuntu, the service does not start on its own on the RHEL family. Enable and start it:

sudo systemctl enable --now docker

Check that it is active with sudo systemctl status docker and run sudo docker run hello-world as in Step 4.

Step 5 - Running Docker without sudo

By default the Docker socket (/var/run/docker.sock) is owned by root and the docker group. Adding your user to that group lets you run docker without sudo:

sudo usermod -aG docker $USER

The group change applies to new sessions. Log out of SSH, log back in and check that it works without sudo:

docker run --rm hello-world

If you see Hello from Docker! again, the setup is correct.

Step 6 - Configuring log rotation

The default logging driver (json-file) stores everything a container writes to stdout and stderr under /var/lib/docker/containers/ with no size limit. A chatty container can fill the disk in days. Set a limit in the daemon configuration:

sudo nano /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

With this, each container keeps at most three 10 MB log files. Restart Docker to apply the change:

sudo systemctl restart docker

Verify that the daemon picked up the configuration:

docker info --format '{{.LoggingDriver}}'
json-file

If Docker fails to start after the restart, the cause is almost always a syntax error in daemon.json; read the message with sudo journalctl -u docker -n 20. The limits apply only to containers created after the change.

Step 7 - Publishing a test container

To confirm networking works, start Nginx and publish its port 80 on port 8080 of the server:

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

Check that it responds:

curl -I http://localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.29.1
Content-Type: text/html

Remove the test container:

docker rm -f test-nginx

Troubleshooting

permission denied while trying to connect to the Docker daemon socket: your user is not in the docker group, or you have not opened a new session yet. Run groups and check that docker is listed; if not, repeat Step 5 and log in again.

The service does not start: read the reason with sudo journalctl -u docker -n 50 --no-pager. The most common causes are invalid JSON in daemon.json or leftover old packages (docker.io) that were not removed in Step 1.

Bind for 0.0.0.0:8080 failed: port is already allocated: another process or container is using that port. Find it with sudo ss -tlnp | grep :8080 and pick another port or stop the process.

The disk fills up: see how much space images, containers and volumes use with docker system df, and remove unused data with docker system prune. Add --volumes only if you are sure you do not need the data in unused volumes.

Updating Docker

Because Docker is installed from a repository, it is updated with the rest of the system:

sudo apt update && sudo apt upgrade

On Rocky Linux use sudo dnf upgrade. Containers with a restart policy (--restart unless-stopped) start again on their own after the upgrade.

Conclusion

You have installed Docker Engine, Buildx and Docker Compose from the official repository, configured access without sudo and log rotation, and confirmed that containers start and publish ports correctly. Remember that published ports bypass the host firewall.

As next steps, you can:

  • Learn the everyday Docker commands to run, inspect and clean up containers, images, volumes and networks.
  • Build your own images with a Dockerfile and multi-stage builds.
  • Define multi-container applications in a compose.yaml file and manage them with docker compose up -d.