Ephemeral autoscaling GitHub Actions runners for multiple repositories and personal accounts.
5.6K
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!
š Try the dashboard liveā ā same UI, mock data, no backend. Click Cancel / Retry to see how the dashboard reacts.
Pre-built multi-arch image: muhac/gharpā .
Minimal docker run
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ā for the full env-var reference.
Recommended ā Docker Compose
# copy docker-compose.yml from this repo, then:
BASE_URL=https://gharp.example.com docker compose up -d
See 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).
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-<hash>; 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_URLis sticky. It's baked into the GitHub App's webhook and OAuth-callback URLs at/setuptime. Changing it later won't reconfigure the App ā gharp will log aBASE_URL driftwarning at startup. To migrate, re-run/setup(creating a fresh App) or revertBASE_URLto the original value.
Pick the repos (or "All repositories") you want runners for and submit.
ā ļø Self-hosted runners + public repos = remote code execution. GitHub explicitly recommends againstā 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_jobwebhooks by default. To opt in, setALLOW_PUBLIC_REPOS=truefor all public repos, or useREPO_ALLOWLIST=owner/repoto bypass the guard for selected public repos.
jobs:
build:
runs-on: [self-hosted]
steps:
- uses: actions/checkout@v4
- run: echo "hello 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) will get a
fresh runner. Jobs requiring a label this pool doesn't advertise are
dropped ā see docs/configuration.mdā .
For the full deployment guide (from-source build, docker compose,
volumes, upgrades, ops APIs, troubleshooting), see docs/deploy.mdā .
GitHub does not support "user-level" runners.
This makes it hard to:
š” This project solves that
workflow_job)š You get GitHub-hosted-like behavior on your own machine
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ā for the full design,
including the GitHub App Manifest flow, sqlite job durability, and
permission scopes.
Apache License 2.0ā ā Copyright 2026 Muhan Li.
Content type
Image
Digest
sha256:26355f06fā¦
Size
20.6 MB
Last updated
2 days ago
docker pull muhac/gharp