Autoscaling GitHub Actions self-hosted runners on Nomad. Listens for workflow_job.queued webhooks and dispatches ephemeral runner jobs on-demand.
GitHub Webhook → Webhook Server (Nomad service) → Dispatches → Runner Job (Nomad batch)
- Nomad cluster with Vault integration
- Docker driver enabled on Nomad nodes
- GitHub org admin access
# Generate a webhook secret
openssl rand -hex 32
# Store secrets
vault kv put kv/github \
blackpaw_token="<GITHUB_PAT>" \
github_webhook_secret="<GENERATED_SECRET>" \
nomad_token="<NOMAD_TOKEN>"GitHub PAT permissions (fine-grained):
- Resource owner: your org
- Organization permissions → Self-hosted runners: Read and write
nomad acl policy apply github-runner-dispatch nomad-jobs/github-runner-policy.hcl
nomad acl token create -name="github-webhook-server" -policy="github-runner-dispatch"Store the resulting SecretID in Vault as nomad_token.
# Register the runner job first (sits idle until dispatched)
nomad job run nomad-jobs/gha-runner.nomad
# Deploy the webhook server
nomad job run nomad-jobs/webhook-server.nomadGo to: https://github.com/organizations/<ORG>/settings/hooks/new
| Field | Value |
|---|---|
| Payload URL | https://<your-webhook-server-url>/ |
| Content type | application/json |
| Secret | Same value stored in Vault |
| Events | Select "Workflow jobs" only |
In your workflow files, use:
runs-on: [self-hosted, linux-x86]The self-hosted label triggers the autoscaler. Additional labels are for routing.
| File | Purpose |
|---|---|
nomad-jobs/webhook-server.nomad |
Webhook server (long-running service) |
nomad-jobs/gha-runner.nomad |
Runner job (parameterized batch) |
nomad-jobs/github-runner-policy.hcl |
Nomad ACL policy for dispatch |
Built automatically on push to main via GitHub Actions:
ghcr.io/blackpaw-studio/github-actions-runner:latest