// self-hosted github actions orchestration
Your runners.
Your servers.
No middleman.
An open-source orchestrator for ephemeral GitHub Actions runners. Drop it on the VMs you already own, point it at your GitHub orgs, and get clean scale-to-zero CI — no Kubernetes cluster, no SaaS owning your compute.
BSL 1.1 · runs on any docker host · no inbound port
// why runaway exists
Self-hosting your runners is the right call. Every other way to do it makes you give something back.
Kubernetes wants a cluster. Hosted runner services want your compute back on their cloud. A
hand-rolled docker run --rm works —
until you need a second host, or until someone reaches for
restart: unless-stopped and your
runners quietly rot into stateful pets. Runaway is the missing middle: true-ephemeral runners, a
real dashboard, and multi-host orchestration, on hardware you already own.
// the hub
Every runner, every host, on one screen.
Connect your GitHub orgs, define scale sets, and the orchestrator does the rest — reconciling desired state against live Docker on every host, spawning and reaping runners so you never babysit a container. The dashboard is the cache; Docker is the truth.
// ephemeral by design
One job per runner. Then it’s gone.
Every runner is AutoRemove: true — it runs exactly one job, then the container is destroyed and replaced. No accumulated state, no writeable-layer bloat, no “why is this runner acting weird” at 2am. One reconciliation loop is the only thing that touches Docker, so crash recovery is just re-reading reality.
// multi-host
Add a box from anywhere. No inbound port.
Each host runs one small agent that dials out to the hub over an authenticated WebSocket — your homelab NAS, a Hetzner VM, a spare Mac mini. No open ports, no SSH, no Tailscale, no cluster. The hub holds no Docker socket at all; every host is reached through its own agent, NAT-friendly by construction.
// scale to zero
Scale clean to zero. Or hold a warm floor.
Runaway watches GitHub for queued and in-progress jobs and sizes each pool to demand. Set a floor of zero to scale all the way down between jobs, or keep a few warm so the next push doesn’t cold-start. Polling needs no public exposure; opt-in webhooks drop latency to near-instant when you want it.
// your hardware, your bill
Free CI on the machines you already own.
Self-hosted runner minutes are free — Runaway just makes them reliable and hands-off. The built-in cost view tallies what the same jobs would have cost on GitHub-hosted runners, so the spread is there at a glance, conservatively, against the lowest hosted tier.
// where it fits
Built for the gap between a bash script and a Kubernetes cluster.
| Runaway | ARC (k8s) | Hosted SaaS | DIY systemd | |
|---|---|---|---|---|
| Runs without Kubernetes | ✓ | — | ✓ | ✓ |
| Compute stays on your hardware | ✓ | ✓ | — | ✓ |
| True-ephemeral by default | ✓ | ✓ | ✓ | — |
| Multi-host from one UI | ✓ | ✓ | ✓ | — |
| Autoscale to zero | ✓ | ✓ | ✓ | — |
| Web dashboard + job history | ✓ | — | ✓ | — |
| No vendor control plane | ✓ | ✓ | — | ✓ |
| Setup measured in | minutes | days | minutes | hours |
vs / actions-runner-controller
The right tool at enterprise scale, but it runs on Kubernetes: you own a cluster, its upgrades, and the expertise to secure it. Runaway is a compose stack on a Linux box.
vs / hosted runner services
Actuated and RunsOn are fast, but each puts a vendor back in the loop — their control plane, or their product in your cloud. Runaway is the orchestration, open-source, on hardware you already have.
vs / systemd + docker run --rm
Works for one host in one person’s head. No UI, no autoscaling, no multi-host placement, no job history — and one restart: unless-stopped away from bloat. Runaway is that same primitive with orchestration on top.
// how it works
You declare the shape. The reconciler holds it.
Connect an org
Add a GitHub org or user with a classic PAT. Runaway validates scopes and discovers your repos.
Define a scale set
Pick a host (or many), a min/max, a runtime, and caches. That’s your desired state.
Push code
Runaway sees the queued job, spawns an ephemeral runner on a host with room, and GitHub dispatches to it.
Walk away
The job finishes, the container is destroyed, the pool returns to its floor. The loop never stops watching.
// built to be trusted
Open source, and architected like it.
BSL 1.1 → Apache 2.0
Source-available today; every release converts to Apache 2.0 after three years. Non-competitor use is granted now.
Socket-less hub
The hub holds no Docker socket. A hub compromise hands an attacker no root on your boxes — all compute lives on agents behind your NAT.
Secrets encrypted at rest
PATs and registry passwords are AES-256-GCM encrypted with a key that never leaves your env. Decrypted secrets are never logged.
Telemetry: opt-out, anonymous
Anonymous counts only — no org names, no repos, no IPs. One click to disable, and the full field list is published.
One-way trust
The hub can trigger an agent to update, but never ships it code. A future hosted control plane can’t push executables to your hosts. Ever.
Stop babysitting runners.
Drop it on a box you own. Two containers, one compose file, an admin account, and you’re taking jobs in about five minutes.
Clone the repo, generate three secrets, and bring up the stack:
RUNAWAY_MASTER_KEY=$(openssl rand -base64 32)
BETTER_AUTH_SECRET=$(openssl rand -base64 32)
RUNAWAY_LOCAL_AGENT_TOKEN=$(openssl rand -base64 32)
docker compose -f docker-compose.example.yml up -d
Open http://localhost:3000,
create your admin account, add an org + PAT, and create a scale set. The hub and a
co-located agent run as one compose stack.
Deploy on your own server straight from the repo — Coolify clones it, builds the hub image, and provisions TLS. No secrets to paste; no prebuilt image to trust. The dogfood path: Runaway runs on Coolify.