- On Ubuntu 22.04/24.04 and Debian 12, Docker Engine is installed from Docker's official repository as
docker-cewithdocker-compose-plugin, not as the distribution'sdocker.iopackage - that brings a current Engine and thedocker composecommand. - Docker publishes container ports through its own iptables rules around the UFW firewall: a port published as
8080:80is reachable from the internet even if UFW blocks it, so internal services should be published only on127.0.0.1. - By default Docker keeps container logs with no size limit; setting
max-size: 10mandmax-file: 3in/etc/docker/daemon.jsoncaps logs at 30 MB per container. - A user in the
dockergroup effectively has root on the server, so only your own administrator account should be added to that group. - Docker and Docker Compose run without restrictions on a KVM VPS; Docker itself is fine with 2 GB of RAM, and the containers determine the rest.
Step 1. Add the Docker repository and install the packages
The same commands work on Ubuntu and Debian: /etc/os-release fills in the distribution name and release. This is the official method from the Docker documentation:
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
sudo curl -fsSL "https://download.docker.com/linux/$ID/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/$ID ${UBUNTU_CODENAME:-$VERSION_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginStep 2. Check the installation
Run the hello-world test container and check the Compose version - both commands should finish without errors:
sudo docker run --rm hello-world
docker compose versionIf hello-world prints its greeting, the Engine works. The Docker service is already enabled at boot and will come back after a server reboot.
Step 3. Run without sudo
To stop typing sudo before every docker command, add your user to the docker group and log in over SSH again:
sudo usermod -aG docker $USER
# log out of SSH and back in, then:
docker psStep 4. A first Docker Compose project
Create a project directory and a compose.yaml file - the example runs nginx reachable only from the server itself on port 8080:
services:
web:
image: nginx:alpine
ports:
- "127.0.0.1:8080:80"
restart: unless-stoppeddocker compose up -d
docker compose ps
docker compose logs -frestart: unless-stopped brings the container back after a crash and after a server reboot - it needs no separate systemd service.
Docker and UFW: ports open around the firewall
Docker writes its own iptables rules for published ports, and they match before UFW rules do. A port published as 8080:80 is reachable from the internet even if UFW keeps it closed. So:
- publish internal services (databases, admin panels, APIs without auth) only on
127.0.0.1, as in the example above; - expose a single reverse proxy (nginx, Caddy, Traefik) on ports 80 and 443 and let it forward requests to containers - the HTTPS guide shows how to set up nginx with a free certificate;
- do not publish ports at all for containers that need no outside access - within one Compose project they reach each other by service name.
Step 5. Cap log size
By default Docker keeps container logs with no size limit, and a chatty container can fill the whole disk. Cap them at three 10 MB files per container. The setting applies to containers created after it - recreate existing ones with docker compose up -d --force-recreate.
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
EOF
sudo systemctl restart dockerHow to free disk space
Old images pile up after every update. The first command shows what takes the space, the second removes images no container uses:
docker system df
docker image prune -aAMD Ryzen 9, NVMe and DDoS protection in Germany, Finland and Poland. Pay with crypto or card.
FAQ
How is the docker.io package different from docker-ce?
docker.io is built by the distribution itself and is usually older. docker-ce comes from Docker's official repository with a current Engine and the Compose plugin; it is what the Docker documentation recommends.
Does Docker work on a Tihost VPS?
Yes. Servers run on KVM - a full virtual machine with its own kernel - so Docker, Compose and container networking work without restrictions.
Why is a container reachable from the internet even though UFW is closed?
Docker publishes ports through its own iptables rules, which match before UFW. Publish internal services on 127.0.0.1 or do not publish them at all.
What is the difference between docker compose and docker-compose?
docker-compose is the old standalone Python program and is no longer developed. docker compose (with a space) is a Docker CLI plugin installed by the docker-compose-plugin package.
How much memory does Docker need?
Docker itself is fine with 2 GB of RAM. The rest depends on your containers: several services with a database are more comfortable on 4-8 GB.