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
| Task | Command (run in the app folder) |
|---|---|
| Follow logs | docker compose logs -f |
| Update to newer images | docker compose pull && docker compose up -d |
| Stop and remove the containers | docker compose down (named volumes are kept) |
| See disk used by Docker | docker system df |
| Remove unused images | docker 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
Written by
FimuroHost Team
Technical Writer