Browse documentation

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=c7g

nebula 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.

KeyAllowedDefault
nebulanon-empty run idrequired
cpu2, 4, 8, 16, 32, 644
familyc7i, c7g, m7i, m7g, r7i, r7gc7i
imageubuntu24-full-x64, ubuntu24-full-arm64matches the family
extrass3-cachenone
spottrue or falsetrue

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.