DEV Community

overnight.host
overnight.host

Posted on

Docker on a VPS - a beginner's guide to your first container

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

2. Run your first container

Prove it works with something disposable:

docker run --rm hello-world
Enter fullscreen mode Exit fullscreen mode

Now run something real — a web server:

docker run -d --name web -p 80:80 --restart unless-stopped nginx
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

Then:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

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, not mysql: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
Enter fullscreen mode Exit fullscreen mode

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)