Skip to content
DnsLister Forum

Where domain hunters compare notes

git push now deploys to my homelab VMs

I run a few Docker VMs on one box at home (KVM/libvirt). For a while every deploy was the same ritual: SSH in, git pull, docker compose up -d --build, then go click around the Cloudflare dashboard to add a hostname. I kept forgetting a step.

So now it works like this:

  1. I git push to GitHub, like always.
  2. On the VM, a cron job runs every 2 minutes, does git fetch with a read-only deploy key, and only if the branch moved it runs docker compose up -d --build. Pushes that only touch docs or the Android folder are ignored.
  3. cloudflared on one VM keeps an outbound tunnel open. Cloudflare maps app.mydomain.com to vm:port. Nothing is open on my router.

The first time, one command sets it all up: creates the deploy key, clones the repo on the VM, copies .env files over SSH (never committed), installs the cron job, adds the tunnel route and DNS record, then checks the URL answers.

hl deploy ./myapp --route myapp=3100 --watch 

Live example (a tiny page that shows its own deploy info): https://hello.voypalante.com

The hardware side

  • One cheap desktop: AMD Athlon 3000G (2 cores, 4 threads, the one with Vega graphics), Biostar B450MH board, 16 GB DDR4-2666 (2×8), onboard gigabit Ethernet. Storage is all ZFS: a 1 TB Samsung NVMe (system), a 2 TB drive and a 16 TB drive. No GPU, no rack, it sits in a corner.
  • 3 VMs on KVM/libvirt, each with Docker. The busiest one has 2 vCPU and 2 GB RAM and runs a journal app, a couple of side projects and this hello page. Load average sits around 0.1.
  • One VM runs cloudflared for the whole lab; the others don't need to know about Cloudflare.
  • Backups: ZFS snapshots of the VMs, two restic repos, and an off-site rsync. GitHub is also an off-site copy of every app's source.
  • Real limit is my upload speed which is very slow in my area but I plan to upgrade my ISP contract sometime in the future.

How it compares:

Tool Runs where UI Needs on the server Container registry Open ports Cost
hl (this) Your VMs No, CLI only git, Docker, cron No, builds on the VM None (tunnel) $0 + domain
Coolify / Dokploy Your server Yes, nice one Their platform (a few containers) No Usually 80/443, or add a tunnel $0 self-hosted
CapRover Your server Yes Docker Swarm + their stack No 80/443 $0
Kamal Your server No Docker, kamal-proxy Yes 80/443 $0
Portainer + Watchtower Your server Yes Agent, Watchtower Yes, images built elsewhere Depends $0
Vercel / Netlify Their cloud Yes Nothing No n/a Free tier, then $20/user/mo
Railway / Render / Fly Their cloud Yes Nothing Optional n/a Usage based, a few $/mo and up

In summary:

  • You want a dashboard, logs in a browser, one-click databases: Coolify or Dokploy are great.
  • You want deploys within seconds of a push: hl polls, so it's up to 2 minutes. No webhooks, on purpose (no inbound anything).
  • You don't use GitHub or Cloudflare: hl is built around both.

What I like about doing it this way is that there is no deploy server to keep alive. If the box reboots, cron and Docker come back and that's it. The whole tool is one Python file with no dependencies, and every command has --json and --dry-run because I like to debug stuff.

Repo (MIT): https://github.com/faustinoaq/homelab-deploy

Happy to answer questions, or hear why this is a bad idea.

https://i.redd.it/4ytq43s5z9uh1.png

Source: r/homelab · by /u/UncommonSort

Leave a Reply

Your email address will not be published. Required fields are marked *