Back to Dashboard

github-runner

2.338.0

Trust posture

📋 SBOM ATTESTED🛡 0 open alerts🏗 AMD64 + ARM64 🔗 3/3 deps tracked daily 🔍 REPRODUCE THESE CHECKS LOCALLY
PULLS 190.4K 109553 to 189511 pulls across 30 recorded days 2026-09-18: 109553 pulls2026-09-19: 120098 pulls2026-09-20: 129297 pulls2026-09-21: 133349 pulls2026-09-22: 135190 pulls2026-09-23: 138815 pulls2026-09-24: 140760 pulls2026-09-25: 147633 pulls2026-09-26: 151541 pulls2026-09-27: 151797 pulls2026-09-28: 152889 pulls2026-09-29: 155223 pulls2026-09-30: 157677 pulls2026-10-01: 159740 pulls2026-10-02: 164089 pulls2026-10-03: 165491 pulls2026-10-04: 167731 pulls2026-10-05: 169454 pulls2026-10-06: 170337 pulls2026-10-07: 175945 pulls2026-10-08: 177907 pulls2026-10-09: 183386 pulls2026-10-10: 185356 pulls2026-10-11: 185616 pulls2026-10-12: 185759 pulls2026-10-13: 186105 pulls2026-10-14: 187239 pulls2026-10-15: 188895 pulls2026-10-16: 189450 pulls2026-10-17: 189511 pulls
STARS 0
COVERAGE 18 variants · 3 versions · amd64+arm64

VERIFIABLE TRUST ARTIFACTS

Provenance

Build commit
43b72a4
Build digest
sha256:f6e4c1dc14ad2eb8aa01c2d6351b6f5aa1c2d22f3d1d393be6316f422e5270ca
Index digest
sha256:757313a9c2dfb0035d2802f6c9a528abfbc3ee13306a57f17d7470f8f1de00ae
Manifest digest (amd64)
sha256:4b8a1ec7c2311a6b5b2a2c7840bf154c3e22b74c9f5a42f9a047e08e24083e74
Manifest digest (arm64)
sha256:f2a2b724b6696bf1b679201558becea72df063f74f681af493691cb60349d206
SBOM attestation
55834442…
Trivy evidence
Code Scanning fetched 2026-10-17 11:24 UTC
Base image
ghcr.io/oorabona/library/ubuntu:24.04
Verify
gh attestation verify oci://ghcr.io/oorabona/github-runner:2.338.0 --owner oorabona guide →

Security evidence

Trivy · Code Scanning for image 2.338.0 fetched 2026-10-17

0 open Code Scanning alerts · fetched 2026-10-17 · advisory mode (does not block builds)

Code Scanning: 0 open alerts · fetched 2026-10-17Recorded scan: 140 findings · scanned 2026-10-17
0Critical
0High
0Medium
0Low
0Info

No open Code Scanning alerts as of 2026-10-17.

Top advisories (upstream, advisory)

    → See verification steps.

    Explore

    Available variants

    TagSize (amd64) Build statusVersion
    2.338.0 default546.8MB OK2.338.0
    2.338.0-dev833.6MB OK2.338.0
    2.338.0-debian-trixie583.8MB OK2.338.0
    2.338.0-debian-trixie-dev969.9MB OK2.338.0
    2.338.0-windows-ltsc20222716.3MB OK2.338.0
    2.338.0-windows-ltsc2022-dev8503.0MB OK2.338.0
    2.337.0 default290.5MB OK2.337.0
    2.337.0-dev575.3MB OK2.337.0
    2.337.0-debian-trixie350.1MB OK2.337.0
    2.337.0-debian-trixie-dev733.1MB OK2.337.0
    2.337.0-windows-ltsc20222715.2MB OK2.337.0
    2.337.0-windows-ltsc2022-dev8672.2MB OK2.337.0
    2.336.0 default290.1MB OK2.336.0
    2.336.0-dev574.9MB OK2.336.0
    2.336.0-debian-trixie349.7MB OK2.336.0
    2.336.0-debian-trixie-dev732.7MB OK2.336.0
    2.336.0-windows-ltsc20222714.7MB OK2.336.0
    2.336.0-windows-ltsc2022-dev8671.7MB OK2.336.0
    Build lineagef6e4c1dc14ad
    Build Lineage
    Build Digest sha256:f6e4c1dc14ad2eb8aa01c2d6351b6f5aa1c2d22f3d1d393be6316f422e5270ca
    Base Image ghcr.io/oorabona/library/ubuntu:24.04
    UBUNTU_2404_BASE ubuntu:24.04
    DEBIAN_TRIXIE_BASE ghcr.io/oorabona/debian:trixie
    PWSH_VERSION 7.6.7
    GIT_VERSION 2.56.0.windows.2
    JQ_VERSION 1.8.2
    VERSION 2.338.0
    MAJOR_VERSION 2
    FLAVOR base
    REMOTE_CR ghcr.io/oorabona
    Package summary 923 packages
    Recent changes +0 −0 ~6
    Build history 8 builds
    Dependency health all up to date

    Dependency Health

    all up to date
    3/3 dependencies monitored
    Up-to-date dependencies
    PWSH_VERSION 7.6.7 GIT_VERSION 2.56.0.windows.2 JQ_VERSION 1.8.2

    Documentation

    README

    github-runner

    Self-hosted GitHub Actions runner in a Docker container. Supports Linux (Ubuntu 24.04, Debian Trixie) and Windows (Server 2022 ltsc2022), each in base and dev flavors. Runners are semi-ephemeral: each container handles exactly one job then exits, while named Docker volumes persist tool caches across restarts.

    Why this image?

    GitHub provides an official runner image (ghcr.io/actions/actions-runner) designed for ARC (Actions Runner Controller) on Kubernetes. If you run K8s, ARC is the recommended approach.

    This image fills a different gap:

    Feature Official (ARC) This image
    Linux containers ✅ ✅
    Windows containers ❌ ✅
    Kubernetes required Yes No
    docker compose up ❌ ✅
    GitHub App auth (JWT) Via ARC config Built into entrypoint
    PAT / registration token auth Via ARC config Built into entrypoint
    Semi-ephemeral with warm caches Manual restart: always + volumes
    Org-level runners Via ARC Via env var (GITHUB_ORG)
    Multi-distro (Ubuntu, Debian) Ubuntu only Ubuntu + Debian

    Use this image when: you want self-hosted runners on Docker Desktop, Podman, or any Docker host — without Kubernetes.

    Use the official image when: you have a Kubernetes cluster and want to use ARC.

    Verify this image

    Every build ships a Sigstore-signed SBOM and a full Trivy scan — verify them yourself, no login required:

    gh attestation verify oci://ghcr.io/oorabona/github-runner:2.332.0 --owner oorabona
    

    Full walkthrough (SBOM payload, Trivy findings, multi-arch manifest inspection, upstream dependency tracking) → https://oorabona.github.io/docker-containers/verify-images/

    Quick Start

    # Copy and fill in the env file
    cp .env.example .env
    # Edit .env: set GITHUB_TOKEN + GITHUB_REPOSITORY (or GITHUB_ORG)
    
    # Start a single runner
    docker compose up
    
    # Start 3 parallel runners
    docker compose up --scale runner=3
    

    The container registers itself with GitHub, executes one job, then exits with code 0.

    Environment Variables

    Variable Required Default Description
    RUNNER_TOKEN One of Token/PAT/App — Direct registration token from GitHub UI (expires in 1h)
    GITHUB_TOKEN One of Token/PAT/App — PAT with repo or admin:org scope
    APP_ID One of Token/PAT/App — GitHub App ID
    APP_PRIVATE_KEY One of Token/PAT/App — GitHub App private key (PEM string with literal \n)
    APP_PRIVATE_KEY_FILE One of Token/PAT/App — Path to GitHub App PEM file (alternative to APP_PRIVATE_KEY)
    GITHUB_REPOSITORY One of Repo/Org — Target repository in owner/repo format
    GITHUB_ORG One of Repo/Org — Target organisation name
    RUNNER_NAME_PREFIX No runner Prefix for the unique runner name
    RUNNER_LABELS No self-hosted,linux,<arch> Comma-separated runner labels
    RUNNER_GROUP No Default Runner group name
    RUNNER_TOOL_CACHE No /opt/hostedtoolcache Tool cache directory; compose.yaml maps this to a named volume at /cache/tool-cache
    GITHUB_API_URL No https://api.github.com Override for GitHub Enterprise Server
    ALLOW_ROOT No false Set true to run as root (security risk — testing only)
    RUNNER_DISABLE_AUTO_UPDATE No 1 Disable runner agent auto-update (recommended for containers)

    Auth Modes

    PAT (Personal Access Token)

    Requires a PAT with repo scope (repository runner) or admin:org scope (org runner).

    docker run --rm \
      -e GITHUB_TOKEN=ghp_xxxxxxxxxxxx \
      -e GITHUB_REPOSITORY=owner/repo \
      ghcr.io/oorabona/github-runner:2.332.0
    

    GitHub App

    Requires an App installed on the target repository or organisation. Provide either the PEM content (inline) or a file path.

    # PEM content inline (escape newlines as \n)
    docker run --rm \
      -e APP_ID=123456 \
      -e APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMII...\n-----END RSA PRIVATE KEY-----" \
      -e GITHUB_REPOSITORY=owner/repo \
      ghcr.io/oorabona/github-runner:2.332.0
    
    # PEM from file (mount the key)
    docker run --rm \
      -e APP_ID=123456 \
      -e APP_PRIVATE_KEY_FILE=/run/secrets/app-key \
      -v /path/to/app.pem:/run/secrets/app-key:ro \
      -e GITHUB_REPOSITORY=owner/repo \
      ghcr.io/oorabona/github-runner:2.332.0
    

    JWT generation uses openssl (pure bash, no extra dependencies).

    Running on Windows

    1. Go to your repo on GitHub: Settings → Actions → Runners → New self-hosted runner
    2. Copy the registration token from the configure step (it starts with A and is valid for 1 hour)

    Linux runners (Podman Desktop or Docker Desktop)

    Both Podman Desktop and Docker Desktop can run Linux runner images on Windows via WSL2:

    podman run --rm \
      -e RUNNER_TOKEN=AXXXXXXXXXXXXXXXXXX \
      -e GITHUB_REPOSITORY=owner/repo \
      ghcr.io/oorabona/github-runner:2.332.0
    

    Windows runners (Docker Desktop only)

    Windows container images require Docker Desktop (or Rancher Desktop with moby engine). Podman does not support Windows containers.

    1. Switch Docker Desktop to Windows containers (right-click tray icon → “Switch to Windows containers”)
    2. Go to your repo → Settings → Actions → Runners → New self-hosted runner
    3. Copy the registration token
    docker run --rm \
      -e RUNNER_TOKEN=AXXXXXXXXXXXXXXXXXX \
      -e GITHUB_REPOSITORY=owner/repo \
      ghcr.io/oorabona/github-runner:2.332.0-windows-ltsc2022
    

    Note: Windows containers require process isolation (default on Windows Server) or Hyper-V isolation (Windows 11 Pro/Enterprise).

    Note: The registration token expires after 1 hour. For persistent runners or scaled deployments, use PAT or GitHub App auth instead — those never expire and can refresh a fresh registration token on every container start.

    Pre-installed software

    What is included per flavor

    Linux — base

    Package Purpose
    git Source control
    curl HTTP client
    jq JSON processing
    unzip Archive extraction
    ca-certificates TLS root certificates
    tini PID 1 init (zombie reaping + signal forwarding)
    gosu Privilege drop from root to runner at startup

    The runner user is also added to the docker group so DooD works without sudo.

    Linux — dev

    Everything in base, plus the following Tauri / native-addon build prerequisites:

    Package Purpose
    build-essential GCC toolchain, make
    pkg-config Library metadata
    libssl-dev OpenSSL headers
    libgtk-3-dev GTK 3 headers (Tauri)
    libwebkit2gtk-4.1-dev WebKit2GTK headers (Tauri)
    libayatana-appindicator3-dev System tray support (Tauri)
    librsvg2-dev SVG rendering (Tauri)

    Language runtimes (Rust, Node, Python, Go, …) are intentionally not pre-installed — see the setup-action table below.

    Windows — base

    Package Purpose
    git Source control (via Chocolatey)
    curl HTTP client (via Chocolatey)
    jq JSON processing (via Chocolatey)
    unzip Archive extraction (via Chocolatey)
    pwsh (PowerShell 7) Default shell for RUN steps and entrypoint

    Long-path support (LongPathsEnabled) and git config core.longpaths true are applied at build time.

    Windows — dev

    Everything in Windows base, plus:

    Package Purpose
    VS Build Tools 2022 (VCTools workload) MSVC compiler, Windows SDK — required for Tauri, native Node addons, Rust on Windows

    What needs a setup-* action

    Language runtimes are not pre-installed in any flavor. Use the standard setup actions — with persistent volumes they are downloaded only on the first job.

    Tool Pre-installed? Action to use Cached after first run?
    Node.js No actions/setup-node@v4 Yes (RUNNER_TOOL_CACHE)
    Python No actions/setup-python@v5 Yes
    Go No actions/setup-go@v5 Yes
    Java No actions/setup-java@v4 Yes
    .NET No actions/setup-dotnet@v4 Yes
    Rust No dtolnay/rust-toolchain@stable Yes (.cargo volume)
    Docker CLI No (DooD available) Mount host socket N/A

    Persistent caches

    Tip: With restart: always and persistent volumes, setup-* actions download tools only on the first job. Subsequent jobs find them in the RUNNER_TOOL_CACHE volume, matching the performance of pre-installed tools without the image bloat. See Cache Volumes for the full volume list.

    Flavors

    Flavor Tag suffix Included
    base -base runner agent, git, curl, jq, unzip, ca-certificates, libicu-dev, libkrb5-dev
    dev -dev everything in base + build-essential, pkg-config, libssl-dev, libgtk-3-dev, libwebkit2gtk-4.1-dev (Tauri prerequisites)

    The dev flavor targets Tauri-based build pipelines. Language runtimes (Rust, Node, Python) are NOT pre-installed — use setup-* actions; they will be cached in RUNNER_TOOL_CACHE.

    Distros

    Distro Tag Notes
    Ubuntu 24.04 2.332.0 or 2.332.0-ubuntu-2404-base Default, recommended
    Debian Trixie 2.332.0-debian-trixie-base Smaller base image
    Windows Server 2022 2.332.0-windows-ltsc2022-base Requires Windows host or --profile windows

    Scaling

    # Start 5 parallel runners for the same repo
    docker compose up --scale runner=5
    

    Each container instance gets a unique name (${RUNNER_NAME_PREFIX}-${HOSTNAME}-${EPOCH}) and registers independently. All share the same named volumes for tool caches.

    Cache Volumes

    Named Docker volumes persist build tool caches across container restarts. They survive docker compose down (use docker compose down --volumes to remove them).

    Volume Container path Purpose
    github-runner-tool-cache /cache/tool-cache setup-node, setup-go, etc. (RUNNER_TOOL_CACHE)
    github-runner-cargo-cache /home/runner/.cargo Rust cargo registry + compiled deps
    github-runner-npm-cache /home/runner/.npm npm global cache
    github-runner-nuget-cache /home/runner/.nuget NuGet package cache
    github-runner-pnpm-store /home/runner/.pnpm-store pnpm content-addressable store

    Docker-outside-of-Docker (DooD)

    Allows workflows to run docker commands by sharing the host Docker socket. The runner user is pre-added to the docker group at build time.

    # In compose.yaml — uncomment the socket volume:
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    

    Or with docker run:

    docker run --rm \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -e GITHUB_TOKEN=... \
      -e GITHUB_REPOSITORY=... \
      ghcr.io/oorabona/github-runner:2.332.0
    

    Security warning: Mounting the Docker socket grants the container full control over the host Docker daemon. Only do this on trusted infrastructure. DinD (Docker-in-Docker with --privileged) is not supported.

    Windows Runner

    The Windows variant (-windows-ltsc2022) runs on Windows Server 2022 with process isolation (no Hyper-V required).

    # Start only the Windows runner (requires a Windows host or Hyper-V)
    docker compose --profile windows up
    

    Requirements:

    • Windows Server 2022 or Windows 10/11 with Windows containers enabled
    • Docker Desktop configured for Windows containers
    • No Hyper-V needed (process isolation is the default)

    The Windows runner uses PowerShell (entrypoint.ps1) and installs packages via Chocolatey.

    Building Locally

    # From the repository root:
    ./make build github-runner 2.332.0
    
    # Build all variants (generates Dockerfiles for all distros × flavors):
    ./make build github-runner
    
    # Build a specific distro + flavor:
    ./github-runner/generate-dockerfile.sh ubuntu-2404 base
    docker build --build-arg RUNNER_VERSION=2.332.0 \
      -f github-runner/Dockerfile.ubuntu-2404-base \
      github-runner/
    

    Troubleshooting

    Token expired (HTTP 401)

    Registration tokens are valid for 1 hour. The entrypoint fetches a fresh token on every start — if the API returns 401, it retries up to 5 times with exponential backoff (2 s, 4 s, 8 s, 16 s, 32 s). If all attempts fail:

    [ERROR] Failed to obtain registration token after 5 attempts.
    

    Check that GITHUB_TOKEN has the correct scope (repo for repository runners, admin:org for org runners).

    Name conflicts

    If a runner with the same name is already registered, config.sh exits with code 3. The entrypoint treats this as a fatal error and exits non-zero. To avoid conflicts, set RUNNER_NAME_PREFIX to a unique value or use docker compose up --scale runner=N which gives each container a different hostname.

    No-network errors at startup

    The entrypoint exits immediately on DNS / connection failures (curl exits non-zero). There is no retry for network-unavailable errors — only for HTTP-level failures (4xx/5xx). Ensure the container can reach api.github.com (or your GHES URL).

    Orphan runners after SIGKILL

    If the container is killed with SIGKILL (OOM kill, docker kill, etc.) the SIGTERM cleanup handler does not run and the runner stays registered as offline on GitHub. GitHub automatically removes offline runners after 14 days, but the cleanup-offline-runners.sh script lets you remove them immediately.

    # Dry-run: list offline runners without removing (default)
    ./github-runner/cleanup-offline-runners.sh owner/repo
    
    # Org-level
    ./github-runner/cleanup-offline-runners.sh --org myorg
    
    # Actually remove them
    ./github-runner/cleanup-offline-runners.sh owner/repo --force
    
    # Uses GITHUB_REPOSITORY or GITHUB_ORG from the environment
    ./github-runner/cleanup-offline-runners.sh --force
    

    The script requires the gh CLI to be authenticated (or GITHUB_TOKEN in the environment with repo scope for repository runners or admin:org scope for org runners). It always prints a table of offline runners before acting.

    Volume UID mismatch

    If a cache volume was created by a different UID, the entrypoint attempts chown on startup and warns if it cannot fix the permissions:

    [WARN]  Cache directory not writable: /cache/tool-cache — attempting permission fix
    

    To reset: docker volume rm github-runner-tool-cache (loses cached data).