Docker has a reputation for being either magic or a headache, and the truth is it's mostly neither once you've run a couple of containers yourself. If you have a KVM VPS with full root, you can go from a blank box to a running, restart-on-reboot app in about ten minutes. Here's the honest, no-magic path.
Why Docker on a VPS
A container bundles your app and everything it needs into one image, so "works on my machine" becomes "works on the server too." You also get clean isolation (one app's mess doesn't touch another's), easy upgrades (pull a new image, recreate the container), and trivial teardown. The one real requirement: a KVM VPS, not an oversold container-on-a-container. You need your own kernel to run Docker properly — if a host doesn't say KVM anywhere, ask before you buy.
1. Install Docker
The official convenience script works across Debian, Ubuntu, and the RHEL family:
curl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable --now docker
docker --version
Add your user to the docker group so you don't have to sudo every command (log out and back in afterward):
sudo usermod -aG docker $USER
2. Run your first container
Prove it works with something disposable:
docker run --rm hello-world
Now run something real — a web server:
docker run -d --name web -p 80:80 --restart unless-stopped nginx
That's a live nginx on port 80. The flags matter: -d runs it in the background, --restart unless-stopped brings it back after a reboot, and -p 80:80 maps the host port to the container.
3. Use Compose for anything with more than one piece
Most real apps are an app plus a database. docker compose (built into modern Docker) describes the whole stack in one file. Create docker-compose.yml:
services:
app:
image: ghost:5
restart: unless-stopped
ports:
- "8080:2368"
environment:
database__client: mysql
database__connection__host: db
database__connection__user: ghost
database__connection__password: changeme
database__connection__database: ghost
depends_on: [db]
db:
image: mysql:8
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: changeme
MYSQL_DATABASE: ghost
MYSQL_USER: ghost
MYSQL_PASSWORD: changeme
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata:
Then:
docker compose up -d
Two containers, networked together, data persisted in a named volume that survives a compose down.
4. The habits that keep it healthy
- Persist data in volumes, never inside the container — containers are disposable, volumes are not.
-
Don't publish database ports (
3306,5432) to the public internet; let containers reach each other over the internal Docker network instead. -
Pin image versions (
mysql:8, notmysql:latest) so an upgrade is a decision, not a surprise. - Put a reverse proxy in front (Caddy or nginx) for TLS, instead of exposing app ports directly.
5. Updating and cleaning up
docker compose pull && docker compose up -d # upgrade in place
docker system prune -f # reclaim space from old images
Where to run it
Docker doesn't care which region your server is in — the same image runs identically in the EU or the US. If you need a box to try this on, overnight.host offers KVM VPS with full root access and honest specs (real KVM, SSD, NAT IPv4 disclosed before checkout), hosted in your region. Spin one up, run the hello-world above, and you'll have demystified Docker by lunch.
Top comments (0)