How to install Docker and Docker Compose on Ubuntu 24.04
This guide walks through installing Docker Engine and the Compose v2 plugin on Ubuntu 24.04 using Docker's official apt repository, which is the method Docker itself supports and keeps patched. It is written for anyone running their own VPS or dedicated server who wants a clean setup without snap packages or curl-into-shell scripts. By the end you will have a working two-container stack and will know where its data actually lives on disk.
What you need before starting
You need Ubuntu 24.04 (Noble) with a non-root user that has sudo rights, plus outbound internet access. Docker Engine itself is lightweight, but the containers you run on top of it are not. For experiments, 1 vCPU and 1 GB of RAM will boot, but for anything you intend to keep running, 2 vCPU and 4 GB of RAM is a comfortable minimum: enough for a web application, a database, and the occasional image build without hitting swap. Plan at least 20 GB of disk, because images and build cache accumulate faster than most people expect.
If the server ever had unofficial Docker packages installed, remove them first so they do not conflict with the official ones:
sudo apt remove docker.io docker-doc docker-compose podman-docker containerd runc
It is fine if apt reports that none of these are installed.
Add the official Docker apt repository
Ubuntu's own docker.io package lags several versions behind and does not include Compose v2. The official repository gets security fixes within days of release, which matters for a daemon that runs as root. First install the prerequisites and Docker's signing 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
Then add the repository itself and refresh the package index:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update
Install Docker Engine and Compose v2
One command installs the engine, the CLI, containerd, and the two plugins you want: Buildx and Compose v2.
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
The service starts and enables itself on boot automatically. Verify both parts:
sudo systemctl status docker sudo docker run hello-world docker compose version
The hello-world container pulls a tiny image, prints a confirmation message, and exits. Note that Compose v2 is a subcommand: docker compose with a space, not the old docker-compose binary.
Run Docker without sudo
By default only root can talk to the Docker socket. Add your user to the docker group so you can drop the sudo prefix:
sudo usermod -aG docker $USER newgrp docker docker run hello-world
newgrp applies the group in the current shell; new SSH sessions pick it up automatically. One honest caveat: membership in the docker group is effectively root access on that machine, because a container can mount the host filesystem. Only add accounts you would trust with root.
A realistic Compose file: web app plus database
Compose describes a multi-container stack in one YAML file. Here is a small but production-shaped example: WordPress with a MariaDB backend, each in its own container, with persistent named volumes.
mkdir -p ~/myapp cd ~/myapp nano docker-compose.yml
services:
web:
image: wordpress:6.5
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: change-me
depends_on:
- db
volumes:
- wp_data:/var/www/html
restart: unless-stopped
db:
image: mariadb:11
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wp
MARIADB_PASSWORD: change-me
MARIADB_ROOT_PASSWORD: change-me-too
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
volumes:
wp_data:
db_data:
The web container reaches the database simply as hostname db: Compose puts both services on a private network with DNS. Start and inspect the stack:
docker compose up -d docker compose ps docker compose logs -f web
docker compose down stops and removes the containers but keeps the volumes, so your data survives restarts and image upgrades.
Where your data actually lives
Named volumes are directories managed by Docker under /var/lib/docker/volumes/. For the example above:
docker volume ls docker volume inspect myapp_db_data
Anything written inside a container outside a volume disappears when the container is removed. Two rules prevent most data loss:
- Put databases and uploads on named volumes or bind mounts, always.
- Never run
docker compose down -vcasually: the-vflag deletes the volumes along with the containers.
For backups, dump the database with the vendor tool (for example mariadb-dump executed via docker compose exec db) rather than copying live database files.
Cleanup, sizing, and next steps
Old images, stopped containers, and build cache eat disk quietly. Check usage and clean up periodically:
docker system df docker system prune docker system prune -a
Plain prune removes stopped containers, dangling images, and unused networks. The -a variant also deletes every image not used by a running container, which means the next deploy re-pulls them. Neither touches volumes unless you explicitly add --volumes, so treat that flag with the same caution as down -v.
On sizing: the stack above idles at roughly 500 MB of RAM, and memory pressure, not CPU, is usually what kills small Docker hosts. If you are picking a server for this, a plan with 2 vCPU and 4 GB of RAM, such as our NVMe VPS in Riga, gives the stack and the host OS room to breathe, and you can resize upward later as containers multiply.