On Ubuntu, docker-ce and docker.io are not interchangeable package names from the same source. docker-ce comes from Docker’s official APT repository; docker.io comes from Ubuntu’s repositories. Both can provide Docker, but choose one source and avoid mixing their Engine packages.
This walkthrough installs Docker’s packages on Ubuntu 22.04 or 24.04, verifies the daemon, and covers the permission warning that’s easy to miss.
Check the system and existing packages
Docker’s supported releases and architectures can change, so check your Ubuntu codename and architecture before adding a repository:
. /etc/os-release
printf 'Release: %s\nCodename: %s\nArchitecture: ' "$VERSION_ID" "${UBUNTU_CODENAME:-$VERSION_CODENAME}"
dpkg --print-architecture
The commands below use those detected values instead of hard-coding a release codename. If you’re on another Ubuntu release or architecture, check Docker’s current support information before proceeding.
If you already have a Docker installation, inspect potentially conflicting packages first:
dpkg -l docker.io docker-compose docker-doc podman-docker containerd runc
When switching to Docker’s repository, Docker lists packages such as these as conflicts to remove. Remove only packages that are installed and that you’ve confirmed are safe to remove:
sudo apt-get remove docker.io docker-compose docker-doc podman-docker containerd runc
Removing packages this way does not automatically delete Docker images, containers, or volumes. Don’t delete Docker’s data directory as routine package cleanup.
If you want Ubuntu’s package instead, install docker.io and stop here; don’t also follow the Docker repository installation below:
sudo apt-get update
sudo apt-get install docker.io
Install Docker’s official APT packages
First install the tools used to fetch the repository signing key:
sudo apt-get update
sudo apt-get install ca-certificates curl
Create APT’s keyring directory, download Docker’s key, and allow APT to read it:
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
Add Docker’s repository as a deb822 source. The release codename and architecture are read from the system:
echo "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" | sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null
Refresh APT’s package index and install the Engine, CLI, container runtime, Buildx, and Compose V2 plugin:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
The Compose V2 command is docker compose—with a space—not the older docker-compose command.
Verify the daemon and run a test
Check whether the service is active, then inspect its status if needed:
sudo systemctl is-active docker
sudo systemctl status docker --no-pager
An active service confirms the daemon is running; it doesn’t guarantee every container or network operation will work. Try Docker’s test image next:
sudo docker run hello-world
The first run needs network access to download the image. You can also check the installed client and Compose plugin versions:
sudo docker version
docker compose version
If APT can’t find docker-ce, inspect the source file and confirm the detected codename and architecture:
cat /etc/apt/sources.list.d/docker.sources
. /etc/os-release
echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}"
dpkg --print-architecture
Then run sudo apt-get update again. A release or architecture not supported by Docker’s repository may require a different installation option.
If the service is inactive or failed, check its status and recent logs before changing configuration:
sudo systemctl status docker --no-pager
sudo journalctl -u docker --no-pager -n 50
For a stopped service, starting it and checking the status again is a reasonable next step. If you need to investigate daemon restarts, see this guide to restarting Docker safely on Linux.
Understand Docker access before dropping sudo
A socket permission error often means your regular user can’t access the Docker daemon. Using sudo is the simplest default. You can add a user to the docker group, but membership grants privileges effectively equivalent to root access on the host. Only do this for users you trust with administrative control. The Docker group setup and its security implications are worth reviewing before changing access.
After a group-membership change, start a new login session before testing; the existing session may not have the updated group list. Docker also offers rootless mode, which has separate setup requirements and limitations.
Finally, take care when publishing container ports. Docker’s networking rules can interact with host firewall configuration, and published ports may be reachable differently than expected from UFW rules alone. Expose only the ports you intend to make available, and verify access from outside the host.
I originally published a more detailed version of this guide on the SSHFlow blog.
I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.
Top comments (1)
tr.ee/dev-to