2026 — present
Scalable self-hosted GitHub Actions runners
Author / Open Source
Impact
Scaling from 1 to N runners becomes changing a number in the command, not editing a YAML file with N copy-pasted blocks — and a crash no longer leaves a ghost runner occupying a slot on GitHub.
The problem
Declaring N self-hosted GitHub Actions runners by hand means N identical
services copy-pasted into a docker-compose.yml. On top of that, a crash or
a redeploy can leave a container registered on GitHub as available even
though it no longer exists — a "zombie" runner GitHub keeps trying to use.
The approach
A single Docker Compose service, parameterized with the repo URL, scales
with docker compose up --scale github-runner=N. Combined with an
EPHEMERAL=true mode, each runner registers for a single job and
deregisters itself once it's done, which solves the zombie runner problem at
the root. Built to avoid depending on GitHub-hosted runners when the job
needs a specific environment, or simply to avoid paying for CI minutes on
repos with heavy builds.
Result
Scaling from 1 to N runners becomes changing a number in the command, not editing a YAML file with N copy-pasted blocks — and a crash no longer leaves a ghost runner occupying a slot on GitHub.