Skip to content

TutorialsContainers & Docker

How to install Docker Engine on Ubuntu 24.04 and 26.04

Install Docker Engine and the Compose plugin on Ubuntu 24.04 or 26.04 LTS from Docker's own apt repository, then secure, update and back it up properly.

  • Beginner
  • 15 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Remove conflicting packages
  3. Step 2 — Add Docker's apt repository
  4. Step 3 — Install Docker Engine and the plugins
  5. Step 4 — Run Docker without sudo (optional)
  6. Step 5 — Turn on log rotation
  7. Step 6 — Keep published ports behind your firewall
  8. Update Docker
  9. Back up and restore
  10. Uninstall Docker
  11. Troubleshooting
  12. permission denied while trying to connect to the Docker daemon socket
  13. Package 'docker-ce' has no installation candidate
  14. Unmet dependencies or a conflict with containerd
  15. A container port is reachable although ufw blocks it
  16. The disk is full
  17. Next steps

Docker Engine runs applications in isolated containers, which is how most self-hosted apps and AI tools in this library are shipped. This guide installs Docker Engine from Docker's own apt repository on Ubuntu 26.04 LTS or 24.04 LTS, together with the Buildx and Compose plugins. You then let your admin user run Docker without sudo, switch on log rotation, keep published ports private behind your firewall, and learn how to update, back up and troubleshoot the installation.

Prerequisites

  • A server running Ubuntu 26.04 LTS (Resolute), 24.04 LTS (Noble) or 22.04 LTS (Jammy). Docker publishes packages for x86_64 (amd64), arm64, armhf, s390x and ppc64le on these releases.
  • A non-root user with sudo rights and SSH key login. If you have not done this yet, follow Secure a new Linux server and Set up SSH keys first.
  • Outbound HTTPS access to download.docker.com and to the container registries you plan to pull from (Docker Hub, GitHub Container Registry and so on).

Docker's documentation does not publish a minimum CPU or memory size for Docker Engine itself; the daemon is light. Size the server for the containers you will run and use the requirements listed in each app guide. As a working rule, keep at least 20% of the disk free, because images, container logs and volumes all live under /var/lib/docker.

Step 1 — Remove conflicting packages

Ubuntu's archive contains unofficial Docker packages (docker.io, docker-compose, podman-docker and others) that conflict with Docker Engine. Remove any that are installed:

Bash
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)

If none of them are installed, dpkg prints "no packages found" warnings and apt has nothing to do; that is fine. Existing images, containers and volumes in /var/lib/docker are not deleted by this step.

Step 2 — Add Docker's apt repository

Install the tools needed to fetch the signing key, store Docker's GPG key in /etc/apt/keyrings, and add the repository in the deb822 .sources format:

Bash
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/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Bash
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

The Suites line resolves to your release codename (resolute, noble or jammy). Check that apt now sees Docker's packages:

Bash
apt-cache policy docker-ce

The Candidate version should come from https://download.docker.com/linux/ubuntu.

Step 3 — Install Docker Engine and the plugins

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

On Ubuntu the docker service starts automatically and is enabled at boot. Verify the daemon and run the test image:

Bash
sudo systemctl status docker --no-pager
sudo docker run --rm hello-world
docker compose version

hello-world prints "Hello from Docker!" and exits. If the service is not running, start it with sudo systemctl start docker.

Step 4 — Run Docker without sudo (optional)

By default only root can talk to the Docker daemon. To let your admin user run docker commands directly, add it to the docker group, then log out and back in (or run newgrp docker for the current shell):

Bash
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
docker run --rm hello-world

groupadd reports that the group already exists on most systems, because the package creates it.

Step 5 — Turn on log rotation

The default json-file logging driver keeps container logs forever, which can fill the disk. Docker's local driver rotates and compresses logs by default (20 MB per file, 5 files). Make it the default for new containers:

Bash
sudo tee /etc/docker/daemon.json <<'EOF'
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF
sudo systemctl restart docker
docker info | grep -i "logging driver"

The last command prints Logging Driver: local. Existing containers keep their old logging settings until you recreate them (for Compose projects, docker compose up -d --force-recreate).

Step 6 — Keep published ports behind your firewall

When you publish a port without a host address (-p 8080:80), Docker listens on every IPv4 and IPv6 address of the server. Docker's own documentation states that ufw and firewalld rules do not apply to these ports, because Docker handles the traffic before ufw's rules are checked.

The safe pattern for web apps has three parts. First, publish app containers only on the loopback address, for example -p 127.0.0.1:8080:80, or in Compose:

YAML
services:
  app:
    image: nginx:stable
    ports:
      - "127.0.0.1:8080:80"

Second, put a reverse proxy in front of them on ports 80 and 443: see Caddy, Nginx with Certbot or Traefik. Third, allow only SSH and web traffic in ufw:

Bash
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Check from another machine that an app port is not reachable, for example with nc -vz your-server-ip 8080; the connection should be refused or time out.

Update Docker

Docker Engine updates arrive through apt like any other package:

Bash
sudo apt update
sudo apt upgrade
docker version

Upgrading docker-ce restarts the daemon. Containers started with a restart policy such as unless-stopped or always start again on their own; others stay stopped. Ubuntu's unattended-upgrades only installs updates from Ubuntu's own security pocket by default, so Docker packages are updated when you run apt yourself. Plan Docker upgrades for a quiet period.

To update the containers themselves, pull new images and recreate them; each app guide shows the exact commands.

Back up and restore

Images can always be pulled again, so back up the data, not the images:

  • named volumes (under /var/lib/docker/volumes/),
  • the host folders you bind-mount into containers,
  • your compose.yaml and .env files,
  • /etc/docker/daemon.json.

Docker's documented way to copy a volume is a short-lived container that mounts the volume and writes a tar archive to the current directory. Stop the containers that write to the volume first, so the files are consistent:

Bash
docker run --rm -v app_data:/data -v "$(pwd)":/backup ubuntu tar czf /backup/app_data.tar.gz -C /data .

Restore into a new or empty volume the same way:

Bash
docker volume create app_data
docker run --rm -v app_data:/data -v "$(pwd)":/backup ubuntu tar xzf /backup/app_data.tar.gz -C /data

For databases (PostgreSQL, MySQL/MariaDB, MongoDB) use the database's own dump tool, such as pg_dump or mariadb-dump, run with docker exec; each app guide shows the right command. Copy backups off the server as well.

Uninstall Docker

Bash
sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
Bash
sudo rm -rf /var/lib/docker /var/lib/containerd
sudo rm /etc/apt/sources.list.d/docker.sources /etc/apt/keyrings/docker.asc

Troubleshooting

permission denied while trying to connect to the Docker daemon socket

Your user is not in the docker group yet, or the session started before you added it. Run id and look for docker in the list; if it is missing, repeat Step 4 and log in again. Use sudo docker … in the meantime.

Package 'docker-ce' has no installation candidate

apt cannot see Docker's repository. Check the file with cat /etc/apt/sources.list.d/docker.sources: the Suites value must be your codename and the key must exist at /etc/apt/keyrings/docker.asc. Run sudo apt update again and read any NO_PUBKEY or 404 errors.

Unmet dependencies or a conflict with containerd

An unofficial package such as containerd or runc from Ubuntu's archive is still installed. Run Step 1 again, then sudo apt install -f and repeat Step 3.

A container port is reachable although ufw blocks it

This is expected for ports published on all addresses. Recreate the container with the port published on 127.0.0.1, or add iptables rules to the DOCKER-USER chain as described in Docker's firewall documentation.

The disk is full

Check what uses the space with docker system df. docker system prune removes stopped containers, unused networks, dangling images and build cache; add -a to remove every image not used by a container. Never add --volumes unless you are sure no volume holds data you need. Enable log rotation (Step 5) to stop logs from growing again.

Next steps

Frequently asked questions

Should I use Ubuntu's docker.io package instead?

You can, but Docker's documentation treats docker.io, docker-compose and podman-docker as unofficial packages that conflict with Docker Engine. The docker-ce packages from Docker's repository follow Docker's release cycle and include the Compose and Buildx plugins, which most app guides expect.

Can I install Docker with the get.docker.com convenience script?

Docker recommends the script only for testing and development, not for production. It configures the same repository but does so without showing each change. This guide uses the repository steps so you can see and review every command.

Does ufw protect ports published by Docker containers?

No. Docker routes published ports in the nat table before ufw's INPUT rules are evaluated, so a port published as 8080:80 is reachable from the internet even if ufw blocks 8080. Publish app ports on 127.0.0.1 and expose only your reverse proxy on ports 80 and 443.

Is adding my user to the docker group safe?

The docker group grants root-level privileges on the host. Add only trusted administrator accounts. If you need stronger isolation, use Docker's rootless mode or keep using sudo.

Which HyperDC servers can run Docker?

Docker runs inside your server's operating system, so you can use it on a HyperDC Linux VPS, VDS or dedicated server where you have root access and a supported Ubuntu release. Size the server for the containers you plan to run.

Sources

Wachtwoord genereren

Please confirm