{"id":51401059,"url":"https://github.com/muhac/actions-runner-pool","last_synced_at":"2026-07-04T06:35:50.082Z","repository":{"id":354553475,"uuid":"1219449483","full_name":"muhac/actions-runner-pool","owner":"muhac","description":"gharp — Ephemeral, autoscaling self-hosted GitHub Actions runners for personal accounts. Multi-repo, Docker-only, no Kubernetes.","archived":false,"fork":false,"pushed_at":"2026-06-26T03:13:42.000Z","size":457,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T06:35:33.177Z","etag":null,"topics":["ci-cd","devops","docker","github-actions","github-app","homelab","self-hosted","self-hosted-runner"],"latest_commit_sha":null,"homepage":"https://muhac.github.io/actions-runner-pool/demo","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/muhac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-23T22:20:49.000Z","updated_at":"2026-06-19T05:21:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/muhac/actions-runner-pool","commit_stats":null,"previous_names":["muhac/actions-runner-pool"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/muhac/actions-runner-pool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muhac%2Factions-runner-pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muhac%2Factions-runner-pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muhac%2Factions-runner-pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muhac%2Factions-runner-pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/muhac","download_url":"https://codeload.github.com/muhac/actions-runner-pool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muhac%2Factions-runner-pool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35112708,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci-cd","devops","docker","github-actions","github-app","homelab","self-hosted","self-hosted-runner"],"created_at":"2026-07-04T06:35:49.614Z","updated_at":"2026-07-04T06:35:50.071Z","avatar_url":"https://github.com/muhac.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🪉 gharp — GitHub Actions Runner Pool\n\nA self-hosted, Docker-based pool of ephemeral GitHub Actions runners.\n\n\u003e 🍴 **Dogfooded** — this repo's own CI was running on a gharp pool during development!\n\n## ✨ Features\n\n* 🔐 **Self-hosted** — no external service dependency\n* ♻️ **Ephemeral runners** — one job per runner, clean environment every time\n* ⚡ **Autoscaling** — runners are created on-demand from webhook events\n* 📊 **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\n* 📦 **Multi-repository, personal-account support** — share compute across repos (not supported natively by GitHub)\n\n\u003e 👉 **[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.\n\n## 🚀 Quick Start\n\n### 1. Run gharp\n\nPre-built multi-arch image: [`muhac/gharp`](https://hub.docker.com/r/muhac/gharp).\n\n**Minimal `docker run`**\n\n```bash\ndocker run -d --name gharp \\\n  -p 8080:8080 \\\n  -e BASE_URL=https://gharp.example.com \\\n  -v /var/run/docker.sock:/var/run/docker.sock \\\n  -v gharp-data:/data \\\n  muhac/gharp:1\n```\n\n`BASE_URL` must be a public HTTPS URL GitHub can reach, terminating at\nthe container's port 8080 (above mapped to the host's 8080). See\n[`docs/configuration.md`](docs/configuration.md) for the full env-var reference.\n\n**Recommended — Docker Compose**\n\n```bash\n# copy docker-compose.yml from this repo, then:\nBASE_URL=https://gharp.example.com docker compose up -d\n```\n\nSee [`docker-compose.yml`](docker-compose.yml) for the full reference configuration\n(workdir cleanup, host Docker socket forwarding for ephemeral runners,\nrunner-container log caps, and `ADMIN_TOKEN` passthrough — set the\ntoken in `.env`).\n\n### 2. Create the GitHub App\n\nOpen `${BASE_URL}/setup` and click **Create GitHub App**. gharp drives\nthe GitHub App Manifest flow and persists the credentials locally.\n\n\u003e ⚠️ **Don't rename the auto-generated App name on GitHub.**\n\u003e gharp creates the App as `gharp-\u003chash\u003e`; renaming it changes the slug,\n\u003e which breaks the install link gharp renders on `/setup`.\n\u003e The webhook keeps working — only the install link goes stale.\n\u003e To fix, delete the App on GitHub and re-run `/setup`.\n\n\u003e ⚠️ **`BASE_URL` is sticky.** It's baked into the GitHub App's webhook\n\u003e and OAuth-callback URLs at `/setup` time. Changing it later won't\n\u003e reconfigure the App — gharp will log a `BASE_URL drift` warning at\n\u003e startup. To migrate, re-run `/setup` (creating a fresh App) or revert\n\u003e `BASE_URL` to the original value.\n\n### 3. Install the App\n\nPick the repos (or \"All repositories\") you want runners for and submit.\n\n\u003e ⚠️ **Self-hosted runners + public repos = remote code execution.**\n\u003e GitHub [explicitly recommends against](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners)\n\u003e using self-hosted runners with public repositories: any contributor\n\u003e who can open a PR can run arbitrary code on your machine.\n\u003e Only install the App on **private** repos you trust,\n\u003e and run gharp on a **dedicated VM / cloud instance / homelab node**.\n\u003e gharp drops public-repo `workflow_job` webhooks by default. To opt in,\n\u003e set `ALLOW_PUBLIC_REPOS=true` for all public repos, or use\n\u003e `REPO_ALLOWLIST=owner/repo` to bypass the guard for selected public repos.\n\n### 4. Add a workflow\n\n```yaml\njobs:\n  build:\n    runs-on:\n      - self-hosted\n    steps:\n      - uses: actions/checkout@v4\n      - run: echo \"hello from $(hostname)\"\n\n  test:\n    runs-on:\n      - self-hosted\n      - \"gharp-test-${{ github.run_id }}-${{ github.run_attempt }}\"\n    steps:\n      - run: echo \"tests from $(hostname)\"\n```\n\nEvery `workflow_job` whose `runs-on` set is fully covered by\n`RUNNER_LABELS` (default `self-hosted`; `self-hosted` is implicit on\nevery self-hosted runner so you don't need to list it) or a configured\ndynamic label prefix (default `gharp-`) will get a fresh runner. Jobs\nrequiring a label this pool doesn't advertise are dropped — see\n[`docs/configuration.md`](docs/configuration.md).\n\nFor the full deployment guide (from-source build, docker compose,\nvolumes, upgrades, ops APIs, troubleshooting), see [`docs/deploy.md`](docs/deploy.md).\n\n## 🤔 Why?\n\nGitHub does **not support \"user-level\" runners**.\n\n* Runners are scoped to: repository, organization, or enterprise\n\nThis makes it hard to:\n\n* share a runner across multiple repositories\n* use self-hosted runners efficiently in personal accounts\n* scale runners dynamically\n\n💡 **This project solves that**\n\n* Uses **GitHub App + webhook (`workflow_job`)**\n* Dynamically creates **ephemeral runners per job**\n* Automatically cleans up after execution\n\n👉 You get **GitHub-hosted-like behavior on your own machine**\n\n## 🏗️ Architecture\n\n```mermaid\nflowchart TB\n    subgraph setup[\"One-time setup\"]\n        direction LR\n        U[User] -- POST manifest --\u003e GH1[GitHub]\n        GH1 -- code + slug --\u003e G1[gharp]\n        G1 -- App credentials --\u003e DB[(sqlite)]\n        U -- install App --\u003e GH1\n    end\n\n    subgraph runtime[\"Per-job runtime\"]\n        direction LR\n        GH2[GitHub] -- workflow_job webhook --\u003e G2[gharp]\n        G2 -- record job --\u003e DB2[(sqlite)]\n        G2 -- registration token --\u003e GH2\n        G2 -- docker run --\u003e R[ephemeral runner]\n        R -- runs the job --\u003e GH2\n        R -- one job, then exit --\u003e X((removed))\n    end\n\n    setup --\u003e runtime\n```\n\nSee [`docs/architecture.md`](docs/architecture.md) for the full design,\nincluding the GitHub App Manifest flow, sqlite job durability, and\npermission scopes.\n\n## 📦 Tech Stack\n\n* Go (server)\n* Docker (runner execution)\n* GitHub App (auth + webhook)\n\n## 📄 License\n\n[Apache License 2.0](LICENSE) — Copyright 2026 Muhan Li.\n\n## 🙌 Acknowledgements\n\n* [GitHub Actions](https://docs.github.com/en/actions) / [self-hosted runners](https://docs.github.com/en/actions/concepts/runners/self-hosted-runners)\n* [Docker Github Actions Runner](https://github.com/myoung34/docker-github-actions-runner)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuhac%2Factions-runner-pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmuhac%2Factions-runner-pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuhac%2Factions-runner-pool/lists"}