Ubuntu 18.04 LTS (Bionic Beaver) reached end of standard support some time ago, but I still run into it regularly on legacy servers, older cloud images, and long-lived internal infrastructure that hasn’t been upgraded yet. Installing Docker on it works essentially the same way as on any modern Ubuntu release, with a couple of version-availability caveats worth knowing up front. This guide walks through a clean install from scratch.
Prerequisites
- A machine or VM running Ubuntu 18.04 LTS with sudo access
- An internet connection for package downloads
- At least 20GB of free disk space (Docker images accumulate quickly)
Check your Ubuntu version first:
lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic
Step 1: Remove Any Old Docker Packages
Older Ubuntu installs sometimes have outdated packages like docker, docker-engine, or docker.io from the default Ubuntu repos, which conflict with Docker’s official builds:
sudo apt-get remove docker docker-engine docker.io containerd runc
Package 'docker' is not installed, so not removed
Package 'docker-engine' is not installed, so not removed
That output is expected on a clean system — it confirms nothing conflicting is present.
Step 2: Update Package Index and Install Prerequisites
sudo apt-get update
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
Step 3: Add Docker’s Official GPG Key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Step 4: Add the Docker APT Repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Verify the file:
cat /etc/apt/sources.list.d/docker.list
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu bionic stable
Note bionic correctly reflects the 18.04 codename, pulled automatically from lsb_release -cs.
Step 5: Install Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Expected output (abbreviated):
Setting up containerd.io (1.7.20-1) ...
Setting up docker-ce-cli (5:27.3.1-1~ubuntu.18.04~bionic) ...
Setting up docker-ce (5:27.3.1-1~ubuntu.18.04~bionic) ...
Setting up docker-buildx-plugin (0.17.1-1~ubuntu.18.04~bionic) ...
Setting up docker-compose-plugin (2.29.2-1~ubuntu.18.04~bionic) ...
Step 6: Verify Docker Is Running
sudo systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-07-29 10:44:12 UTC; 30s ago
sudo docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
Step 7: Manage Docker as a Non-Root User
Running every command with sudo gets old fast. Add the current user to the docker group:
sudo usermod -aG docker $USER
Log out and back in, or apply the group change to the current shell session without logging out:
newgrp docker
Verify:
docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
No sudo needed this time.
Step 8: Configure Docker to Start on Boot
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
Synchronizing state of docker.service with SysV service script.
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service.
Step 9: Confirm Compose Is Available
docker compose version
Docker Compose version v2.29.2
A Note on Ubuntu 18.04’s Kernel Version
Ubuntu 18.04 shipped originally with a 4.15 kernel, later updated via HWE (Hardware Enablement) stacks to newer kernels. Docker requires certain kernel features (namespaces, cgroups, overlay filesystem support) that are all present by 4.15, but some newer Docker features (like certain cgroup v2-only behaviors) assume a newer kernel than 18.04 ships by default. Check your running kernel:
uname -r
5.4.0-192-generic
If this looks unusually old (like a bare 4.15.x without HWE updates), I’d upgrade the kernel via the HWE stack before relying on Docker in anything beyond a test environment:
sudo apt-get install --install-recommends linux-generic-hwe-18.04
Internal Working: What “Installing Docker” Actually Installs
The docker-ce package I installed above is really a bundle of several cooperating components:
containerd: a high-level container runtime that manages container lifecycle, image transfer, and storage, originally split out of Docker itself and now a CNCF graduated project used by Docker, Kubernetes, and others.runc: the low-level OCI-compliant runtime that actually creates namespaces, sets up cgroups, and executes the container process.dockerd: the Docker daemon, which exposes the Docker API, manages images/volumes/networks, and delegates actual container execution down tocontainerdandrunc.docker-ce-cli: thedockercommand-line client that talks todockerdover its Unix socket (or TCP, if configured).docker-buildx-pluginanddocker-compose-plugin: CLI plugins that adddocker build(BuildKit-powered) anddocker composesubcommands.
When I run docker run hello-world, the CLI sends a request to dockerd, which asks containerd to pull the image and create a container, which in turn calls runc to actually fork and exec the isolated process using Linux namespaces and cgroups.
Networking Considerations
On installation, Docker creates a default bridge network (docker0) and configures iptables rules for NAT so containers can reach the internet and have their published ports (-p) forwarded from the host. On Ubuntu 18.04, this requires iptables (not nftables exclusively) to be functioning correctly — the default 18.04 install uses iptables-legacy, which Docker handles natively without extra configuration.
Storage Considerations
Docker’s default storage driver on modern kernels is overlay2, which requires the overlay kernel module (present by default on 18.04’s kernel). Verify:
docker info | grep "Storage Driver"
Storage Driver: overlay2
Docker’s data (images, containers, volumes) lives under /var/lib/docker by default — worth monitoring disk usage on this path over time:
sudo du -sh /var/lib/docker
2.1G /var/lib/docker
Security Considerations
- Since Ubuntu 18.04 is past its standard support window, ensure Docker itself is kept current even if the base OS receives fewer updates, and consider Ubuntu’s Extended Security Maintenance (ESM) if you must stay on 18.04 for compatibility reasons.
- Membership in the
dockergroup is equivalent to root access on the host — treat it with the same caution as sudo access. - Regularly run
docker system prunecautiously (after reviewing what it will remove) to avoid accumulating stale images that may contain outdated, vulnerable packages:
docker image prune -a --filter "until=720h"
Troubleshooting
“E: Unable to locate package docker-ce” Almost always means the repository wasn’t added correctly, or apt-get update wasn’t re-run after adding it. Recheck:
cat /etc/apt/sources.list.d/docker.list
sudo apt-get update
“Got permission denied while trying to connect to the Docker daemon socket” The current shell session hasn’t picked up the new docker group membership yet. Use newgrp docker or log out and back in.
Docker service fails with cgroup-related errors Check GRUB kernel parameters include cgroup support and reboot after any change:
cat /proc/cgroups
Monitoring
docker stats --no-stream
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 1 412.3MB 298.1MB (72%)
Containers 1 1 0B 0B
Local Volumes 1 1 5.2MB 0B (0%)
Best Practices
- Always remove distro-default Docker-adjacent packages before installing Docker’s official build.
- Pin the specific Docker version in production via
apt-get install docker-ce=<version>for reproducibility. - Keep the kernel updated via HWE stacks on long-lived 18.04 hosts.
- Enable both
docker.serviceandcontainerd.serviceon boot. - Regularly audit
/var/lib/dockerdisk usage and prune unused images/volumes.
Summary
Installing Docker on Ubuntu 18.04 follows Docker’s standard APT-based installation process almost identically to newer Ubuntu releases — add the GPG key, add the repository (correctly resolved to bionic), and install the docker-ce package family. The main things worth double-checking on an older release like 18.04 are kernel version/HWE status, iptables mode, and planning for the fact that the OS itself is past standard support even though Docker on it works exactly as documented.
References
- Docker Engine installation for Ubuntu: https://docs.docker.com/engine/install/ubuntu/
- Docker post-installation steps for Linux: https://docs.docker.com/engine/install/linux-postinstall/
- containerd documentation: https://containerd.io/docs/
- Ubuntu 18.04 Extended Security Maintenance: https://ubuntu.com/security/esm