
If you have ever deployed an application and watched it break on a new server because of a missing dependency or a wrong Python version, you already know why Docker exists. Docker solves the “it works on my machine” problem by packaging your app and every dependency it needs into an isolated container that runs identically on any host. In this guide, you will learn exactly how to install Docker on Ubuntu 26.04 LTS (Resolute Raccoon), configure it correctly for real server use, and run your first container with confidence.
Ubuntu 26.04 is the latest LTS release, and Docker CE 29.4.0 supports it natively from day one. This means no workarounds, no pinning to an older Ubuntu codename, and no PPAs. Everything in this guide was tested on a fresh Ubuntu 26.04 server running kernel 7.0.0-10-generic in April 2026.
Prerequisites
Before you run a single command, confirm these items are in place:
- Ubuntu 26.04 LTS installed (fresh install is ideal to avoid leftover package conflicts)
- A user account with
sudoprivileges — the install process modifies system-level APT sources, and it needs elevated permissions to do so - Active internet connection to download packages from Docker’s repository at
download.docker.com - A 64-bit system — Docker supports x86_64/amd64, arm64, armhf, s390x, and ppc64le architectures on Ubuntu
- Minimum 2GB RAM recommended if you plan to run real containers
Run this quick check to confirm you are on the right release:
lsb_release -a
You should see Ubuntu 26.04 LTS and codename Resolute in the output.
Why You Should Not Use Ubuntu’s docker.io Package
Ubuntu 26.04 does include a Docker package in its default repositories called docker.io. Many users install it because it is one apt install away. But for anything beyond a quick personal test, that package has real drawbacks.
It lags behind the official Docker CE releases by weeks or months. You miss critical security patches and engine improvements. The bundled Docker Compose version is older and ships as a separate binary rather than a plugin.
The table below shows the version difference between what Ubuntu ships and what you get from the official Docker repository:
| Component | Official Docker CE (this guide) | Ubuntu docker.io |
|---|---|---|
| Docker Engine | 29.4.0 | Older, lags behind |
| Docker Compose | v5.1.2 (plugin) | Separate, older version |
| containerd | 2.2.2 | Varies |
| Buildx | 0.33.0 | Separate package |
| Update cadence | Direct from Docker Inc. | Ubuntu-controlled |
The official repository also gives you a direct upgrade path — you run apt update && apt upgrade and you stay current without any extra steps. That matters on a server you are responsible for.
Step 1: Remove Conflicting Docker Packages
The first thing to do before installing Docker CE is clean out any package that might collide with it. This applies even on a fresh Ubuntu 26.04 install, because Ubuntu includes several Docker-adjacent packages in its default repo.
If any of these packages exist alongside Docker CE, APT will hit version conflicts during installation or when you run apt upgrade later. The packages to remove are: docker.io, docker-doc, docker-compose, docker-compose-v2, podman-docker, containerd, and runc.
Run this loop to remove all of them in one shot:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt remove -y $pkg 2>/dev/null
done
On a fresh server, APT will report that none of these are installed. That is the expected and correct output — it is not an error.
Should You Also Delete the Old Data Directories?
If you are cleaning up a server where Docker was previously installed, you need to go further. APT remove only uninstalls the binaries. It leaves behind everything in /var/lib/docker — all your old images, containers, and volumes. Those data directories can cause containerd to misbehave with the new installation if the formats are incompatible.
Warning: the following commands permanently delete all Docker data. Back up anything you need first.
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
On a genuinely fresh Ubuntu 26.04 server with no prior Docker history, skip these two commands. There is nothing there to remove.
Step 2: Update Your System and Install the Required Dependencies
With conflicting packages cleared, update APT’s package cache and install the two tools Docker’s setup process depends on.
sudo apt update && sudo apt upgrade -y
Running apt upgrade before installing Docker is worth doing. A stale system with outdated ca-certificates can cause curl to reject the TLS certificate from download.docker.com, which breaks the GPG key download in the next step. Keeping the system current prevents that class of failure.
Now install the two required packages:
sudo apt install -y ca-certificates curl
ca-certificates gives your system an up-to-date set of trusted certificate authorities. Without them, secure HTTPS connections to Docker’s servers fail. curl is the download tool you use in the next step to fetch Docker’s signing key.
Step 3: Add Docker’s Official GPG Signing Key
Before APT installs any package from Docker’s repository, it needs a way to verify those packages have not been tampered with. That is what Docker’s GPG signing key does. Every package Docker publishes is signed with this key, and APT checks the signature before installing anything.
First, create the keyrings directory. This is where modern Ubuntu stores trusted repository keys, separated from the older and now deprecated trusted.gpg.d location:
sudo install -m 0755 -d /etc/apt/keyrings
Now download Docker’s GPG key and save it to that directory:
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
Set the file permissions so APT can read it:
sudo chmod a+r /etc/apt/keyrings/docker.asc
The chmod a+r step matters more than it looks. APT runs as a non-root user during certain signature verification operations. If the key file is only readable by root, APT silently fails to verify package signatures, which can cause confusing installation errors.
Optional: Verify the Key Fingerprint
You can visually inspect the key to confirm it matches Docker’s published fingerprint:
gpg --show-keys /etc/apt/keyrings/docker.asc
Look for a key associated with Docker Release (CE deb). Cross-reference the fingerprint with what Docker publishes in their official documentation.
Step 4: Add Docker’s Official APT Repository
With the GPG key in place, add Docker’s official APT repository to your system’s source list. This tells APT where to look for Docker CE packages and confirms that packages from that source are authenticated with the key you just installed.
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" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Two things in this command are worth understanding:
$(dpkg --print-architecture)automatically detects your system’s CPU architecture (amd64, arm64, etc.) and adds it to the repository line. This prevents APT from listing incompatible package architectures on multi-arch systems.$(. /etc/os-release && echo "$VERSION_CODENAME")reads your Ubuntu release codename directly from the system and inserts it. On Ubuntu 26.04, this resolves toresolute. The same command works on Ubuntu 24.04 (noble) or 22.04 (jammy) without any manual editing.
Verify the repository file was written correctly:
cat /etc/apt/sources.list.d/docker.list
Expected output:
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu resolute stable
Confirm you see resolute in the output. If the codename is missing or wrong, re-run the repository add command before continuing.
Refresh APT to pull in the Docker repository’s package index:
sudo apt update
Step 5: Install Docker Engine, CLI, containerd, Compose, and Buildx
Now install Docker CE and all of its companion tools in a single command. Installing them together is important because they are designed to work as a coordinated unit.
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Here is what each package does and why it is included:
docker-ce— the Docker Engine daemon (dockerd). This is the core process that manages container lifecycle, networking, and storage on your host.docker-ce-cli— thedockercommand you type in the terminal. It communicates with the daemon over a Unix socket.containerd.io— the low-level container runtime. Docker delegates the actual work of starting, stopping, and pulling containers to containerd. Ubuntu 26.04 ships containerd at version 2.2.2, a major step up from the 1.x series on older Ubuntu releases.docker-buildx-plugin— enables BuildKit, Docker’s modern image build engine. The classic builder is deprecated. Buildx is required for multi-stage Dockerfiles,--mountcache flags, and multi-platform image builds.docker-compose-plugin— installs Docker Compose as a CLI sub-command (docker compose). The old standalonedocker-composev1 Python binary is end-of-life. This plugin is the supported path going forward.
APT pulls roughly 95 MB of packages. Both the Docker and containerd services start automatically after installation completes.
Check the installed versions:
docker --version
docker compose version
docker buildx version
Expected output:
Docker version 29.4.0, build 9d7ad9f
Docker Compose version v5.1.2
github.com/docker/buildx v0.33.0
Step 6: Verify the Docker Service and Test Your Installation
Confirm Docker Is Running with systemd
Version output alone only tells you the binary installed correctly. It says nothing about whether the daemon is actually running and accepting connections. Check the service status through systemd:
sudo systemctl status docker
Look for two things in the output:
Active: active (running)— the daemon is liveenabled; preset: enabled— Docker starts automatically at boot
If Docker is not enabled to start on boot, fix that now:
sudo systemctl enable --now docker
On servers, forgetting this step means a reboot kills your containers with no automatic recovery.
Run the hello-world Container
The hello-world container exercises the entire Docker pipeline in one shot: the client contacts the daemon, the daemon pulls an image from Docker Hub, creates a container from it, runs it, and streams the output back to your terminal. If any part of the chain is broken, this test catches it.
sudo docker run hello-world
Expected output:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
...
Hello from Docker!
This message shows that your installation appears to be working correctly.
Docker pulled the image from Docker Hub because it was not cached locally, ran the container, printed the success message, and exited. Your installation is working.
Run a Real Container: Nginx
Go one step further and verify that port mapping and container networking work:
docker run -d -p 127.0.0.1:8080:80 --name web nginx:alpine
curl -sI http://localhost:8080
You should see HTTP/1.1 200 OK in the response headers. Binding to 127.0.0.1 rather than 0.0.0.0 is intentional here — it prevents the test container from being publicly accessible if your firewall is open. Clean up when done:
docker rm -f web
Post-Installation Step 1: Run Docker Without sudo
By default, Docker commands require sudo because the daemon runs as root and exposes its socket at /var/run/docker.sock. Only root or members of the docker group can write to that socket.
Add your user to the docker group:
sudo usermod -aG docker $USER
Activate the group change in your current session without logging out:
newgrp docker
Test it:
docker ps
If you see an empty container list (not a permission error), non-root Docker access is working.
Security note: Members of the docker group have root-equivalent access to the host system. Through volume mounts and --privileged containers, a docker group member can read or write any file on the host. Only add users you trust completely. For stricter security requirements, look into Docker rootless mode.
Post-Installation Step 2: Configure the Docker Daemon for Server Use
Docker’s default configuration works fine for development. For a server, two defaults will eventually cause problems: there is no log size limit, so container logs will fill your disk over time, and the default network pool can collide with existing subnets on some network setups.
Create or edit the Docker daemon configuration file:
sudo nano /etc/docker/daemon.json
Add this production-ready baseline configuration:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2"
}
What each setting does:
max-size: "10m"andmax-file: "3"— caps each container’s log storage at 30 MB total (three 10 MB files with rotation). Without this, a chatty container can quietly consume gigabytes of disk space over days.storage-driver: "overlay2"— explicitly sets the storage driver to overlay2, which is the recommended and only officially supported driver on Ubuntu 26.04 with cgroup v2 and ext4 or xfs filesystems.
Apply the new settings by restarting Docker:
sudo systemctl restart docker
Note that existing containers keep their old log configuration. Only containers created after the restart inherit these settings.
Verify cgroup v2 Is Active (Ubuntu 26.04 Specific)
Ubuntu 26.04 is the first Ubuntu LTS to drop cgroup v1 entirely. There is no fallback. Docker CE 29.4.0 handles this cleanly, but it is worth confirming:
docker info | grep -i cgroup
Expected output:
Cgroup Driver: systemd
Cgroup Version: 2
If you see cgroup v1 anywhere, something is wrong with the host configuration — not just Docker.
Troubleshooting Common Issues on Ubuntu 26.04
Error: Cannot Connect to the Docker Daemon
Symptom:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Why it happens: The Docker service failed to start after installation, often due to a port conflict, a stale lock file, or a previous dockerd process still running.
Fix:
sudo systemctl start docker
sudo systemctl enable docker
sudo systemctl status docker
Check the service journal for the real error if it still fails:
sudo journalctl -u docker.service -n 50 --no-pager
Error: Permission Denied on the Docker Socket
Symptom:
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
Why it happens: The user was added to the docker group, but the current shell session started before that group assignment existed. The session still holds the old group list.
Fix:
newgrp docker
Or log out and log back in completely. On remote SSH sessions, newgrp docker is less disruptive.
Error: Unable to Locate Package docker-ce
Symptom:
E: Unable to locate package docker-ce
Why it happens: APT’s package index was not refreshed after adding the Docker repository, or the codename in the source file resolved to something other than resolute.
Fix: Check the source file first:
cat /etc/apt/sources.list.d/docker.list
Confirm it shows resolute. Then refresh:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Error: Container Networking Fails or Containers Cannot Reach the Internet
Symptom: Containers start but cannot make outbound network requests or reach each other.
Why it happens: Docker modifies iptables rules directly to set up container networking. UFW, Ubuntu’s default firewall, can have rules that conflict with or override Docker’s bridge traffic.
Fix: Check that Docker’s default bridge network exists:
docker network ls
You should see a bridge network. If container internet access is still broken, restart the Docker service and confirm IP forwarding is enabled:
sudo systemctl restart docker
sysctl net.ipv4.ip_forward
The output should be net.ipv4.ip_forward = 1. If it is 0, set it manually:
sudo sysctl -w net.ipv4.ip_forward=1
Error: Disk Space Issues from Docker Data
Symptom: Server disk fills up over time; df -h shows /var/lib/docker consuming gigabytes.
Why it happens: Pulled images, stopped containers, and unused volumes accumulate silently. Docker does not auto-clean anything.
Fix: Check what Docker is using:
docker system df
Remove everything that is not actively in use:
docker system prune -a --volumes
This removes all stopped containers, unused networks, dangling images, and volumes not attached to a running container. Run it during a maintenance window on production servers.
Essential Docker Commands for Daily Use
Once Docker is running, these are the commands you will use most often:
| Command | What It Does |
|---|---|
docker ps |
Lists running containers |
docker ps -a |
Lists all containers, including stopped ones |
docker images |
Lists locally cached images |
docker logs <container> |
Shows stdout/stderr output from a container |
docker exec -it <container> bash |
Opens a shell inside a running container |
docker stop <container> |
Gracefully stops a running container |
docker rm <container> |
Removes a stopped container |
docker system prune -a |
Removes all unused Docker data |
docker compose up -d |
Starts a Compose stack in the background |
docker info |
Shows full daemon configuration and status |
How To Completely Remove Docker from Ubuntu 26.04
If you need to start completely fresh or decommission Docker from a server, use apt purge rather than apt remove. The remove command leaves configuration files behind, which interferes with a clean reinstall.
sudo apt purge -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
Remove all Docker data and configuration:
sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker
Remove the repository source and GPG key:
sudo rm /etc/apt/sources.list.d/docker.list /etc/apt/keyrings/docker.asc
This permanently destroys all containers, images, and volumes. Back up anything you need before running these commands.
Congratulations! You have successfully installed Docker. Thanks for using this tutorial for installing Docker container on the Ubuntu 26.04 LTS Resolute Raccoon) system. For additional help or useful information, we recommend you check the official Docker website.