You have GARM running (via Docker or systemd). This guide walks you through the steps to get your first runner spinning:
- Understand the resource hierarchy
- (Optional) Add an endpoint
- Add credentials
- Add a repository (or organization)
- Create a runner pool
- Verify runners appear in GitHub
GARM resources form a hierarchy:
Endpoint (github.com, GHES, Gitea)
└── Credential (PAT, GitHub App, Gitea token)
└── Entity (repository, organization, enterprise)
├── Pool (webhook-driven runners)
└── Scale Set (message-queue-driven runners)
- Endpoints represent a forge: github.com, a GitHub Enterprise Server instance, or a Gitea server.
- Credentials are scoped to an endpoint and authenticate GARM's access to that forge.
- Entities (repos/orgs/enterprises) are tied to credentials, which determines their endpoint.
- Pools and Scale Sets are tied to entities and define how runners are created.
GARM ships with a default github.com endpoint. If you're using github.com, skip to step 2.
For GitHub Enterprise Server:
garm-cli github endpoint create \
--name my-ghes \
--description "Internal GHES" \
--base-url https://ghes.example.com \
--upload-url https://upload.ghes.example.com \
--api-base-url https://api.ghes.example.com \
--ca-cert-path /path/to/ca-cert.pemFor Gitea (1.24+):
garm-cli gitea endpoint create \
--name my-gitea \
--description "Internal Gitea" \
--api-base-url https://gitea.example.com/ \
--base-url https://gitea.example.com/ \
--ca-cert-path /path/to/ca-cert.pemThe --ca-cert-path is optional for both GHES and Gitea. Use it when the server uses certificates signed by an internal CA.
List endpoints:
garm-cli github endpoint list # GitHub / GHES endpoints
garm-cli gitea endpoint list # Gitea endpointsSee Managing Entities for more details on endpoints.
Credentials are scoped to an endpoint. GARM needs them to manage runners and webhooks. See Credentials for full details on permissions and credential types.
Add a PAT (for github.com):
garm-cli github credentials add \
--name my-pat \
--description "GitHub PAT for runner management" \
--auth-type pat \
--pat-oauth-token gh_yourTokenGoesHere \
--endpoint github.comOr a GitHub App:
garm-cli github credentials add \
--name my-app \
--description "GitHub App for runner management" \
--endpoint github.com \
--auth-type app \
--app-id 12345 \
--app-installation-id 67890 \
--private-key-path /path/to/private-key.pemFor GHES or Gitea, replace --endpoint github.com with the endpoint name you created in step 1. For Gitea, use garm-cli gitea credentials add with the same flags.
Verify:
garm-cli github credentials list # for GitHub / GHES credentials
garm-cli gitea credentials list # for Gitea credentialsgarm-cli repo add \
--owner your-org \
--name your-repo \
--credentials my-pat \
--random-webhook-secret \
--install-webhook \
--pool-balancer-type roundrobinThis does three things:
- Registers the repository in GARM
- Generates a random webhook secret
- Installs a webhook in GitHub that sends
workflow_jobevents to GARM
Important
--install-webhook requires the PAT or App to have webhook management permissions. If you prefer to set up webhooks manually, see Webhooks.
Verify:
garm-cli repo listNote the repository ID from the output -- you'll need it for the next step. You can also use the owner/name format (e.g., my-org/my-repo) in place of the UUID wherever --repo is expected.
Check which providers are available:
garm-cli provider listCreate a pool using the LXD provider from the quickstart:
garm-cli pool add \
--repo <REPO_ID> \
--enabled \
--provider-name lxd_local \
--flavor default \
--image ubuntu:22.04 \
--max-runners 5 \
--min-idle-runners 1 \
--os-arch amd64 \
--os-type linux \
--tags ubuntu,genericKey options:
| Option | Description |
|---|---|
--min-idle-runners |
Runners kept warm and waiting for jobs. Set to 0 for pure on-demand scaling. |
--max-runners |
Upper limit on runners in this pool. |
--tags |
Labels applied to runners. Workflows target these with runs-on:. |
--flavor |
Provider-specific sizing (LXD profile, cloud instance type). |
--image |
Provider-specific image (LXD image alias, cloud AMI, etc). |
garm-cli runner list --repo <REPO_ID>After a few minutes:
+----+-------------------+---------+---------------+--------------------------------------------+
| NR | NAME | STATUS | RUNNER STATUS | POOL / SCALE SET |
+----+-------------------+---------+---------------+--------------------------------------------+
| 1 | garm-tdtD6zpsXhj1 | running | idle | Pool: 344e4a72-2035-4a18-a3d5-87bd3874b56c |
+----+-------------------+---------+---------------+--------------------------------------------+
Get detailed status:
garm-cli runner show garm-tdtD6zpsXhj1The runner should now appear in GitHub under Settings > Actions > Runners.
Target your runner using the tags you set on the pool:
# .github/workflows/test.yml
jobs:
build:
runs-on: [ubuntu, generic]
steps:
- uses: actions/checkout@v4
- run: echo "Running on a GARM-managed runner!"- Managing Repositories, Orgs, and Enterprises -- Add organizations and enterprises
- Pools and Scaling -- Fine-tune pool settings, scaling behavior, and pool balancing
- Scale Sets -- Use GitHub scale sets instead of webhook-driven pools
- Templates -- Customize runner bootstrap scripts
- Credentials -- PAT scopes, GitHub Apps, and Gitea tokens
- FAQ -- Common questions and answers