Quickstart
Runaway runs as a small Docker stack you drop on a Linux host: a hub (the orchestrator and web UI) and an agent (which drives your Docker daemon and runs the actual runner containers). This guide takes you from nothing to a runner picking up a job in about five minutes.
Before you start
Section titled “Before you start”You’ll need:
- A Linux host with Docker and the Compose plugin — a homelab box, a VPS, anything you control.
- A GitHub organization or personal account whose Actions workflows you want to run.
- A classic personal access token (PAT) with the
repoandadmin:orgscopes. Fine-grained tokens and GitHub App auth aren’t supported yet.
Install
Section titled “Install”-
Get Runaway.
The hub builds from source; only the agent ships as a prebuilt image. Clone the repository:
Terminal window git clone https://github.com/<owner>/runaway.gitcd runaway -
Generate the secrets.
Runaway needs three secrets. Generate them straight into a
.envfile:Terminal window {echo "RUNAWAY_MASTER_KEY=$(openssl rand -base64 32)"echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)"echo "RUNAWAY_LOCAL_AGENT_TOKEN=$(openssl rand -base64 32)"} >> .envRUNAWAY_MASTER_KEYencrypts your GitHub tokens at rest.BETTER_AUTH_SECRETsigns your login session.RUNAWAY_LOCAL_AGENT_TOKENlets the bundled agent enroll itself.
-
Start the stack.
Terminal window docker compose -f docker-compose.example.yml up -dThis builds and starts the hub alongside a co-located agent that enrolls itself on first boot. Give it a few seconds to come up.
-
Create your admin account.
Open http://localhost:3000 and create the first account. Runaway is single-admin — once that account exists, signup closes.
-
Connect a GitHub organization.
In the UI, add your organization (or personal account) and paste the classic PAT. Runaway validates it live and stores it encrypted at rest.
-
Create a scale set.
A scale set is a pool of ephemeral runners. Pick the org, the runner image, and the pool size:
minRunners— the warm floor kept ready. Set it to0to scale to zero between jobs.maxRunners— the ceiling Runaway scales up to under load.
Save it, and the reconciler spawns the pool within seconds. You’ll see the runners come online in the dashboard.
-
Run a workflow.
Point a workflow at your self-hosted pool and push it to a repo in the connected org:
jobs:build:runs-on: self-hostedsteps:- run: echo "running on Runaway"A runner picks up the job, runs it once, and is destroyed on completion — a fresh container takes the next one.
What you just built
Section titled “What you just built”A single hub now manages a pool of ephemeral runners on your own machine. Each runner is a
one-shot container (AutoRemove: true), so nothing accumulates between jobs. When the queue is
empty the pool can scale to zero; when work arrives it scales back up to maxRunners.
What’s next
Section titled “What’s next”You have a working single-host setup. From here you can:
- Add more hosts — run one agent on any other Docker machine and it dials out to the hub over an authenticated WebSocket. No inbound port, no SSH, no Tailscale.
- Cut scaling latency with webhooks — opt in per organization for a faster demand signal than polling, with polling kept as the automatic fallback.
- Reuse caches between runs — every scale set gets a persistent
/cachevolume. Point your package managers and browser binaries at it instead of round-tripping through GitHub’s Actions cache. - Isolate each runner — wrap runners in the sysbox runtime for github-hosted-style isolation, where every job gets a fresh inner Docker daemon.