Installing Docker on Ubuntu: Reliable Steps and Common Pitfalls
At some point, running isolated workloads—development, testing, or production—on Ubuntu leads developers and ops teams straight to Docker. Here’s the reference process for installing Docker CE (Community Edition) on most supported Ubuntu releases (20.04/22.04/24.04). Side note: the following assumes a fresh system; mixed-version upgrades can introduce dependency headaches.
Prerequisites
- Ubuntu 20.04 LTS or newer (x86_64/amd64).
- User with
sudo
access. - Minimal shell experience.
For cloud VMs (e.g., AWS EC2, GCP Compute Engine, Azure VMs), these instructions remain identical, though outbound internet for apt is mandatory.
1. Clean State (Highly Recommended)
Remove any previously installed Docker components to avoid version collisions or retained config files.
sudo apt remove -y docker docker-engine docker.io containerd runc
Gotcha: Stale daemons can linger after uninstall—ensure
systemctl status docker
returns inactive before proceeding.
2. System Package Update
Out-of-date apt indices cause 404s on install. Always refresh system metadata first.
sudo apt update && sudo apt upgrade -y
3. Install Required Transport and Crypto Utilities
APT’s https transport requires several supporting packages.
sudo apt install -y ca-certificates curl gnupg lsb-release
4. Add Docker’s Official GPG Key
Security best practice: Only trust signed packages. Store the Docker public key outside the default apt trust path.
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
5. Register the Docker Repository
Ensure only the Docker-maintained packages are offered (not Ubuntu universe).
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
6. Reload Package Lists
sudo apt update
At this stage, verify the source:
apt-cache policy docker-ce
Expected: repository lines must match download.docker.com
.
Sample output:
docker-ce:
Installed: (none)
Candidate: 5:24.0.7-1~ubuntu.22.04~jammy
Version table:
5:24.0.7-1~ubuntu.22.04~jammy 500
500 https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages
If Candidate
shows no version, the repo is misconfigured or unsupported on this distro.
7. Install Docker Engine and Dependencies
Install the core components:
sudo apt install -y docker-ce docker-ce-cli containerd.io
Note: Additional packages such as docker-buildx-plugin
or docker-compose-plugin
are available, but not strictly required for base engine operation.
8. Validate the Installation
Engine status:
sudo systemctl status docker
Healthy output resembles:
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since ...
Check the installed version:
docker --version
# Docker version 24.0.7, build afdd53b
Quick smoke test—ensure images can be pulled and containers started:
sudo docker run --rm hello-world
Expected message includes:
Hello from Docker!
This message shows that your installation appears to be working correctly.
If you see Cannot connect to the Docker daemon...
, the service is likely not running or user permissions need tuning.
9. (Practical Tip) Enable Non-root Docker CLI Usage
By default, Docker requires root privileges. For non-interactive CI/CD, running as docker
group avoids repeated use of sudo
.
Security note: Adding users to docker
group gives root-equivalent access.
sudo groupadd docker 2>/dev/null || true
sudo usermod -aG docker $USER
You must log out and log back in for the group change to propagate to your session. Validate with:
docker run --rm hello-world
No sudo
required; failure indicates group membership isn’t yet effective.
10. System Tuning and Troubleshooting
- To auto-start Docker after boot:
sudo systemctl enable docker
- If container networking fails (often on VPS or WSL), inspect custom firewall or iptables rules.
- For “Cannot connect to the Docker daemon”:
- Ensure dockerd is active.
- Confirm user group assignment.
- Check
docker.sock
permissions.
- Want extra isolation? Swap out
containerd.io
for a custom runtime, but expect more manual integration.
Reference Command Cheat Sheet
sudo apt remove -y docker docker-engine docker.io containerd runc
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
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
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
docker --version
sudo docker run --rm hello-world
# (Optional: Docker group configuration)
sudo groupadd docker
sudo usermod -aG docker $USER
Real-world Deployment Note
Most modern CI runners (GitHub Actions, GitLab CI) pre-install Docker, but versions can lag behind upstream. Always verify the version and configuration on each host. There are edge cases: for example, mixing apt installs with Snap can break the socket path. Purge the unwanted method before proceeding.
For production, consider additional configuration steps: configure storage backends, audit daemon.json options, or deploy via configuration management (Ansible, Terraform modules).
Next steps: Consider integrating Docker Compose for orchestrating multi-container setups, or hardening the daemon for multi-user systems. Kubernetes setup is non-trivial and has its own prerequisites—the above covers only stand-alone Docker hosts.