Skip to content
Docker & Containers Pillar Guide

How to Install Docker on Ubuntu Server Step by Step

Install Docker on Ubuntu Server the right way: add the official apt repo and GPG key, install docker-ce plus the Compose plugin, and verify it works.

SDSysadmin Desk June 6, 2026 9 min read
Terminal-style cover showing apt installing Docker Engine on Ubuntu Server with the official Docker repository configured

There are three ways to put Docker on an Ubuntu server, and two of them will cause you grief later. apt install docker.io pulls an older, community-packaged build. The snap package runs Docker inside a confinement sandbox that quietly breaks bind mounts and socket paths. The method that actually matches the docs and behaves predictably is Docker’s own apt repository.

This guide walks through that official method end to end: removing any old packages, adding Docker’s GPG key and repo, installing Docker Engine with the Compose plugin, running Docker without sudo, making sure it survives a reboot, and confirming the whole thing works with a test container.

Everything here is for Ubuntu Server (20.04, 22.04, or 24.04). The commands are the same across those releases because the setup reads your version codename automatically. You’ll need a user with sudo rights and a few minutes.

Remove old or conflicting packages first

If this is a brand-new server, you can skip ahead. But if anyone ever ran apt install docker.io or installed the snap, clear it out before adding the official repo. Mixing package sources is where weird, hard-to-debug breakage comes from.

Remove the old apt packages:

sudo apt remove docker docker-engine docker.io containerd runc

Don’t worry if apt says some of those aren’t installed — it’s just making sure. This command removes the packages but leaves /var/lib/docker alone, so any existing images or volumes stay put.

If Docker came in as a snap, remove that too:

sudo snap remove docker

Add the prerequisites and Docker’s GPG key

Docker’s repo is signed, so apt needs the signing key on disk before it’ll trust packages from it. First install the small set of tools used to fetch the key over HTTPS:

sudo apt update
sudo apt install ca-certificates curl gnupg

Now create the keyring directory and download Docker’s official GPG key into 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

The /etc/apt/keyrings path matters. Older guides drop keys into apt-key or /etc/apt/trusted.gpg.d, but apt-key is deprecated and the modern, scoped approach is a dedicated keyring referenced directly by the repo entry. That’s what the next step does.

Add the official Docker repository

This one command writes the repo definition, automatically filling in your architecture and Ubuntu codename:

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

A few things are happening in that line worth understanding:

  • arch=$(dpkg --print-architecture) inserts amd64, arm64, etc. so you get packages for your CPU.
  • signed-by=... points at the key you just saved, scoping trust to this repo.
  • $(. /etc/os-release && echo "$VERSION_CODENAME") expands to jammy, noble, or whatever your release is called, so you never hardcode the version.

Then refresh apt so it reads the new repo:

sudo apt update

If apt update errors here, it’s almost always the key or codename. Re-check that /etc/apt/keyrings/docker.asc exists and is readable, and that your Ubuntu release is one Docker actually publishes for.

Install Docker Engine and the Compose plugin

Now the actual install. This pulls Docker Engine, the CLI, containerd, Buildx, and the Compose v2 plugin in one go:

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Here’s what each package is for:

What you're installing

docker-ce Docker Engine — the daemon that builds and runs containers.
docker-ce-cli The docker command-line client you actually type into.
containerd.io The container runtime Docker sits on top of.
docker-buildx-plugin Modern image builder; powers docker buildx and faster builds.
docker-compose-plugin Compose v2, used as docker compose (a space, not a hyphen).

Because docker-compose-plugin is in that list, you do not need to install Compose separately. You’ll call it as docker compose. If you’ve used the old docker-compose (one word, hyphen) before, that was the deprecated Python tool — the plugin replaces it.

Run Docker without sudo

Right after install, docker commands only work as root because the daemon’s socket is owned by root. You can prefix everything with sudo, but the cleaner fix is to add your user to the docker group:

sudo usermod -aG docker $USER

This change doesn’t apply to your current shell session. You have to start a fresh login so the new group membership is picked up:

# Log out and back in (SSH: disconnect and reconnect), or for the current shell:
newgrp docker

Verify the group took effect — you should see docker in the output:

groups

Make sure Docker starts on boot

The apt package registers Docker as a systemd service and enables it, so it should already start at boot. Confirm rather than assume:

systemctl is-enabled docker
systemctl status docker

is-enabled should print enabled, and status should show active (running). If for some reason it isn’t enabled, turn it on and start it in one command:

sudo systemctl enable --now docker

There’s a second layer people forget. Enabling the Docker service means the daemon comes back after a reboot — it does not automatically restart your containers. For a container to survive a reboot, it needs a restart policy. With docker run, add --restart unless-stopped; in Compose, set restart: unless-stopped on the service. If you’re new to Compose, the Docker Compose beginner guide shows exactly where that line goes.

Restart policies worth knowing

no Default. Container never restarts on its own.
unless-stopped Restarts on failure and after a reboot, unless you stopped it manually. Good default for services.
always Always restarts, even one you stopped manually (restarts again after daemon restart).
on-failure Restarts only if the container exits with an error code.

Verify the install with hello-world

The traditional smoke test pulls and runs a tiny image that prints a message and exits:

docker run hello-world

If everything is wired up, Docker pulls the hello-world image, runs it, and you see a message starting with “Hello from Docker!” That single command proves four things at once: the daemon is running, your user can reach the socket, image pulls work, and the runtime can start a container.

Check your versions while you’re here:

docker version
docker compose version

docker compose version should report v2.x.x. If that command works, the Compose plugin installed correctly and you’re set for multi-container setups.

Post-install verification

  • docker run hello-world prints the success message
  • docker version shows both Client and Server (the daemon is reachable)
  • docker compose version reports v2.x.x
  • You can run docker without sudo after re-login
  • systemctl is-enabled docker says 'enabled'

A quick first container

hello-world proves the plumbing, but it exits immediately. Run something that stays up so you can see Docker actually serving traffic. This starts Nginx on port 8080:

docker run -d --name web --restart unless-stopped -p 8080:80 nginx

Then check it from the server itself:

curl http://localhost:8080

You should get back Nginx’s default HTML. When you’re done, stop and remove it:

docker stop web
docker rm web

From here, most real workloads use more than one container — an app plus a database, say — which is exactly what Compose is for. Once you’ve got a few services running, putting a reverse proxy in front of them lets you host several apps on one server behind ports 80 and 443.

Common install problems

A handful of errors come up again and again on a fresh Ubuntu install.

permission denied while trying to connect to the Docker daemon socket — You haven’t logged out and back in after usermod -aG docker. Group changes need a new login session. Run newgrp docker for the current shell or reconnect your SSH session.

docker: command not found — The install didn’t complete, usually because apt update failed earlier on the repo. Re-check the keyring file and the docker.list repo entry, run apt update again, then reinstall.

Cannot connect to the Docker daemon — The daemon isn’t running. Start it with sudo systemctl start docker and check systemctl status docker for the reason it stopped.

A port conflict when starting a container — Something already holds the port you’re publishing. That’s common enough to have its own walkthrough: see how to fix “port is already allocated”.

Wrapping up

The official apt repository is the install method worth using on Ubuntu Server. It gives you current Docker Engine, the maintained Compose plugin, and behavior that matches every official doc — no snap confinement surprises, no stale docker.io build. The sequence is always the same: clear old packages, add the key and repo, install the docker-ce set, fix the group so you skip sudo, confirm it’s enabled on boot, and test with hello-world.

With Docker running, the natural next step is multi-container apps. Start with the Docker Compose beginner guide, and browse the rest of the Docker & Containers guides when you’re ready to go further.

Frequently asked questions

Should I install Docker from the Ubuntu repo or the snap package?

Use Docker's official apt repository. The version in Ubuntu's own repos (docker.io) lags behind and is community-maintained, and the snap build runs Docker in a confined sandbox that breaks bind mounts, socket paths, and networking in surprising ways. The official apt repo gives you current Docker Engine plus the Compose plugin and matches every official tutorial.

Do I need to install Docker Compose separately on Ubuntu?

No. When you install from the official repo, the docker-compose-plugin package comes with it, and you call it as docker compose (a space). The old standalone docker-compose binary is a separate Python tool that is now deprecated, so you don't need it on a fresh install.

Why can't I run docker without sudo?

By default the Docker daemon socket is owned by root, so only root or members of the docker group can talk to it. Add your user with sudo usermod -aG docker $USER, then log out and back in so the new group membership takes effect. Until you re-login, you'll still see permission denied errors.

Does Docker start automatically after a reboot?

On Ubuntu the apt package enables the docker service through systemd, so it starts on boot. You can confirm with systemctl is-enabled docker. If it says disabled, run sudo systemctl enable --now docker. Individual containers also need a restart policy like unless-stopped to come back after a reboot.

How do I uninstall Docker cleanly later?

Run sudo apt remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin, then sudo apt autoremove. Images, containers, and volumes live in /var/lib/docker and are not removed automatically; delete that directory manually only if you're sure you no longer need the data.

Which Ubuntu versions does the official Docker repo support?

Docker publishes packages for current LTS releases and recent interim releases, including 20.04, 22.04, and 24.04. The setup uses your distribution codename automatically, so the same steps work across versions as long as the release is still supported by Docker.

Sources & further reading

Official vendor documentation referenced while writing this guide.

SD

Sysadmin Desk

Infrastructure & Cloud

Hands-on guidance for infrastructure, virtualization, and containers — Hyper-V, VMware, Docker, and the day-to-day operations work that keeps environments running.

MCSA Guru provides independent, educational IT guidance. Microsoft, Windows, Windows Server, Microsoft 365, Exchange, and Microsoft Teams are trademarks of Microsoft Corporation; Docker is a trademark of Docker, Inc. MCSA Guru is not affiliated with or endorsed by Microsoft or Docker. Always test changes in a safe environment before applying them in production.

Related guides

Fixing something right now?

Jump straight into the guide library or search for the exact error or task you are dealing with.