This was the second month in a row I hit the GitHub Actions minutes limit. And I'd already switched to Pro to get more - 3,000 minutes a month for private repos, at the time of writing. The bill creeps from the €4-ish I actually want to pay into double digits, and for what? Running the same builds I could run on hardware I already own.
So I decided it was enough. I moved all of it onto self-hosted GitHub Actions runners: one small cloud box for deploys, and a 16GB mini PC sitting in my living room for the heavy lifting. Billed CI minutes are now zero. Here's exactly how.
Where the minutes actually went
First thing I did was stop guessing and look at what was eating the budget. It wasn't the deploys. Push to main, build two images, ship - that's a couple of minutes a few times a day. Annoying but not 3,000-minutes-a-month annoying.
The killer was a nightly cron that runs a batch of build-and-boot tests. It's a few dozen small jobs, each one building an image and booting it to make sure nothing's quietly broken. They run on every relevant pull request, and once more every night to catch base images drifting underneath us.
Self-hosted runners don't burn billed minutes
Here's the thing most people miss when they look at that bill: GitHub only charges for GitHub-hosted runners. A .
Can I run a self-hosted runner on a home network behind NAT?
Yes. The runner makes an outbound connection to GitHub and polls for work. There's no inbound port to open, no router config, and it works behind carrier-grade NAT. That's what makes a living-room box viable.
Are self-hosted runners safe?
Only if you scope them right, and getting this wrong is genuinely dangerous. The thing to never do is attach a self-hosted runner to a repo that accepts pull requests from strangers - a fork PR can run attacker-controlled code on your hardware, steal secrets, and pivot into whatever network the box can reach. Researchers found GitHub itself, PyTorch, and Tensorflow exploitable this exact way. Keep the runner on private repos you control, run it as an unprivileged user, cap it with a resource slice, and never let the box that runs untrusted action code hold credentials to production.
Should I run everything on the self-hosted runner, or keep some jobs hosted?
Split by what the job needs. Heavy, frequent builds are the ones worth moving - that's where the minutes go. A job that wants massive parallelism (a big test matrix finishing in five minutes across dozens of ephemeral machines) can actually be a poor fit for one or two self-hosted agents. Move the minute-burners, leave the rest.
What's the difference between a self-hosted runner and a full CI platform like Jenkins or CDS?
Scale and babysitting. A self-hosted GitHub Actions runner is a single agent that plugs into the GitHub Actions you already use - your existing workflows run unchanged. A full self-hosted CI platform replaces GitHub Actions entirely and is a distributed system you operate yourself. For one person or a small team, the runner is almost always the right call.
SOCIAL SHARE CARD GENERATOR