CONTAINERS / STEP-BY-STEP

How to install Docker Engine on Ubuntu Server

Install Docker from its official repository, add the Compose plugin, and verify your container engine before hosting an application.

TEXT SIZE
Container services connected through Docker Engine illustration
What you’ll finish with

Docker Engine installed from Docker’s official Ubuntu repository, the Compose plugin available, and a successful test container.

This guide is for a clean Ubuntu Server system. Docker currently documents Ubuntu 26.04, 24.04, and 22.04 LTS among its supported versions. If this machine already runs containers, stop here and review your current installation and backups before replacing packages or changing the engine.

1. Check your Ubuntu installation

Complete the Ubuntu Server guide first, or confirm you have a supported release, internet access, and an account with sudo permissions.

Check Ubuntu and CPU architecture
cat /etc/os-release
dpkg --print-architecture

Use the actual output to choose the right installation instructions. This walkthrough follows the official Ubuntu APT-repository method. It is separate from Docker Desktop and does not use Ubuntu’s docker.io package.

On an existing installation, conflicting container packages can require migration or removal. Do not blindly uninstall them from a working server. Check Docker’s current prerequisites and make a migration plan first.

2. Add Docker’s repository and signing key

Install the tools needed to fetch the repository key, create the key directory, and make the key readable to APT:

Prepare the Docker repository key
sudo apt update
sudo apt install ca-certificates curl
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

Create the repository definition. The expressions below read your Ubuntu codename and package architecture rather than assuming a particular release. Paste the whole block, including the final EOF line, into a Bash shell:

Create the Docker APT source
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
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
EOF

This is the repository-based installation path documented by Docker. It keeps later engine updates in the normal APT workflow.

3. Install the engine and plugins

Refresh APT after adding the repository, then install the engine, container runtime, build plugin, and Compose plugin:

Install Docker Engine and plugins
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Check the service and command versions:

Check the engine and Compose
sudo systemctl status docker --no-pager
sudo docker version
sudo docker compose version

If the service is not active on this fresh install, start it with sudo systemctl enable --now docker and inspect any errors. Compose is invoked as docker compose with a space.

These examples keep sudo in Docker commands. Membership in the Docker group grants powerful access to the host; understand that tradeoff before allowing an account to control the engine without sudo.

4. Run a small test container

The official test image checks whether Docker can pull an image and run a container:

Verify Docker with hello-world
sudo docker run --rm hello-world

A successful run prints a greeting and an explanation of what the engine did. The --rm option removes the test container after it exits; the downloaded image can remain in the local cache.

Now check that no unexpected containers are running:

Inspect the running containers
sudo docker ps

This test does not publish a service port. If the pull fails, investigate DNS, internet access, repository connectivity, and the actual error message before changing container settings.

5. Understand ports before hosting a service

A running container is not automatically a reachable website. A published port connects a host address and port to a container port. Without a specified host address, Docker normally publishes to all host interfaces.

Binding a port to a particular LAN address narrows where it is published, but routing and firewall configuration still control who can reach it. Binding to 127.0.0.1 on a current Docker release makes it accessible through the host’s loopback interface. See Docker’s port-publishing guide for the details and older-version caveats.

UFW is not the container access policy

Docker’s published-port traffic can bypass ordinary UFW rules. Do not assume a host firewall rule makes a container private. Keep router port forwarding off for the local Jellyfin project and review Docker’s firewall guidance before changing exposure.

6. Troubleshoot before adding an application

ProblemUseful next check
APT cannot find Docker packagesCheck that docker.sources exists, its codename matches your supported Ubuntu release, and sudo apt update completed successfully.
Docker socket permission deniedUse the sudo docker … form shown here. Do not make the Docker socket world-writable.
The service will not startRead sudo journalctl -u docker --no-pager -n 80. Investigate the error rather than reinstalling repeatedly.
docker compose is missingConfirm docker-compose-plugin installed from the intended repository.
An image cannot be downloadedCheck the image name, DNS, internet connection, available disk space, and any registry error.

Once the engine and Compose checks work, you have the foundation for the Jellyfin guide. Keep application configuration and backups organized from the start.

Sources & further reading

The commands and examples in this guide are written for a generic installation. Consult the official documentation for release-specific changes.

NEXT STEPSet up Jellyfin with Docker Compose