Before you start
Use a fresh or well-understood Ubuntu 24.04 LTS or AlmaLinux 9 VPS with a non-root sudo account and a working firewall. Docker needs a 64-bit system and runs comfortably on 2 GB of memory for a few small containers; images and volumes use disk, so check free space first.
Install Docker from Docker's own repository rather than the distribution package. The distribution packages are older and use different names, which makes official instructions harder to follow. Remove any conflicting packages only if you installed them earlier and have no containers you need.
cat /etc/os-release
df -h /
docker --version 2>/dev/null || echo "Docker is not installed"Ubuntu: add the repository and install
Add Docker's signing key and package source, then install the engine, command-line tool, container runtime, Buildx and the Compose plugin. The source line uses your release codename, so it works for the installed Ubuntu version.
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
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginAlmaLinux: add the repository and install
AlmaLinux is binary-compatible with RHEL, and Docker's CentOS repository is commonly used on it. Add the repository, install the same packages and start the service. Accept the Docker signing key only if the fingerprint shown matches the one in Docker's documentation.
sudo dnf install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now dockerTest the installation
Run the small hello-world image with sudo. It downloads, starts, prints a message and exits. Then confirm Compose is available. Docker Compose v2 is a plugin, so the command is docker compose with a space, not docker-compose.
sudo docker run --rm hello-world
sudo docker compose version
sudo systemctl is-enabled dockerDecide whether to add your user to the docker group
Members of the docker group can control Docker without sudo, but that is equivalent to root access on the server, because a container can mount any part of the filesystem. Add your user only if that matches who uses this account. Otherwise keep using sudo.
Group membership applies after you log out and in again.
sudo usermod -aG docker "$USER"
# log out, log in, then:
docker run --rm hello-worldRun a first Compose project
Create a project directory with a compose.yaml file. This example runs the Nginx web server and publishes it on port 8080 of the loopback address only. The 127.0.0.1 prefix matters: it keeps the port private to the server, and you reach it through a reverse proxy or an SSH tunnel.
mkdir -p ~/demo && cd ~/demo
cat > compose.yaml <<'EOF'
services:
web:
image: nginx:stable
ports:
- "127.0.0.1:8080:80"
restart: unless-stopped
EOF
sudo docker compose up -d
curl -I http://127.0.0.1:8080sudo docker compose downThe published-port firewall trap
Docker adds its own firewall rules for published ports. A port published as "8080:80" is reachable from the internet even if UFW or firewalld says it is closed, because Docker's rules are evaluated before them. Publish services as 127.0.0.1:PORT:PORT unless you intend them to be public, and put a reverse proxy in front of anything that should be reachable.
Check what is actually listening after every change. Anything bound to 0.0.0.0 or [::] is reachable from outside unless something else blocks it.
sudo ss -lntp
sudo docker ps --format "table {{.Names}}\t{{.Ports}}"Official documentation
These upstream references provide more detail on the commands and workflows in this guide.