Why Docker on a VPS?
Docker lets you package applications with all their dependencies into portable containers. On a VPS, this means:
- Consistent environments — no "works on my machine" problems
- Easy deployments —
docker compose upand you're live - Isolation — each app runs in its own container, can't interfere with others
- Reproducibility — your entire stack is defined in code
Installing Docker on Ubuntu 24.04
The official Docker installation for Ubuntu:
# Remove old versions
sudo apt remove docker docker-engine docker.io containerd runc
# Add Docker's official GPG key
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Post-Installation
Add your user to the docker group so you don't need sudo:
sudo usermod -aG docker $USER
newgrp docker
Verify:
docker run hello-world
Essential Docker Commands
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# View container logs
docker logs <container_name>
# Execute a command in a running container
docker exec -it <container_name> bash
# Stop/start/restart a container
docker stop <name>
docker start <name>
docker restart <name>
# Remove unused images/containers/volumes
docker system prune -a
Docker Compose: The Real Power
For anything beyond a single container, Docker Compose is how you define multi-service applications.
Example docker-compose.yml for a Next.js app with PostgreSQL:
version: "3.8"
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
- db
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
pgdata:
Deploy with:
docker compose up -d
Resource Management on Hetzner
On a CPX42 (8 vCPU, 16GB RAM), you can comfortably run:
- 5-10 web applications
- 2-3 databases
- Coolify management platform
- Mailcow email stack (if configured correctly)
Monitor resource usage:
docker stats
Best Practices
1. Always use named volumes for persistent data
2. Never store secrets in Dockerfiles — use environment variables or Docker secrets
3. Pin image versions — use postgres:16 not postgres:latest
4. Use multi-stage builds to keep images small
5. Set resource limits with deploy.resources.limits
Next Steps
Docker is the foundation for everything else — Coolify uses it, Mailcow uses it, and most modern applications ship with Dockerfiles.
Our complete VPS guide covers Docker in the context of a full production stack, including networking, volume management, and integration with Coolify and Mailcow.
Want the Complete Setup Guide?
This blog post covers the basics. Our premium guide includes step-by-step commands, exact configurations, and the solutions to every gotcha we encountered.