How to install Docker and Compose on Ubuntu, Debian and AlmaLinux from the official repository, run an application from compose.yaml, avoid opening a port past the firewall, and stop logs filling the disk.
Contents
Docker runs programs in containers — together with everything they need, separate from the rest of the system. It is best to install it from Docker’s own repository: the versions are current and Compose comes with it. Docker is also available in the operating systems’ own repositories, but the versions there are older.
Ubuntu and Debian
Commands for Ubuntu:
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
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
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginFor Debian, use the same commands, but write debian instead of ubuntu in the two URLs. The Docker service starts by itself and will start at boot.
AlmaLinux
sudo dnf install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now dockerThe first time you install, dnf asks you to confirm the repository key — its fingerprint should be 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35.
Checking the installation
sudo docker run --rm hello-world
docker --version
docker compose versionIf you see “Hello from Docker!”, everything is working.
To avoid typing sudo every time, add yourself to the docker group and log in again:
sudo usermod -aG docker $USERdocker group can get root rights without a password. Only add people you would also trust with sudo.Compose: an application in one file
Compose describes several containers, their settings and their data in a single file. Here is an example: WordPress with a MariaDB database. Create a directory, for example /opt/wordpress, and in it a file called compose.yaml:
services:
db:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_DATABASE: wp
MARIADB_USER: wp
MARIADB_PASSWORD: strong-password
MARIADB_RANDOM_ROOT_PASSWORD: "1"
volumes:
- db:/var/lib/mysql
wordpress:
image: wordpress:6
restart: unless-stopped
depends_on:
- db
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: strong-password
WORDPRESS_DB_NAME: wp
ports:
- "127.0.0.1:8080:80"
volumes:
- wp:/var/www/html
volumes:
db:
wp:Start and manage it from that directory:
| Command | What it does |
|---|---|
| docker compose up -d | downloads the images, then creates and starts the containers |
| docker compose ps | shows what is running |
| docker compose logs -f wordpress | shows the container’s log; press Ctrl+C to exit |
| docker compose pull && docker compose up -d | updates the images and recreates the containers |
| docker compose down | stops and removes the containers; the data in the volumes stays |
restart: unless-stopped — the containers start again by themselves after the server reboots. The data is kept in volumes (volumes): you can delete and recreate the containers without losing the database or the website files. Volumes are stored in /var/lib/docker/volumes, and you should include them in your backups.
Ports and the firewall
The line "127.0.0.1:8080:80" publishes the container’s port 80 only on the server’s internal address, so it cannot be reached from outside. The site is served to the outside world by nginx on the server itself, which also handles the free certificate: Let’s Encrypt certificate: certbot. The nginx configuration:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}"8080:80" or -p 8080:80, Docker opens the port to the whole internet, bypassing ufw and firewalld: it adds its own rules ahead of the firewall’s rules. This is a common way for databases and admin panels to end up on the internet by accident. Publish on 127.0.0.1 everything that should not be visible from outside.Container logs
Docker saves everything a container outputs to a file, and by default that file grows without limit — in time it can fill the whole disk. Limit its size by creating /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}and restart Docker: sudo systemctl restart docker. The setting applies to new containers — recreate existing ones with docker compose up -d --force-recreate.
Disk space
docker system df # how much space images, containers, volumes and cache take
docker image prune -a # remove images that no container usesFor more on what is safe to clear, see the article Disk full.
Didn’t find the answer? Ask our support team — we’ll help.