Appearance
Install Docker on Ubuntu 22.04, 24.04 and 26.04
Docker runs an application in a container together with everything it depends on. For a VPS this means most self hosted software starts with one command or one compose.yaml file, and removing it leaves the system clean. This guide installs Docker Engine, the Buildx plugin and the Compose plugin from Docker's own apt repository. The steps are the same on every supported Ubuntu LTS release, and the commands detect your release automatically.
Which Ubuntu versions are supported
Docker publishes packages for the following Ubuntu releases (checked against the Docker documentation in November 2026):
| Ubuntu release | Codename | Type | Docker repository |
|---|---|---|---|
| 26.10 | Stonking | Interim, 9 months of support | Supported |
| 26.04 | Resolute | LTS | Supported |
| 24.04 | Noble | LTS | Supported |
| 22.04 | Jammy | LTS | Supported |
On a server, pick an LTS release. Ubuntu 26.04 LTS is fully supported by Docker's repository, so there is no reason to wait with it. 24.04 and 22.04 keep working too. Older releases such as 20.04 are no longer in the list.
Docker builds packages for 64 bit systems only: amd64 (x86_64), arm64, armhf, s390x and ppc64le.
Distributions built on Ubuntu, such as Linux Mint, are not officially supported. They report their own codename, which the repository does not know. On Debian, follow install Docker on Debian instead, because Debian uses a different repository URL.
Before you start
- A VPS with Ubuntu 22.04, 24.04 or 26.04. Docker Engine itself needs little memory. The containers you run decide the rest. For one or two small apps, VPS-1 (1 vCPU, 1 GB) is enough. A typical stack of an app, a database and a reverse proxy is more comfortable on VPS-2 (1 vCPU, 2 GB) or VPS-3 (2 vCPU, 4 GB). See how much RAM your VPS needs and the pricing page.
- SSH access as root or as a user with sudo rights. See how to connect via SSH. The commands below use
sudo. As root you can leave it out.
Why not the docker.io package?
Ubuntu ships its own docker.io package. It is maintained by Ubuntu, usually lags behind Docker's releases, and Buildx and Compose come as separate Ubuntu packages with their own versions. Docker's repository gets new versions on the day of release and keeps Engine, CLI and plugins in step.
Step 1. Check your Ubuntu version
Make sure you are on a supported release and a 64 bit architecture:
bash
lsb_release -ds
. /etc/os-release && echo "$VERSION_CODENAME"
dpkg --print-architectureExample output:
text
Ubuntu 24.04.3 LTS
noble
amd64The codename (jammy, noble or resolute) is what the repository uses in Step 3. If it prints something that is not in the table above, stop here, because the repository will not have packages for it.
Install pending updates before you add new software:
bash
sudo apt update && sudo apt upgrade -yStep 2. Remove conflicting packages
Docker's packages conflict with several unofficial ones: docker.io, docker-compose, docker-compose-v2, docker-doc, docker-buildx, podman-docker, and the standalone containerd and runc (Docker ships its own containerd.io). This command removes whichever of them are installed and does nothing on a clean system:
bash
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)Images, containers and volumes under /var/lib/docker stay where they are.
Also check for Docker installed as a snap. Some Ubuntu installers offer it as an option:
bash
snap list dockerIf the snap is listed, it will compete with the apt version for the docker command. Move any data you need out of it first, then remove it:
bash
sudo snap remove --purge docker--purge skips the automatic snapshot, so the snap's images and volumes are gone afterwards. Leave the flag out if you want snapd to keep a snapshot.
Step 3. Add Docker's apt repository
Install the tools needed to fetch the key and save Docker's signing key:
bash
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.ascThen add the repository in the deb822 format. The Suites line fills in your codename and Architectures your CPU architecture:
bash
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 updateThe last apt update should list a line with download.docker.com and finish without errors. If it complains about keys or Signed-By, jump to Troubleshooting.
Step 4. Install Docker Engine and Compose
bash
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin| Package | What it is |
|---|---|
docker-ce | Docker Engine, the background daemon |
docker-ce-cli | The docker command |
containerd.io | The container runtime the daemon uses |
docker-buildx-plugin | docker buildx, the image builder |
docker-compose-plugin | docker compose, for multi container projects |
The package starts the daemon and enables docker.service and containerd.service at boot. Check it:
bash
sudo systemctl status dockerYou want to see active (running). Press q to leave the status view.
Need a specific version?
List what the repository offers with apt list --all-versions docker-ce, then install with docker-ce=VERSION docker-ce-cli=VERSION and the other packages as above. Most people should simply take the latest.
Step 5. Test the installation
bash
sudo docker run hello-worldDocker pulls a tiny test image, starts a container from it and prints Hello from Docker! followed by a short explanation of what just happened. The container exits right after. Now check the versions:
bash
docker --version
docker compose versionThe Compose command is docker compose with a space. The plugin replaces the old standalone docker-compose script, which you do not need to install.
Step 6. Run Docker without sudo
The Docker daemon listens on a Unix socket, /var/run/docker.sock, that belongs to root and the docker group. To use docker as your regular user, add the user to that group:
bash
sudo groupadd docker
sudo usermod -aG docker $USERThe package normally creates the group, so groupadd may say it already exists. That is fine. Group membership is read at login, so log out and connect again, or apply it to the current shell:
bash
newgrp docker
docker run hello-worldThe docker group is root access
Anyone in the docker group can start a container that mounts / from the host and change any file. Treat membership like sudo rights. If you need stronger isolation, Docker offers a rootless mode, which is beyond this guide.
Step 7. Start your first container stack
A quick check that publishing ports and Compose work together. Create a small project:
bash
mkdir -p ~/hello-nginx && cd ~/hello-nginx
nano compose.yamlyaml
services:
web:
image: nginx:stable
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"bash
docker compose up -d
curl -I http://127.0.0.1:8080
docker compose downHTTP/1.1 200 OK in the curl output means everything works. For a real project with a database, an .env file and health checks, continue with Docker Compose on Ubuntu.
Docker and the firewall
This catches many people on a new VPS. When a container publishes a port (-p 8080:80 or ports: - "8080:80"), Docker adds its own iptables rules, and traffic reaches the container even if UFW denies that port. UFW and firewalld simply do not see these packets.
Three habits keep you safe:
- Bind internal services to localhost:
127.0.0.1:8080:80. They stay reachable for a reverse proxy on the same server or through an SSH tunnel, but not from the internet. - Publish publicly only what must be public, usually ports 80 and 443 of the reverse proxy.
- Check what listens on all interfaces after starting something new:
bash
sudo ss -tlnpLines with 0.0.0.0:PORT or [::]:PORT are open to the world. If you need real filtering in front of containers, Docker expects the rules in the DOCKER-USER iptables chain. For the basic server firewall, see secure your VPS with UFW and fail2ban.
Limit the size of container logs
By default Docker keeps container output in JSON files without a size limit. A chatty container can fill the disk in a few weeks. Set a limit for all containers in /etc/docker/daemon.json:
bash
sudo nano /etc/docker/daemon.jsonjson
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}bash
sudo systemctl restart dockerThe setting applies to containers created after the restart. Existing ones keep their old settings until you recreate them, for example with docker compose up -d --force-recreate.
How to update Docker
Docker installed from the repository updates through apt like every other package. A normal system upgrade includes it:
bash
sudo apt update && sudo apt upgradeTo update only the Docker packages:
bash
sudo apt update
sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginThe upgrade restarts the daemon, so running containers stop for a few seconds. Containers with a restart policy such as unless-stopped come back on their own. Plan updates for a quiet moment on production servers. If you have unattended-upgrades enabled, note that by default it only installs Ubuntu security updates, not packages from Docker's repository.
Updating Docker does not update your images. That is a separate step per project, covered in Docker Compose on Ubuntu.
Troubleshooting
Permission denied on /var/run/docker.sock
text
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sockThe wording differs slightly between Docker versions, but it always mentions permission denied and docker.sock. Your user is not in the docker group yet, or the current session started before you added it. Check:
bash
groupsIf docker is missing from the list, run the commands from Step 6, then log out and back in. Do not fix this with chmod 666 /var/run/docker.sock: it gives every local user root access and resets after a restart anyway.
A related warning, Error loading config file: /home/USER/.docker/config.json ... permission denied, appears when you ran docker with sudo before and root now owns ~/.docker. Give the folder back to your user:
bash
sudo chown "$USER":"$USER" "$HOME/.docker" -R
sudo chmod g+rwx "$HOME/.docker" -RCannot connect to the Docker daemon
text
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?The client works, but the daemon is not running or failed to start. Start it and read why it stopped:
bash
sudo systemctl start docker
sudo systemctl status docker
sudo journalctl -u docker --no-pager -n 50Common causes in the log are a syntax error in /etc/docker/daemon.json (one missing comma is enough) and a full disk (df -h /var/lib/docker). If the DOCKER_HOST environment variable is set in your shell, the client looks for the daemon elsewhere. Check it with echo $DOCKER_HOST and unset DOCKER_HOST if it should not be there.
Docker from snap and apt at the same time
Symptoms: containers you started disappear, docker ps shows different results with and without sudo, or paths like /var/snap/docker show up in errors. Check which binary runs:
bash
which -a docker
snap list dockerOnly /usr/bin/docker should be listed. If /snap/bin/docker appears, remove the snap as shown in Step 2, then run hash -r so the shell forgets the old path.
NO_PUBKEY or "is not signed" during apt update
text
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY ...A similar message is The repository ... is not signed. In both cases apt cannot use the key for Docker's repository. Usually the key download failed or the file is not readable. Fetch it again and check the permissions:
bash
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
ls -l /etc/apt/keyrings/docker.asc
sudo apt updateConflicting values set for option Signed-By
text
E: Conflicting values set for option Signed-By regarding source https://download.docker.com/linux/ubuntu/ noble: ...The repository is defined twice with different keys. This happens on servers that followed an older guide, which created /etc/apt/sources.list.d/docker.list. Keep the new docker.sources file and delete the old one:
bash
ls /etc/apt/sources.list.d/ | grep -i docker
sudo rm /etc/apt/sources.list.d/docker.list
sudo apt updateUnable to locate package docker-ce
text
E: Unable to locate package docker-ce
E: Package 'docker-ce' has no installation candidateapt does not see Docker's repository. Either Step 3 was skipped, apt update was not run after it, or the codename in the repository file is wrong. Look at the file:
bash
cat /etc/apt/sources.list.d/docker.sourcesThe Suites: line must be jammy, noble, resolute or another release from the table at the top. An empty value or the codename of a derivative distribution leads to errors like does not have a Release file.
docker: 'compose' is not a docker command
text
docker: 'compose' is not a docker command.The Compose plugin is missing. With Docker's repository set up, install it:
bash
sudo apt install docker-compose-pluginThe opposite case is docker-compose: command not found. That is the old Compose v1 command. You do not need it: write docker compose instead. Migration from v1, and the case where Docker came from Ubuntu's docker.io package, are covered in Docker Compose on Ubuntu.
Everyday commands
| Task | Command |
|---|---|
| List running containers | docker ps |
| List all containers, including stopped | docker ps -a |
| Follow a container's logs | docker logs -f NAME |
| Open a shell in a container | docker exec -it NAME sh |
| Disk usage of images, containers and volumes | docker system df |
| Remove unused images | docker image prune -a |
For Compose projects there is a separate Docker Compose commands cheat sheet.
Data that should survive a container belongs in volumes or bind mounts, and those need backups like any other data. See how to back up your VPS.
FAQ
Is Docker free on Ubuntu?
Yes. Docker Engine, the CLI and the Compose and Buildx plugins are open source and free to use on servers, including commercial use. The paid subscriptions are for Docker Desktop and Docker Hub features, which a Linux server does not need.
Should I use the official script from get.docker.com?
The convenience script at get.docker.com sets up the same repository and installs the same packages in one go. It is handy for throwaway test machines. On a server you keep, the manual steps above are easier to understand and to repeat. Either way, later updates come through apt. Do not run the script again to upgrade.
Does Docker work on Ubuntu 26.04 LTS?
Yes. Ubuntu 26.04 "Resolute" is on Docker's list of supported releases, and the commands in this guide work on it without changes.
How do I check that Docker starts after a reboot?
bash
systemctl is-enabled dockerIt should print enabled. Containers come back only if they have a restart policy, for example restart: unless-stopped in Compose or --restart unless-stopped with docker run.
How much RAM does Docker need?
Docker itself needs very little. What counts is the sum of your containers. A small web app may need 50 to 200 MB, a database a few hundred MB more. If memory gets tight, check docker stats to see which container uses what.
How do I remove Docker completely?
Removing the packages, images, volumes and repository is described step by step in how to uninstall Docker.
Is the docker group a security risk?
It is equal to root access on that server. That is acceptable for your own admin user, but do not add service accounts or other people you would not give sudo to.
Summary
Docker Engine, Buildx and Compose are installed from Docker's repository and update with apt like the rest of the system. You can run containers without sudo, keep published ports from bypassing the firewall and cap log growth. Next steps: build a real multi container project in Docker Compose on Ubuntu, or deploy something useful right away, such as Uptime Kuma, n8n, a TeamSpeak 6 voice server or the Coolify platform.