Virteche
Guideschevron_rightServers

Servers · 8 min read · Updated

How to Run Docker and Docker Compose on a VPS

Docker packages an application with everything it needs, and Compose describes a whole stack — app, database, cache — in one file you can start with one command. On a VPS that makes self-hosting and deploying repeatable. Install it from Docker's own repository, run services with Compose, and deal with two defaults up front: published ports skip your firewall, and container logs grow until the disk is full.

1. Install Docker Engine and Compose

On Ubuntu (for Debian, replace ubuntu with debian in both URLs):

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

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$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-plugin
sudo docker run --rm hello-world

To run docker without sudo, add yourself to the docker group and log in again. Be aware that membership of that group is equivalent to root on the server.

sudo usermod -aG docker $USER

2. Cap Log Sizes Before You Start Anything

By default each container logs to a JSON file with no size limit. Switch the default to the local driver, which rotates and compresses, then restart Docker:

echo '{ "log-driver": "local", "log-opts": { "max-size": "20m", "max-file": "5" } }' \
  | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker

This applies to containers created from now on, which is why it comes first.

3. Describe a Stack with Compose

One folder per stack, with a compose.yaml in it:

mkdir -p ~/apps/whoami && cd ~/apps/whoami
nano compose.yaml
services:
  web:
    image: traefik/whoami
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"   # reachable only from the server itself
docker compose up -d
docker compose ps
curl http://127.0.0.1:8080
docker compose logs -f web

restart: unless-stopped brings the service back after a crash or a reboot.

4. Published Ports Skip UFW

This is the one that catches everyone. A mapping like "8080:80" listens on every address, and Docker inserts firewall rules for it that are checked before UFW's — so the port is open to the internet even if ufw status says otherwise. Two safe patterns:

  • Publish on 127.0.0.1 as above and put Nginx or Caddy in front for HTTPS — see hosting a website, step 6.
  • Publish without an address only for ports you genuinely want public, such as 80 and 443 on a proxy container.

sudo ss -tlnp shows what is listening on the server. To see what the internet can actually reach, test from another machine, for example nc -zv 203.0.113.10 8080.

The firewall on your server's page in the dashboard is applied outside the server, before traffic reaches it, so Docker's rules cannot bypass it. Allowing only the ports you mean to expose there is a dependable backstop.

5. Updating and Cleaning Up

cd ~/apps/whoami
docker compose pull          # fetch newer images
docker compose up -d         # recreate what changed
docker image prune -f        # drop the old images
docker system df             # what is using the disk

6. Back Up the Data, Not the Containers

Everything worth keeping lives in volumes or bind mounts, plus the compose files. Keep bind-mounted data under one folder (for example ~/apps), dump databases to files on a schedule, and send the lot off the server with Borg to a storage box.

Common Questions

  • Does Docker work on your VPS plans?

    Yes. Every VPS is a full KVM virtual machine with its own kernel, so Docker, Podman, Kubernetes distributions like k3s, and anything else that needs kernel features run exactly as they would on hardware.

  • Why can the internet reach a port I blocked in UFW?

    Docker writes its own firewall rules for published ports, and they are evaluated before UFW's. Publish ports on 127.0.0.1 and put a reverse proxy in front, or only publish ports you actually want open.

  • Should I use the apt docker.io package instead?

    It works, but it lags behind, and Compose is packaged separately (docker-compose-v2 on Ubuntu) and lags too. Docker's own repository gets you the current docker compose and timely security fixes.

  • How do I back up containers?

    Back up the data, not the containers: the named volumes or bind-mounted folders, plus your compose.yaml. Containers are rebuilt from images. Dump databases to a file first rather than copying their live data directory.

Full KVM virtual machines in Ashburn and Dallas — Docker, Compose and k3s run as they would on hardware.

See VPS plans

Keep Reading

All guides
Run Docker and Docker Compose on a VPS | Virteche Cloud