Skip to main content

Install Docker and Docker Compose on Ubuntu

Docker runs applications with all their dependencies in containers, and Docker Compose starts several containers (for example web, database and cache) from one compose.yaml file. In this tutorial you install Docker Engine and the Compose plugin from Docker's official repository (Ubuntu's own package is older), run a sample service, and learn to publish ports without leaving them open by accident.

Prerequisites​

  • A cloud server or VPS with Ubuntu 24.04 or 22.04
  • A user with sudo (first SSH login and hardening)
  • At least 1 GB of RAM for light work; for several services a bigger plan or swap
Servers in Iran

download.docker.com and Docker Hub restrict access from Iranian IPs, and you may get 403 Forbidden. On servers in Iranian data centers, use a local mirror of the repository and registry, or create the server in a data center outside Iran.

1. Remove old or conflicting packages​

If you installed Docker from Ubuntu's repository before, remove it (packages that are not installed only print a message):

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove -y $pkg
done

Existing images and volumes in /var/lib/docker are kept.

2. Add Docker's official repository​

sudo apt-get update
sudo apt-get 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

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-get update

These commands detect the release name themselves (noble for 24.04, jammy for 22.04).

3. Install Docker Engine and Compose​

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

The Docker service is running after install and starts on boot. Check:

sudo systemctl is-enabled docker
sudo docker run --rm hello-world
docker compose version
note

Compose v2 is a plugin and runs as docker compose (with a space), not docker-compose.

4. Run Docker without sudo (optional)​

sudo usermod -aG docker $USER

Log out of SSH and back in, then try docker ps without sudo.

danger

Members of the docker group effectively have root access to the server. Only add users you would give root.

5. Your first Docker Compose project​

mkdir -p ~/hello && cd ~/hello
cat > compose.yaml <<'EOF'
services:
web:
image: nginx:alpine
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
EOF

docker compose up -d
docker compose ps
curl -I http://127.0.0.1:8080

HTTP/1.1 200 OK means the container works. See logs with docker compose logs -f and stop the service with docker compose down.

restart: unless-stopped brings the container back after a server reboot.

6. Docker and the firewall​

Docker creates its own iptables rules for published ports, and those rules are evaluated before ufw. So ports: - "8080:80" opens port 8080 on every IP of the server, even if ufw blocks it.

Safe options:

  • Publish ports only on 127.0.0.1 (as in the example above) and put a reverse proxy such as Nginx in front.
  • For server-to-server traffic, publish the port on the private network IP, for example "10.0.1.10:5432:5432".
  • Use the Arianet cloud firewall; it runs outside the server and Docker cannot bypass it.

Container logs grow without limit by default and can fill the disk. The local driver keeps logs compressed and rotated:

sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"log-driver": "local"
}
EOF
sudo systemctl restart docker

This only affects containers created from now on; recreate your projects with docker compose up -d --force-recreate.

Install at server creation​

In Arianet Cloud you can install Docker automatically when creating a server, in the "Startup script (cloud-init)" step (or --user-data-file in the CLI and user_data in Terraform). This example uses Docker's convenience script, which is fine for testing; for production prefer the repository method above:

#cloud-config
runcmd:
- curl -fsSL https://get.docker.com | sh

Common errors​

ErrorFix
permission denied while trying to connect to the Docker daemon socketUse sudo, or add the user to the docker group and log in to SSH again.
403 Forbidden on apt-get update or docker pullAccess restriction from Iran; see "Servers in Iran" above.
toomanyrequests: You have reached your pull rate limitDocker Hub's anonymous pull limit. Run docker login or use another registry.
bind: address already in useAnother service has the port: sudo ss -tlnp | grep 8080.
Disk fulldocker system df shows usage; docker system prune removes unused images and containers. For a lot of data, attach a separate volume.

Next steps​

Create your server​

Create an Arianet cloud server to run your containers; it is billed hourly and you delete it whenever you no longer need it. In the Arianet panel, go to Cloud server / Cloud Computing → New server, pick Ubuntu 24.04 and put the cloud-init example above in the startup script.