Back to Dashboard

github-runner

2.335.1

Trust posture

๐Ÿ“‹ SBOM ATTESTED๐Ÿ›ก TRIVY: 14 HIGH (advisory) ยท SCANNED 2026-07-10๐Ÿ— AMD64 + ARM64 ๐Ÿ”— 3/3 deps tracked daily ๐Ÿ” REPRODUCE THESE CHECKS LOCALLY
PULLS 52.5K
STARS 0
COVERAGE 18 variants ยท 3 versions ยท amd64+arm64

VERIFIABLE TRUST ARTIFACTS

Provenance

Build commit
ed67d41
Build digest
sha256:cb5c51a02ffbfb838cc26a4bedba381e0dea356778e98fb8fa20971f09de4703
Index digest
sha256:5a844509f50595a358e9a91df9b4566dd448033cab7101b6773e16055df05fe6
Manifest digest (amd64)
sha256:9365578f66d1f7e03694515aff9ea7f9b4669ba0fb8641823b3cbcecb2b3de43
Manifest digest (arm64)
sha256:04e8b4cac6b1200ca352c9e4b24dca147877453f07ccafb724313d41ee39c1af
SBOM attestation
34817667โ€ฆ
Trivy last scan
2026-07-10 20:42 UTC
Base image
Verify
gh attestation verify oci://ghcr.io/oorabona/github-runner:2.335.1 --owner oorabona guide โ†’

Security scan results

Trivy ยท last scan 2026-07-10

Last scan: (advisory mode โ€” Trivy runs continue-on-error in CI; we surface findings, we do not block builds on them).

0Critical
14High
45Medium
18Low
0Info

Top advisories (upstream, advisory)

    โ†’ Full report via gh api โ€” see Verify Images.

    Explore

    Available variants

    TagSize (amd64) Build statusVersion
    2.335.1 default540.8MB OK2.335.1
    2.335.1-dev830.6MB OK2.335.1
    2.335.1-debian-trixie579.8MB OK2.335.1
    2.335.1-debian-trixie-dev962.8MB OK2.335.1
    2.335.1-windows-ltsc20222615.5MB OK2.335.1
    2.335.1-windows-ltsc2022-dev8455.9MB OK2.335.1
    2.334.0 default289.1MB OK2.334.0
    2.334.0-dev576.4MB OK2.334.0
    2.334.0-debian-trixie348.6MB OK2.334.0
    2.334.0-debian-trixie-dev729.2MB OK2.334.0
    2.334.0-windows-ltsc20222615.0MB OK2.334.0
    2.334.0-windows-ltsc2022-dev8281.5MB OK2.334.0
    2.333.1 default287.9MB OK2.333.1
    2.333.1-dev575.2MB OK2.333.1
    2.333.1-debian-trixie347.4MB OK2.333.1
    2.333.1-debian-trixie-dev728.0MB OK2.333.1
    2.333.1-windows-ltsc20222613.9MB OK2.333.1
    2.333.1-windows-ltsc2022-dev8454.1MB OK2.333.1
    Build lineagesha256:
    Build Lineage
    Build Digest sha256:cb5c51a02ffbfb838cc26a4bedba381e0dea356778e98fb8fa20971f09de4703
    Base Image
    UBUNTU_2404_BASE ubuntu:24.04
    DEBIAN_TRIXIE_BASE ghcr.io/oorabona/debian:trixie
    PWSH_VERSION 7.6.3
    GIT_VERSION 2.55.0.windows.2
    JQ_VERSION 1.8.2
    Package summary n/a โ€” runtime parsed
    Recent changes n/a โ€” runtime parsed
    Build history n/a โ€” runtime fetched
    Dependency health all up to date

    Dependency Health

    all up to date
    3/3 dependencies monitored
    Up-to-date dependencies
    PWSH_VERSION 7.6.3 GIT_VERSION 2.55.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).