GARM (GitHub Actions Runner Manager) automatically creates and manages self-hosted GitHub Actions runners across multiple infrastructure providers. It supports GitHub.com, GitHub Enterprise Server, and Gitea.
Get GARM running and create your first runner pool:
- Quickstart: Docker -- Deploy GARM as a Docker container (simplest)
- Quickstart: Systemd -- Deploy GARM as a native Linux service
- First Steps -- Add credentials, a repository, and your first runner pool
| Guide | Description |
|---|---|
| Credentials | PATs, GitHub Apps, Gitea tokens, and required permissions |
| Managing Entities | Repositories, organizations, enterprises, endpoints, and webhooks |
| Pools and Scaling | Pool configuration, scaling behavior, balancing, labels, and runner management |
| Scale Sets | GitHub scale sets as an alternative to webhook-driven pools |
| Templates | Customizing runner bootstrap scripts |
| Using GARM with Gitea | Gitea-specific setup and differences from GitHub |
| Agent Mode and Object Store | WebSocket agent mode, remote shell, file storage |
| Page | Description |
|---|---|
| Configuration Reference | Complete config.toml reference |
| Providers | Supported providers and configuration |
| Monitoring and Debugging | Metrics, log streaming, events, and the top dashboard |
| Performance | Cached runners, image optimization, LXD tuning |
| Webhooks | Automatic and manual webhook setup |
| Building from Source | Compiling GARM, the Web UI, and regenerating API clients |
| FAQ | Common questions and answers |
GitHub/Gitea GARM Provider (LXD, AWS, etc.)
| | |
|-- webhook: job queued -------->| |
| |-- create instance ------------>|
| | |-- boots VM/container
| |<-- instance ready -------------|
| | |
|<-- runner registers -----------| |
| | |
|-- job runs on runner --------->| |
| | |
|-- webhook: job completed ----->| |
| |-- delete instance ------------>|
| | |
- GitHub sends a
workflow_jobwebhook when a job is queued (or GARM polls a scale set message queue) - GARM finds a matching pool and asks the provider to create an instance
- The instance boots, installs the runner, and registers with GitHub
- The runner picks up the job and executes it
- When the job completes, GARM deletes the instance
| Concept | Description |
|---|---|
| Controller | A GARM installation, identified by a unique Controller ID |
| Endpoint | A GitHub.com, GHES, or Gitea server that GARM connects to |
| Credential | A PAT or GitHub App tied to an endpoint, used to manage runners |
| Entity | A repository, organization, or enterprise managed by GARM |
| Provider | An external executable that creates/destroys infrastructure (LXD, AWS, etc.) |
| Pool | A group of runners with the same config (image, flavor, labels, provider) |
| Scale Set | An alternative to pools using GitHub's message queue instead of webhooks |
| Runner | A self-hosted GitHub/Gitea runner instance |
| Template | A script that customizes how runners are bootstrapped |
| Provider | Repository |
|---|---|
| Akamai/Linode | flatcar/garm-provider-linode (experimental) |
| Amazon EC2 | cloudbase/garm-provider-aws |
| Azure | cloudbase/garm-provider-azure |
| CloudStack | nexthop-ai/garm-provider-cloudstack |
| GCP | cloudbase/garm-provider-gcp |
| Incus | cloudbase/garm-provider-incus |
| Kubernetes | mercedes-benz/garm-provider-k8s |
| LXD | cloudbase/garm-provider-lxd |
| OpenStack | cloudbase/garm-provider-openstack |
| Oracle OCI | cloudbase/garm-provider-oci |