Installing Docker on Ubuntu
Docker is the most popular tool for building and running containers (lightweight, isolated packages that bundle an app with everything it needs to run). To use it on a server, you install Docker Engine — the background service and command-line tool that actually builds images and runs containers. This page walks you through the official installation on Ubuntu, step by step, so you end up with a clean, up-to-date setup and your first container running.
Why install from Docker’s official repo (not docker.io)
Ubuntu ships a package called docker.io in its default repositories. It works, but it is often months or years behind the real Docker release. You miss new features, bug fixes, and security patches.
The recommended way is to add Docker’s own APT repository (APT is Ubuntu’s package manager — the tool behind apt install). This gives you the genuine docker-ce (Docker Community Edition) package, updated directly by Docker, and it stays current every time you run apt upgrade.
| Option | What you get | When to use |
|---|---|---|
apt install docker.io | Ubuntu’s older, repackaged Docker | Quick throwaway test on a machine you don’t care about |
Docker’s official APT repo (docker-ce) | Latest Docker Engine, Compose plugin, kept current | Every real server, dev box, or production host |
Use the official repo for anything you’ll keep. The few extra setup steps below pay off the first time you need a recent Docker feature or a security fix.
Step 1 — Remove any old or conflicting packages
If a different Docker package was installed before, remove it first so it doesn’t clash with the official one. This is safe to run even on a fresh server — it simply does nothing if those packages aren’t present.
sudo apt remove -y docker docker-engine docker.io containerd runc
Step 2 — Set up Docker’s APT repository
First, install a few helper packages and add Docker’s signing key. The GPG key (a cryptographic signature) lets APT verify that packages really came from Docker and were not tampered with.
# Update the package list and install prerequisites
sudo apt update
sudo apt install -y ca-certificates curl gnupg
# Create the folder for APT keyrings and download Docker's GPG key
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
Now add the repository itself. This command writes the correct line for your exact Ubuntu version automatically, so it works the same on Ubuntu 22.04 LTS and 24.04 LTS (LTS means Long-Term Support, the stable releases meant for servers).
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
sudo apt update
Step 3 — Install Docker Engine
With the repo in place, install the engine, its container runtime, and the official Compose plugin (a tool for running multi-container apps from a single file) in one go.
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
After this finishes, Docker runs as a systemd service (systemd is Ubuntu’s service manager — it starts programs in the background and restarts them after a reboot). The installer enables and starts it for you. Confirm it is active:
sudo systemctl status docker
Output:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Mon 2026-06-15 10:12:44 UTC; 8s ago
Docs: https://docs.docker.com
Main PID: 4821 (dockerd)
Tasks: 9
Memory: 24.6M
active (running) and enabled mean Docker is up now and will start automatically on every boot.
Step 4 — Run Docker without sudo (the docker group)
Right after install, every Docker command needs sudo because the Docker daemon (the dockerd background process) runs as root (the all-powerful admin user). Typing sudo every time is tedious, so Docker creates a group called docker. Any user in that group can talk to the daemon directly.
Add your own user to the group, then reload your group membership:
sudo usermod -aG docker $USER
newgrp docker
newgrp docker applies the new group in your current shell. To be safe, log out and back in (or reboot) so every new terminal picks it up.
Security warning: members of the
dockergroup effectively have root-level access to the whole machine. A container can mount the host filesystem, so anyone who can rundockercan read or change any file. Only add trusted users, and on shared or production servers consider keeping Docker behindsudoor using rootless mode instead.
Step 5 — Verify the install and run your first container
Check the versions of the client (the docker command) and the server (the daemon). If both show up, they are talking to each other correctly.
docker version
Output:
Client: Docker Engine - Community
Version: 27.5.1
API version: 1.47
Go version: go1.22.11
OS/Arch: linux/amd64
Server: Docker Engine - Community
Engine:
Version: 27.5.1
API version: 1.47 (minimum version 1.24)
containerd:
Version: 1.7.25
Now run the classic test container. hello-world is a tiny official image that prints a message and exits — it proves the whole pipeline (pulling images, creating a container, running it) works end to end.
docker run hello-world
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.
If you see “Hello from Docker!”, you are done — Docker is installed and working.
Best Practices
- Always install from Docker’s official APT repo, not
docker.io, so you get timely security and feature updates. - Keep Docker current by including it in routine updates:
sudo apt update && sudo apt upgrade. - Add only trusted users to the
dockergroup — membership is equivalent to root access. - Confirm the service is enabled (
systemctl is-enabled docker) so containers come back after a reboot. - Test every install with
docker run hello-worldbefore deploying real workloads. - On multi-user or production hosts, evaluate rootless Docker to reduce the blast radius of a compromise.
- Pin or note the Docker version you tested against so server rebuilds stay reproducible.