Self-hosted runners
GitHub Actions jobs on ephemeral EC2. Not a cloud session.
A job opts in by its runs-on labels. GitHub queues the job. Nebula launches one matching instance, the runner takes that job, and the instance terminates. Cloud sessions, on their own page, run the Mind agent on Fargate. This page is the Actions runner.
Labels
The labels customers put on a job are runs-on: nebula=…, cpu=8, family=c7g. GitHub delivers them as separate strings, so the workflow writes a list. A single comma-separated string would be one label, and the size would not parse.
runs-on:
- nebula=${{ github.run_id }}
- cpu=8
- family=c7gnebula is required. Its value is the workflow run id, which scopes the runner to that run. Without it the job is not ours and nothing is launched. Unknown keys are refused.
| Key | Allowed | Default |
|---|---|---|
| nebula | non-empty run id | required |
| cpu | 2, 4, 8, 16, 32, 64 | 4 |
| family | c7i, c7g, m7i, m7g, r7i, r7g | c7i |
| image | ubuntu24-full-x64, ubuntu24-full-arm64 | matches the family |
| extras | s3-cache | none |
| spot | true or false | true |
Bare self-hosted, linux and nebula are tolerated. x64 and arm64 must match the family.
Families and size
A family ending in g is Graviton, arm64. A family ending in i is x86_64. The image has to agree, or the job is refused. cpu=8, family=c7g launches c7g.2xlarge. The label allows 32 and 64, and the default deployment refuses anything above 16.
What the instance does
The instance is Ubuntu 24.04 with Docker, so a job can use service containers. It registers with a just-in-time config, runs one job, and terminates. The default bound is one hour. Six hours is the ceiling. Spot is the default. The workflow cannot choose the AMI id, the subnet, the security group or the role. extras=s3-cache points the Actions cache at a loopback proxy on the instance.
Related
- Runners overview
- Cloud sessions, the Fargate sandbox, which is not this runner