An open API service indexing awesome lists of open source software.

https://github.com/muhac/actions-runner-pool

gharp — Ephemeral, autoscaling self-hosted GitHub Actions runners for personal accounts. Multi-repo, Docker-only, no Kubernetes.
https://github.com/muhac/actions-runner-pool

ci-cd devops docker github-actions github-app homelab self-hosted self-hosted-runner

Last synced: 1 day ago
JSON representation

gharp — Ephemeral, autoscaling self-hosted GitHub Actions runners for personal accounts. Multi-repo, Docker-only, no Kubernetes.

Awesome Lists containing this project

README

          

# 🪉 gharp — GitHub Actions Runner Pool

A self-hosted, Docker-based pool of ephemeral GitHub Actions runners.

> 🍴 **Dogfooded** — this repo's own CI was running on a gharp pool during development!

## ✨ Features

* 🔐 **Self-hosted** — no external service dependency
* ♻️ **Ephemeral runners** — one job per runner, clean environment every time
* ⚡ **Autoscaling** — runners are created on-demand from webhook events
* 📊 **Built-in dashboard** — inspect jobs and runners (with prometheus metrics), retry/cancel controls, and in-place credential rotation (webhook secret / pem / client secret) gated behind a `ALLOW_ADMIN_EDIT` kill-switch
* 📦 **Multi-repository, personal-account support** — share compute across repos (not supported natively by GitHub)

> 👉 **[Try the dashboard live](https://muhac.github.io/actions-runner-pool/demo/)** — same UI, mock data, no backend. Click Cancel / Retry to see how the dashboard reacts.

## 🚀 Quick Start

### 1. Run gharp

Pre-built multi-arch image: [`muhac/gharp`](https://hub.docker.com/r/muhac/gharp).

**Minimal `docker run`**

```bash
docker run -d --name gharp \
-p 8080:8080 \
-e BASE_URL=https://gharp.example.com \
-v /var/run/docker.sock:/var/run/docker.sock \
-v gharp-data:/data \
muhac/gharp:1
```

`BASE_URL` must be a public HTTPS URL GitHub can reach, terminating at
the container's port 8080 (above mapped to the host's 8080). See
[`docs/configuration.md`](docs/configuration.md) for the full env-var reference.

**Recommended — Docker Compose**

```bash
# copy docker-compose.yml from this repo, then:
BASE_URL=https://gharp.example.com docker compose up -d
```

See [`docker-compose.yml`](docker-compose.yml) for the full reference configuration
(workdir cleanup, host Docker socket forwarding for ephemeral runners,
runner-container log caps, and `ADMIN_TOKEN` passthrough — set the
token in `.env`).

### 2. Create the GitHub App

Open `${BASE_URL}/setup` and click **Create GitHub App**. gharp drives
the GitHub App Manifest flow and persists the credentials locally.

> ⚠️ **Don't rename the auto-generated App name on GitHub.**
> gharp creates the App as `gharp-`; renaming it changes the slug,
> which breaks the install link gharp renders on `/setup`.
> The webhook keeps working — only the install link goes stale.
> To fix, delete the App on GitHub and re-run `/setup`.

> ⚠️ **`BASE_URL` is sticky.** It's baked into the GitHub App's webhook
> and OAuth-callback URLs at `/setup` time. Changing it later won't
> reconfigure the App — gharp will log a `BASE_URL drift` warning at
> startup. To migrate, re-run `/setup` (creating a fresh App) or revert
> `BASE_URL` to the original value.

### 3. Install the App

Pick the repos (or "All repositories") you want runners for and submit.

> ⚠️ **Self-hosted runners + public repos = remote code execution.**
> GitHub [explicitly recommends against](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners)
> using self-hosted runners with public repositories: any contributor
> who can open a PR can run arbitrary code on your machine.
> Only install the App on **private** repos you trust,
> and run gharp on a **dedicated VM / cloud instance / homelab node**.
> gharp drops public-repo `workflow_job` webhooks by default. To opt in,
> set `ALLOW_PUBLIC_REPOS=true` for all public repos, or use
> `REPO_ALLOWLIST=owner/repo` to bypass the guard for selected public repos.

### 4. Add a workflow

```yaml
jobs:
build:
runs-on:
- self-hosted
steps:
- uses: actions/checkout@v4
- run: echo "hello from $(hostname)"

test:
runs-on:
- self-hosted
- "gharp-test-${{ github.run_id }}-${{ github.run_attempt }}"
steps:
- run: echo "tests from $(hostname)"
```

Every `workflow_job` whose `runs-on` set is fully covered by
`RUNNER_LABELS` (default `self-hosted`; `self-hosted` is implicit on
every self-hosted runner so you don't need to list it) or a configured
dynamic label prefix (default `gharp-`) will get a fresh runner. Jobs
requiring a label this pool doesn't advertise are dropped — see
[`docs/configuration.md`](docs/configuration.md).

For the full deployment guide (from-source build, docker compose,
volumes, upgrades, ops APIs, troubleshooting), see [`docs/deploy.md`](docs/deploy.md).

## 🤔 Why?

GitHub does **not support "user-level" runners**.

* Runners are scoped to: repository, organization, or enterprise

This makes it hard to:

* share a runner across multiple repositories
* use self-hosted runners efficiently in personal accounts
* scale runners dynamically

💡 **This project solves that**

* Uses **GitHub App + webhook (`workflow_job`)**
* Dynamically creates **ephemeral runners per job**
* Automatically cleans up after execution

👉 You get **GitHub-hosted-like behavior on your own machine**

## 🏗️ Architecture

```mermaid
flowchart TB
subgraph setup["One-time setup"]
direction LR
U[User] -- POST manifest --> GH1[GitHub]
GH1 -- code + slug --> G1[gharp]
G1 -- App credentials --> DB[(sqlite)]
U -- install App --> GH1
end

subgraph runtime["Per-job runtime"]
direction LR
GH2[GitHub] -- workflow_job webhook --> G2[gharp]
G2 -- record job --> DB2[(sqlite)]
G2 -- registration token --> GH2
G2 -- docker run --> R[ephemeral runner]
R -- runs the job --> GH2
R -- one job, then exit --> X((removed))
end

setup --> runtime
```

See [`docs/architecture.md`](docs/architecture.md) for the full design,
including the GitHub App Manifest flow, sqlite job durability, and
permission scopes.

## 📦 Tech Stack

* Go (server)
* Docker (runner execution)
* GitHub App (auth + webhook)

## 📄 License

[Apache License 2.0](LICENSE) — Copyright 2026 Muhan Li.

## 🙌 Acknowledgements

* [GitHub Actions](https://docs.github.com/en/actions) / [self-hosted runners](https://docs.github.com/en/actions/concepts/runners/self-hosted-runners)
* [Docker Github Actions Runner](https://github.com/myoung34/docker-github-actions-runner)