Sign inSign up

ltamp/github-actions-runner

By ltamp

•Updated about 16 hours ago

Self-hosted GitHub Actions runners: Ubuntu 24.04 and Windows Server Core LTSC 2022 (x64).

Image
0

467

ltamp/github-actions-runner repository overview

⁠GitHub Actions Runner Containers

Self-hosted GitHub Actions runners for Ubuntu 24.04 and Windows Server Core LTSC 2022. Self-hosted GitHub-Actions-Runner fuer Ubuntu 24.04 und Windows Server Core LTSC 2022.

Documentation / Dokumentation⁠ | Releases⁠ | Runner upstream⁠

⁠English

⁠Images and tags

Both images target x64. The Linux image uses Ubuntu 24.04; the Windows image uses Windows Server Core LTSC 2022 and requires a compatible Windows container host. A Linux Docker engine cannot run the Windows image. Both Dockerfiles use separate download/extraction stages. Their final images include the runner, Docker CLI, Buildx and Git, but no Docker daemon or download archives. Linux also includes the Docker repository key, certificates and required runtime libraries. Windows uses SHA256-verified static Docker/Buildx binaries and MinGit for command-line Git; MinGit does not provide a general-purpose Git Bash shell. Windows tool versions and hashes are pinned in build arguments and must be updated together; the automatic updater only updates the runner.

PlatformVersion tag (example)Moving tag
Ubuntu 24.041.0.0-ubuntu24.04latest-ubuntu24.04
Windows LTSC 20221.0.0-windowslatest-windows

Images are published to <dockerhub-user>/github-actions-runner and <registry>.azurecr.io/github-actions-runner. Use versioned tags for reproducibility. The container release version is independent of the bundled actions/runner version.

⁠Start a runner

Generate a runner registration token, not a personal access token, in the target organization or repository under Settings > Actions > Runners > New self-hosted runner. Registration tokens expire after one hour. Supply credentials at runtime only.

Environment variableRequiredMeaning
RUNNER_URLYesOrganization or repository URL; no default
RUNNER_TOKENYesRegistration token for that exact URL
RUNNER_NAMEYesRunner name and additional runs-on label

Linux example, after setting these three variables in your shell:

docker run -d --name gha-linux \
	-e RUNNER_URL -e RUNNER_TOKEN -e RUNNER_NAME \
	<dockerhub-user>/github-actions-runner:latest-ubuntu24.04

Windows example, after setting the variables in your PowerShell environment:

docker run -d --name gha-windows `
	-e RUNNER_URL -e RUNNER_TOKEN -e RUNNER_NAME `
	<dockerhub-user>/github-actions-runner:latest-windows

For private-registry images, authenticate with docker login <registry>.azurecr.io and replace the image prefix. Select your runner by name-label and operating system:

jobs:
	example:
		runs-on: [self-hosted, Linux, X64, my-linux-runner]
		steps:
			- run: echo "Running on my Linux runner"

For Windows use [self-hosted, Windows, X64, my-windows-runner]. Organization runner-group access rules still determine which repositories may use a runner.

⁠Repository setup

Configure these repository Actions secrets before publishing:

SecretPurpose
USER_DOCKERHUBDocker Hub username and image namespace
PAT_DOCKERHUBDocker Hub access token with push permission; overview sync requires read/write/delete scope
URL_AZURECONTAINERREGRegistry hostname, e.g. example.azurecr.io, or its HTTPS origin; no repository path
USER_AZURECONTAINERREGRegistry login username
PW_AZURECONTAINERREGRegistry password or token with push permission

Both registries must be reachable from GitHub-hosted runners. A registry behind a private endpoint requires a network-connected self-hosted build runner instead. Docker Hub must allow the supplied user to push to github-actions-runner.

Enable Settings > Actions > General > Allow GitHub Actions to create and approve pull requests. Set Settings > Pages > Build and deployment > Source to GitHub Actions. Ensure luth2 can be assigned to repository PRs.

⁠Releases and automation
  • release.yml: validates the project, runs semantic-release on main, then builds Ubuntu and Windows images in a matrix and pushes each image to both registries. Pull requests build and smoke-test both images without registry credentials or pushes.
  • Conventional Commits: fix: creates a patch, feat: a minor, and a BREAKING CHANGE: footer a major release. The first release is 1.0.0. Use a release-worthy first commit such as feat: add runner release pipeline. Squash-merge PRs with a matching Conventional Commit title.
  • Documentation-only and ordinary chore: commits do not publish images. Release notes and Git tags are generated by semantic-release; nothing is published to npm.
  • update-runner.yml: checks official stable actions/runner releases daily at 06:23 UTC and updates both versions and SHA256 digests in a fix(deps) PR assigned to luth2. Both assets must be present; Docker builds verify their SHA256 checksums.
  • Dependabot checks workflow Actions and release/documentation npm tooling weekly; all its PRs and all other newly opened/reopened PRs are assigned to luth2.
  • pages.yml: publishes this README as English/German documentation.
  • dockerhub-overview.yml: syncs this README to the Docker Hub repository overview on README changes to main or a manual run. The existing PAT_DOCKERHUB must have read/write/delete scope; a push-only token is insufficient for this action.

Runner-update PRs use GITHUB_TOKEN, which does not trigger normal PR CI workflows. Manually run Validate, release and publish containers on the update branch to validate it before merging. Non-main manual runs build without publishing. Main-branch releases and image publication share one workflow, so no release-event PAT is needed.

If image publishing fails after a release was created, rerun the workflow: it reuses the existing version at that commit. Older releases cannot overwrite latest through a rerun. Registry pushes are not transactional; a failed run can leave one registry or platform updated.

⁠Docker builds on the Linux runner

The Linux image includes Docker CLI and Buildx from Docker's signed APT repository. It connects to a host Docker engine; it does not start Docker-in-Docker. Start it on a dedicated Linux Docker host with the socket and its numeric group ID:

docker run -d --name gha-docker \
	-e RUNNER_URL -e RUNNER_TOKEN -e RUNNER_NAME \
	--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
	--group-add "$(stat -c '%g' /var/run/docker.sock)" \
	<dockerhub-user>/github-actions-runner:latest-ubuntu24.04

Set RUNNER_NAME=docker-runner for this workflow example:

jobs:
	image:
		runs-on: [self-hosted, Linux, X64, docker-runner]
		permissions:
			contents: read
		steps:
			- uses: actions/checkout@v6
			- uses: docker/setup-buildx-action@v3
			- uses: docker/login-action@v3
				with:
					username: ${{ secrets.USER_DOCKERHUB }}
					password: ${{ secrets.PAT_DOCKERHUB }}
			- uses: docker/build-push-action@v6
				with:
					context: .
					file: Dockerfile
					push: true
					tags: ${{ secrets.USER_DOCKERHUB }}/my-image:latest

Use the Dockerfile path in the job's repository, e.g. Dockerfile.linux when building this project. Verify daemon access with docker exec gha-docker docker info. No --privileged or world-writable socket permissions are needed. The socket gives workflows effectively root access to the host, not just the runner container: never run untrusted PRs on this runner. Container-based Actions and jobs.container also require runner work directories mounted at the same absolute path on host and runner; the socket-only example is for JavaScript Actions and streamed Docker build contexts.

⁠Docker builds on the Windows runner

Start on a compatible, dedicated Windows container host with its Docker engine pipe:

docker run -d --name gha-windows-docker `
	-e RUNNER_URL -e RUNNER_TOKEN -e RUNNER_NAME `
	--mount 'type=npipe,source=\\.\pipe\docker_engine,target=\\.\pipe\docker_engine' `
	<dockerhub-user>/github-actions-runner:latest-windows
docker exec gha-windows-docker docker info

The runner and jobs run as ContainerAdministrator, so jobs can install tools without sudo. Git, Docker CLI and Buildx are available on startup; no Docker service starts inside the container. The named pipe gives jobs administrative control over the host Docker engine: only run trusted workflows and never unreviewed PRs.

For native Windows image builds, use PowerShell steps with docker build, docker login and docker push; set $env:DOCKER_BUILDKIT = '0' for the legacy Windows builder. Installing Buildx does not install a BuildKit server. Windows BuildKit support is experimental and requires a separately configured compatible remote builder. The Linux docker/setup-buildx-action example above is not a drop-in Windows configuration. Docker container Actions and jobs.container are unsupported on Windows runners. Building Linux images requires a remote Linux engine or BuildKit builder, not the local Windows engine.

⁠Operations and local checks
docker build -f Dockerfile.linux -t github-actions-runner:local .
npm ci --ignore-scripts
npm test
npm run docs:build

Build Windows with docker build -f Dockerfile.windows -t github-actions-runner:local . on a Windows container host. The generated Pages site is in docs/_site/.

The runner name must be unique. --replace replaces an existing registration of the same name; do not run two containers with that name. Registration is skipped when the container already has .runner; changed URL/name values require recreating it. The token is unset before the runner starts, but Docker administrators can still inspect the container's configured environment. Do not bake credentials into images.

These are persistent runners: shutdown does not automatically deregister them. Delete stale registrations in GitHub when replacing/removing containers. Jobs share the runner workspace until the container is recreated; only run trusted workflows. No host Docker socket/pipe or language-specific build toolchains are included. Both images include command-line Git; install additional tools as your jobs require. The Linux runner user has passwordless sudo: jobs can run sudo apt-get update and sudo apt-get install -y <package>. This grants full root access inside the container; use it only for trusted workflows. The runner itself starts as a non-root user. Windows starts as ContainerAdministrator, with full administrative rights inside the container. Runner self-updates remain enabled; rebuild and redeploy for fresh base-image patches.

Both Dockerfiles declare owner=luth2 and the OCI author luth2 (https://github.com/luth2). The npm release-tool dependency tree currently has upstream security advisories that compatible updates do not resolve. Install scripts are disabled, PR jobs have no registry credentials, and publishing runs only on trusted main; review npm audit before deployment.

⁠Deutsch

⁠Images und Start

Beide Images sind fuer x64: Ubuntu 24.04 beziehungsweise Windows Server Core LTSC 2022. Windows benoetigt einen kompatiblen Windows-Containerhost, keine Linux-Engine. Beide Multistage-Builds trennen Download und Entpacken vom Laufzeitimage. Dieses enthaelt Runner, Docker CLI, Buildx und Git, aber keinen Docker-Daemon oder Downloadarchive. Linux enthaelt ausserdem den Docker-Repository-Schluessel, Zertifikate und Laufzeitbibliotheken. Windows verwendet SHA256-gepruefte Docker-/Buildx-Binaerdateien und MinGit fuer die Git-Kommandozeile, ohne allgemeine Git-Bash-Shell. Windows-Werkzeugversionen und Hashes sind als Build-Argumente festgelegt und gemeinsam zu aktualisieren; der automatische Updater pflegt nur den Runner. Veroeffentlicht wird nach Docker Hub und in die private Registry, jeweils unter github-actions-runner. Tags sind beispielsweise 1.0.0-ubuntu24.04 und 1.0.0-windows; bewegliche Tags heissen latest-ubuntu24.04 und latest-windows. Image-Version und enthaltene GitHub-Runner-Version sind voneinander unabhaengig.

Beim Start muessen RUNNER_URL, RUNNER_TOKEN und RUNNER_NAME gesetzt sein. Die URL bezeichnet die Zielorganisation oder das Zielrepository und hat keinen Standardwert. Der Token ist ein dazu passender Registrierungstoken, kein PAT; er laeuft nach einer Stunde ab. Den Token erzeugst du unter Settings > Actions > Runners > New self-hosted runner. Nutze die Linux-/PowerShell-Startbefehle im englischen Abschnitt mit deinen Umgebungsvariablen.

Der Name wird auch als Label hinterlegt:

runs-on: [self-hosted, Linux, X64, mein-linux-runner]

Unter Windows verwende [self-hosted, Windows, X64, mein-windows-runner]. Bei Organisations-Runnern gelten zusaetzlich die Zugriffsregeln der Runner-Gruppe.

⁠Einrichtung und Versionierung

Die fuenf oben beschriebenen Secrets sind erforderlich: USER_DOCKERHUB, PAT_DOCKERHUB, URL_AZURECONTAINERREG, USER_AZURECONTAINERREG und PW_AZURECONTAINERREG. Die Registry-URL muss ein Hostname oder eine HTTPS-Adresse ohne Repository-Pfad sein. Beide Registries muessen von GitHub-hosted Runnern erreichbar sein; fuer einen privaten Netzwerk-Endpunkt brauchst du eigene Build-Runner.

Erlaube GitHub Actions unter Settings > Actions > General das Erstellen von PRs. Waehle unter Settings > Pages > Build and deployment > Source die Option GitHub Actions. luth2 muss im Repository als Assignee verfuegbar sein.

Auf main erzeugt semantic-release anhand von Conventional Commits die Version: fix: = Patch, feat: = Minor, BREAKING CHANGE: = Major; erste Version = 1.0.0. Der erste Commit sollte beispielsweise feat: add runner release pipeline heissen. Beim Squash-Merge muss der PR-Titel diesem Format entsprechen. Reine Doku- oder normale chore:-Commits loesen keine Image-Veroeffentlichung aus.

Nach dem Release baut die Matrix Ubuntu und Windows auf passenden Hosts, prueft die Runner-Binaerdatei und pusht Versionstags und bewegliche Tags in beide Registries. PRs bauen und testen ohne Registry-Secrets und ohne Push. npm wird nicht veroeffentlicht.

⁠Docker-Builds auf dem Linux-Runner

Docker CLI und Buildx sind installiert, aber kein Docker-Daemon. Verwende den Startbefehl im englischen Abschnitt auf einem dedizierten Linux-Dockerhost: Er bindet /var/run/docker.sock ein und uebergibt dessen numerische Gruppen-ID mit --group-add. Dadurch kann runner ohne sudo auf Docker zugreifen. Kein --privileged und kein chmod 666 auf dem Socket sind erforderlich.

Mit RUNNER_NAME=docker-runner kannst du die gezeigten Actions docker/setup-buildx-action, docker/login-action und docker/build-push-action verwenden. Passe Image-Tag und Dockerfile-Pfad an das jeweilige Repository an. docker exec gha-docker docker info prueft den Zugriff auf den Host-Daemon.

Der Socket gibt Jobs praktisch Root-Kontrolle ueber den Host: keine unbekannten oder ungeprueften PRs darauf ausfuehren. Container-Actions und jobs.container brauchen zusaetzlich Arbeitsverzeichnisse, die auf Host und Runner unter demselben absoluten Pfad gemountet sind. Das Socket-Beispiel deckt JavaScript-Actions und gestreamte Build-Kontexte ab.

⁠Docker-Builds auf dem Windows-Runner

Der PowerShell-Startbefehl im englischen Windows-Docker-Abschnitt bindet die Named Pipe \\.\pipe\docker_engine des Windows-Hosts ein. docker exec gha-windows-docker docker info prueft die Verbindung. Der Runner startet als ContainerAdministrator: Jobs koennen Werkzeuge direkt installieren, ohne sudo. Docker CLI, Buildx und Git sind vorinstalliert; im Container wird kein Docker-Dienst gestartet.

Die Named Pipe gibt Jobs administrative Kontrolle ueber die Docker-Engine des Hosts: nur vertrauenswuerdige Workflows, keine ungeprueften PRs ausfuehren. Fuer Windows-Images nutze PowerShell-Schritte mit docker build, docker login und docker push; $env:DOCKER_BUILDKIT = '0' waehlt den klassischen Windows-Builder. Buildx bringt keinen BuildKit-Server mit. Windows-BuildKit ist experimentell und braucht einen separat konfigurierten kompatiblen Remote-Builder; das Linux-Action-Beispiel ist nicht unveraendert auf Windows uebertragbar. Container-Actions und jobs.container werden auf Windows-Runnern nicht unterstuetzt. Linux-Images brauchen eine entfernte Linux-Engine oder einen passenden BuildKit-Builder, nicht die lokale Windows-Engine.

⁠Automatische Pflege und Betrieb

Der Runner-Update-Workflow prueft taeglich um 06:23 UTC offizielle stabile Releases aus actions/runner. Beide Downloads und SHA256-Pruefsummen muessen vorliegen. Ein fix(deps)-PR aktualisiert beide Dockerfiles und wird luth2 zugewiesen. Der Workflow dockerhub-overview.yml synchronisiert diese README als Docker-Hub-Overview bei README-Aenderungen auf main oder einem manuellen Run. PAT_DOCKERHUB braucht dafuer den Scope read/write/delete; reine Push-Rechte reichen fuer diese Action nicht.

Dependabot aktualisiert Actions und npm-Werkzeuge woechentlich. Auch alle anderen neu erstellten oder wieder geoeffneten PRs werden luth2 zugewiesen.

Da Update-PRs mit GITHUB_TOKEN keine normale PR-CI ausloesen, starte vor dem Merge Validate, release and publish containers manuell auf dem Update-Branch. Manuelle Runs ausserhalb von main bauen ohne Veroeffentlichung. Bei einem fehlgeschlagenen Registry-Push kann der Run dieselbe Release-Version wiederverwenden. Alte Releases duerfen latest nicht zuruecksetzen; Registry-Pushes sind trotzdem nicht atomar und koennen teilweise erfolgreich sein.

Runner-Namen muessen eindeutig sein: --replace ersetzt die gleichnamige Registrierung. Vorhandene Container behalten ihre Registrierung; fuer eine neue URL oder einen neuen Namen erstelle den Container neu. Der Token wird vor dem Runner-Start entfernt, bleibt aber fuer Docker-Administratoren in der Container-Konfiguration einsehbar. Keine Secrets ins Image schreiben.

Beim Stoppen erfolgt keine automatische Abmeldung. Entferne veraltete Runner in GitHub. Persistente Runner teilen ihren Arbeitsbereich zwischen Jobs: nur vertrauenswuerdige Workflows ausfuehren. Host-Docker-Socket/-Pipe und Sprach-Toolchains sind nicht enthalten; Git ist in beiden Images vorhanden. Runner-Selbstupdates bleiben aktiv. Fuer aktuelle Basisimage-Patches Images neu bauen und Container ersetzen. Der Linux-Benutzer runner hat passwortloses sudo, etwa fuer sudo apt-get update und sudo apt-get install -y <paket>. Jobs erhalten damit volle Root-Rechte im Container: nur vertrauenswuerdige Workflows ausfuehren. Der Runner startet weiterhin ohne Root-Rechte. Windows startet als ContainerAdministrator mit vollen Administratorrechten im Container.

Lokale Pruefung: npm ci --ignore-scripts, npm test, npm run docs:build. Die generierte zweisprachige Seite liegt unter docs/_site/.

Beide Images tragen owner=luth2 sowie das OCI-Autorenlabel mit dem GitHub-Profil. Die npm-Releasewerkzeuge enthalten derzeit nicht kompatibel behebbare Upstream-Sicherheitsmeldungen. Installationsskripte sind deaktiviert; PR-Jobs erhalten keine Registry-Zugangsdaten. Pruefe npm audit vor der Inbetriebnahme.

Tag summary

Content type

Image

Digest

sha256:89d63f02c…

Size

2.2 GB

Last updated

about 16 hours ago

docker pull ltamp/github-actions-runner:latest-windows