guide · 6 min de lecture
Installing Docker
The official repository rather than Ubuntu's, the compose plugin, and the six commands that are enough to run a home lab.
Docker is what makes a home lab sustainable. Without it, installing six services means six ways to configure, six ways to update, and six chances to break the one next door. With it, each service lives in its own box, and one text file describes the whole thing.
This guide starts from a freshly installed Ubuntu Server — see Installing Ubuntu Server if that is not done yet. Ten minutes.
Do not take Ubuntu's
apt install docker.io works and installs a version packaged by Ubuntu, often
months behind, without the compose plugin. Docker's own repository takes five
more lines, once, and puts you on the project's own updates.
That is the only decision in this guide. The rest is mechanical.
Step 1 — Remove what is lying around
On a new machine this finds nothing. On a machine that has seen use, it avoids package conflicts whose error messages never name the cause:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 \
podman-docker containerd runc; do
sudo apt remove -y $pkg
done
Your data and images are untouched: they live in /var/lib/docker, which this
command does not remove.
Step 2 — Add Docker's repository
sudo apt update
sudo apt install -y 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
Then the repository itself:
sudo tee /etc/apt/sources.list.d/docker.sources <<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
sudo apt update
Two details that explain why this differs from most guides online:
- The file is a
.sources, not a line indocker.list. Docker moved to that format; both work, but following the current documentation beats following the 2022 one. - The
Suitesline does not hardcode your release: it reads it from/etc/os-release. On 26.04 that givesresolute.
If apt update complains it cannot find the repository, Docker has probably
not published for your Ubuntu release yet — common in the weeks after a release.
Check that your codename is listed at
download.docker.com/linux/ubuntu/dists.
As of 28 July 2026, resolute is there, for amd64 and arm64.
Step 3 — Install
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Five packages, two of which deserve naming:
docker-compose-pluginprovidesdocker compose, two words. The old hyphenateddocker-composewas a separate Python program, now retired. A guide that has you typedocker-compose upis over four years old, and the rest of its advice has aged the same way.docker-buildx-pluginbuilds images. You will not need it immediately; it is on the list because its absence produces baffling warnings on your first build.
Step 4 — Check
sudo docker run hello-world
Docker pulls a tiny image, runs it, prints a paragraph and stops. If you see it, everything is in place.
docker --version
docker compose version
The second command is the real test: it is the one that fails when the compose plugin is missing, and you only notice at the moment you need it.
Step 5 — Drop the sudo
By default only root talks to the Docker daemon. To avoid sudo on every
command:
sudo usermod -aG docker $USER
Log out and back in so the group membership is re-evaluated. An SSH session already open will not see it — the number one cause of "I ran the command and it still does not work".
One thing worth knowing, and Docker's own documentation says it: the docker
group is equivalent to root. Anyone who can start a container can mount any
directory of the machine into it. On a personal server with a single user that
is of no consequence; on a shared machine it is worth knowing before you add
someone to the group.
Step 6 — Your first docker-compose.yml
This site's builder hands you a ready-made file. Here is its mechanism, so you know what you are pasting.
One folder per stack:
mkdir -p ~/docker && cd ~/docker
nano docker-compose.yml
services:
example:
image: nginx:alpine
container_name: example
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./example/data:/usr/share/nginx/html
Four lines decide everything:
image— where the software comes from. Prefer an explicit version (nginx:1.29) overlatestfor anything you care about:latestmoves under you on the nextpull.restart: unless-stopped— the container comes back after a reboot, but not if you stopped it yourself. That is the value you want on an always-on server.ports—"8080:80"reads host:container. The first number is what you type in your browser, the second is what the software listens on inside its box. You only ever change the first.volumes—./example/datais a path on the machine, relative to the file's folder. Anything not in a volume disappears the first time the container is updated. It is the one mistake in this guide that costs data.
Then:
docker compose up -d
-d detaches: the command returns and the containers keep running. Without it,
closing the terminal stops everything.
The six commands that are enough
docker compose up -d # start, or apply a change to the file
docker compose down # stop and remove the containers
docker compose ps # what is running, in this folder
docker compose logs -f # logs, following — Ctrl+C to leave
docker compose pull # fetch newer images
docker stats # what it is consuming, live
Updating a stack is three commands in this order:
docker compose pull
docker compose up -d
docker image prune -f
The last one removes images nothing uses any more. Without it, a 250 GB system disk fills up in a year with versions nothing references — and the resulting error talks about a full disk, never about Docker.
What will happen to you, and what to do about it
permission denied on files in a volume. The container runs as a user
that is not you. Most images accept PUID and PGID in their
environment section: give them the output of id -u and id -g.
port is already allocated. Two services want the same host port. Change
the first number in ports, never the second. sudo ss -tulpn | grep 8080
says who holds it.
A container restarting in a loop. docker compose logs will say why. Nine
times out of ten it is a volume path that does not exist, or a required
environment variable that is missing.
The disk filling up. docker system df shows where. docker system prune -a cleans it — careful, -a also removes unused images, which you will have
to download again.
Next
Your services are running, but only from home. To reach them from outside there are two roads: open a port on your router, or use a tunnel that opens none — and the second is the one this site recommends.
Vidéo
Pi My Life Up installs Docker on Ubuntu from the official repository and runs a first container — the part where you see what the commands actually produce.
Rien n'est envoyé à YouTube tant que vous n'avez pas lancé la lecture. Ce site ne dépose aucun cookie qui lui soit propre.Regarder sur YouTube