Command Palette

Search for a command to run...

Hectal
PHASE 2Intermediate ~13 min· topic 4 of 4

Topic 2.4

Self-Hosted Runners

In one line

A hosted runner is fresh, disposable infrastructure GitHub manages for you — a self-hosted runner is your own machine instead, needed when a job requires specific hardware, network access, or software hosted runners can't provide.

0/4 · 0%

Key ideas

  1. 01

    Every example so far has used runs-on: ubuntu-latest — a HOSTED runner, a fresh virtual machine GitHub provisions, uses for exactly one job, and destroys immediately afterward. This is genuinely the right default: zero maintenance, always clean, and billed only for actual usage time.

  2. 02

    A SELF-HOSTED RUNNER is your OWN machine (physical, virtual, or a container) registered with GitHub specifically to run jobs from your repository or organization — runs-on: [self-hosted, linux, gpu] targets it using custom LABELS you define, instead of a hosted runner's fixed image names.

  3. 03

    The genuine real reasons to reach for a self-hosted runner: needing SPECIFIC HARDWARE hosted runners don't offer (a GPU for a machine-learning build step), needing NETWORK ACCESS to a private, internal resource hosted runners genuinely can't reach (an internal artifact repository behind a VPN, echoing the DevOps roadmap's own artifact-management section), or needing SOFTWARE/LICENSES that are impractical to install fresh on every single hosted-runner run.

  4. 04

    A self-hosted runner, UNLIKE a hosted one, is NOT automatically fresh and disposable between jobs by default — it persists as a real, standing machine, meaning artifacts, cached files, or even malicious code from a PREVIOUS job could genuinely still be present when the NEXT job runs, unless you deliberately configure cleanup between runs.

  5. 05

    This is a genuinely real SECURITY concern specifically for self-hosted runners on PUBLIC repositories — anyone who can open a pull request could potentially get their own (possibly malicious) workflow code executed on your own actual infrastructure; GitHub's own documentation explicitly warns against using self-hosted runners on public repos without carefully restricting which workflows can actually trigger them.

  6. 06

    Registering a self-hosted runner is genuinely simple mechanically (download GitHub's runner agent, run a registration script with a token from your repository's settings, start the agent as a background service) — the real complexity is entirely operational: keeping the runner's own OS and software patched, monitoring its health, and managing its capacity as demand grows, exactly the kind of ongoing infrastructure responsibility a hosted runner exists specifically to remove from your plate.

Code & diagrams

HostedVsSelfHosteddiagram

Fresh and disposable versus persistent and yours to maintain — a genuine, deliberate trade-off, not a strict upgrade.

Rendering diagram…
self-hosted-runner.ymlmarkdown

Targeting a self-hosted runner by custom labels, for a job needing a GPU.

jobs:
  train-model:
    runs-on: [self-hosted, linux, gpu]    # custom labels, not a hosted image name
    steps:
      - uses: actions/checkout@v4
      - name: Run GPU-accelerated training
        run: python train.py --device cuda

      # Explicit cleanup — genuinely necessary on a persistent, self-hosted machine
      - name: Clean workspace
        if: always()
        run: rm -rf ${{ github.workspace }}/*

Explain it without notes

01

What's the actual difference in lifecycle between a hosted runner and a self-hosted runner, and why does that difference create a real security consideration?

02

Give one genuine, concrete real reason a team would need a self-hosted runner rather than simply using a hosted one.

Practice

01

If you have access to a spare machine (even a local VM), register it as a self-hosted runner for a test repository and confirm a job targeting its specific labels actually runs on it.

02

Think through, for a hypothetical job needing access to an internal, VPN-only resource, why a hosted runner genuinely couldn't do this job at all, regardless of how it's configured.

Trade-offs

  • ↔

    Self-hosted runners solve real problems hosted runners genuinely cannot, but they trade GitHub's own zero-maintenance guarantee for real, ongoing operational responsibility (patching, monitoring, capacity planning, and genuine security hardening) that YOU now own — the right call specifically when a concrete, real need (specific hardware, private network access) actually exists, and a real cost to take on otherwise.

Done when you can

  • I understand the lifecycle difference between a hosted and a self-hosted runner.

  • I can name genuine real reasons to need a self-hosted runner rather than a hosted one.

  • I understand the real security consideration self-hosted runners introduce, especially on public repositories.