Skip to content

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.

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 repo and admin:org scopes. Fine-grained tokens and GitHub App auth aren’t supported yet.
  1. Get Runaway.

    The hub and agent both run from published images on GHCR. Clone the repository to get the Compose file and example env:

    Terminal window
    git clone https://github.com/<owner>/runaway.git
    cd runaway
  2. Generate the secrets.

    Runaway needs three secrets. Generate them straight into a .env file:

    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)"
    } >> .env
    • RUNAWAY_MASTER_KEY encrypts your GitHub tokens at rest.
    • BETTER_AUTH_SECRET signs your login session.
    • RUNAWAY_LOCAL_AGENT_TOKEN lets the bundled agent enroll itself.
  3. Start the stack.

    Terminal window
    docker compose -f docker-compose.example.yml up -d

    This pulls the images and starts the hub alongside a co-located agent that enrolls itself on first boot. Give it a few seconds to come up.

  4. Create your admin account.

    Open http://localhost:3000 and create the first account. Runaway is single-admin — once that account exists, signup closes.

  5. 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.

  6. Create a runner profile.

    A runner profile is the reusable shape of a runner — its image, resource limits, and pull policy. A workload references a profile, so create one before the workload. The defaults are a fine starting point.

  7. Create a workload.

    A workload is a pool of ephemeral runners. Pick the org, the runner profile, the routing labels, the runtime, the target hosts, and the pool size:

    • minRunners — the warm floor kept ready. Set it to 0 to 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.

  8. 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-hosted
    steps:
    - 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.

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.

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 as the fallback if a hook breaks.
  • Reuse caches between runs — every workload gets a persistent /cache volume. Point your package managers and browser binaries at it instead of round-tripping through GitHub’s Actions cache.
  • Isolate each runner — give each runner its own nested Docker daemon for github-hosted-style isolation, where every job gets a fresh inner daemon.