4 min read Sep 26, 2026

How to Install Docker and Docker Compose on Your VPS

Install Docker Engine and the Compose plugin from Docker's official repository on Ubuntu, Debian, AlmaLinux or Rocky, run your first Compose app and keep ports safe behind the firewall.

FimuroHost Team

FimuroHost Team

Technical Writer

Share Article

Docker runs applications in containers: packaged bundles that include everything the app needs. It is the easiest way to run tools such as monitoring dashboards, databases, self-hosted apps or your own services on a VPS without installing their dependencies on the server itself. Docker Compose starts several containers together from one file.

Use Docker's own repository rather than the distribution's older docker.io packages, so you get current versions and the Compose plugin.

Which VPS is this for? These steps are for an Unmanaged VPS, where you log in as root and look after the server yourself. On a Managed VPS we take care of the operating system and server software, and you manage your websites in StackCP instead.

Before you start

  • Containers use RAM. A 1-core, 1 GB VPS can run a couple of light containers; for databases plus apps, choose 2 GB or more, or add swap.
  • Log in as your sudo user.

Ubuntu (22.04, 24.04)

# remove unofficial packages if any are installed
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)

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

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 -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Debian 12

Use the same commands, but replace both linux/ubuntu addresses with linux/debian and set the Suites line to $(. /etc/os-release && echo "$VERSION_CODENAME").

AlmaLinux and Rocky Linux 9

These systems may include Podman, which conflicts with Docker. Remove it unless you use it:

sudo dnf remove -y podman buildah runc
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

If the first command says no packages were marked for removal, that's fine. Accept Docker's GPG key if prompted; its fingerprint is published on Docker's install page.

Check the installation

sudo docker run --rm hello-world
docker compose version

To run Docker without typing sudo, add your user to the docker group and log out and back in: sudo usermod -aG docker $USER. Be aware that membership of this group is equivalent to root access, so only add trusted users.

Your first Compose app

This example serves a static site with Nginx, reachable only from the VPS itself on port 8080:

mkdir -p ~/apps/hello/html && cd ~/apps/hello
echo '<h1>Hello from Docker</h1>' > html/index.html
nano compose.yaml

Paste this into compose.yaml:

services:
  web:
    image: nginx:stable-alpine
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

Start it and test:

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

To publish it on your domain with HTTPS, put Nginx on the host in front of it as a reverse proxy (the same way as in the Node.js guide, using proxy_pass http://127.0.0.1:8080;) and add a certificate with Certbot.

Docker and your firewall

This catches many people out. A port published as "8080:80" is opened to the whole internet by Docker's own firewall rules, even if UFW or firewalld appears to block it. Always bind internal services to localhost ("127.0.0.1:8080:80") and only expose them through your reverse proxy. Never publish database ports such as 3306 or 5432 publicly.

Everyday commands

TaskCommand (run in the app folder)
Follow logsdocker compose logs -f
Update to newer imagesdocker compose pull && docker compose up -d
Stop and remove the containersdocker compose down (named volumes are kept)
See disk used by Dockerdocker system df
Remove unused imagesdocker image prune -a

Stop container logs filling the disk

By default container logs grow without limit. Create /etc/docker/daemon.json:

{
  "log-driver": "local",
  "log-opts": { "max-size": "20m", "max-file": "3" }
}

Then run sudo systemctl restart docker. The setting applies to containers created afterwards, so recreate existing ones with docker compose up -d --force-recreate.

Backups

Your data lives in volumes and bind-mounted folders, not in the containers. Back up the app folder (including compose.yaml) and dump databases with their own tools, for example docker compose exec db mariadb-dump -u root -p --all-databases > backup.sql. See How to Back Up Your VPS.

Need help?

If something about the VPS itself is not working (it won't start, you can't reach it, or you need console access, an upgrade or a reinstall), open a support ticket from your client area or message us on WhatsApp at 01818160926. Include your VPS IP address and what you have already tried so we can help faster.

Categories

FimuroHost Team

Written by

FimuroHost Team

Technical Writer