GitHub managed Runner sind praktisch, aber nicht für jeden Anwendungsfall geeignet. Vielleicht benötigen Sie spezielle Hardware, möchten Compliance-Anforderungen erfüllen oder auf interne Ressourcen zugreifen, ohne komplexe Netzwerk-Setups. Hier kommen selbst-gehostete Runner ins Spiel: Sie betreiben die Runner-Infrastruktur auf Ihrer eigenen Hardware oder in Ihrer Cloud-Umgebung.
Dieses Kapitel führt Sie Schritt für Schritt durch die praktische Arbeit mit selbst-gehosteten Runnern – von der Installation über die Organisation mit Labels und Gruppen bis hin zu fortgeschrittenen Themen wie Container-Anpassung und Monitoring.
Bevor wir einsteigen, ein kritischer Hinweis: GitHub empfiehlt selbst-gehostete Runner ausschließlich für private Repositories. Der Grund ist simpel, aber gravierend: Bei öffentlichen Repositories kann jeder einen Fork erstellen und über einen Pull Request Code auf Ihrem Runner ausführen lassen. Ein böswilliger Akteur könnte Ihre Infrastruktur kompromittieren, Daten stehlen oder Ihren Runner für andere Zwecke missbrauchen.
Wenn Sie selbst-gehostete Runner einsetzen, stellen Sie sicher, dass: - Die Repositories privat sind - Sie die Zugriffe über Runner-Gruppen kontrollieren - Der Runner in einer isolierten Umgebung läuft - Sensible Daten und Credentials geschützt sind
Die Installation eines selbst-gehosteten Runners erfolgt auf drei Ebenen: Repository, Organisation oder Enterprise. Die Wahl hängt davon ab, wie Sie den Runner nutzen möchten.
| Ebene | Zugriff | Typischer Einsatz |
|---|---|---|
| Repository | Nur dieses Repository | Dedizierte Hardware für ein Projekt |
| Organisation | Alle oder ausgewählte Repositories | Geteilte Runner für Teams |
| Enterprise | Mehrere Organisationen | Zentrale Runner-Infrastruktur |
Navigieren Sie zum Repository, öffnen Sie Settings → Actions → Runners und klicken Sie auf New self-hosted runner. GitHub zeigt Ihnen nun plattformspezifische Installationsanweisungen.
Das Interface zeigt Download-Links und Konfigurationsschritte für Ihr Betriebssystem. Auf einem Linux-System sieht der Prozess typischerweise so aus:
# 1. Runner-Anwendung herunterladen
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz
# 2. Runner konfigurieren
./config.sh --url https://github.com/YOUR-ORG/YOUR-REPO \
--token AUTHENTICATION_TOKEN
# 3. Runner starten
./run.shDas config.sh-Script fragt interaktiv einige Details ab:
- Runner-Name (wird in der UI angezeigt) - Runner-Gruppe (falls
vorhanden) - Labels (mehr dazu später) - Arbeitsverzeichnis
Wichtig: Der --token-Parameter enthält
ein zeitlich begrenztes Token, das GitHub automatisch generiert. Es ist
nur eine Stunde gültig. Wenn Sie die Konfiguration später durchführen
möchten, müssen Sie ein neues Token über die GitHub-UI generieren.
Nach erfolgreicher Konfiguration sehen Sie:
√ Connected to GitHub
2024-12-13 10:23:45Z: Listening for Jobs
Der Runner ist nun aktiv und wartet auf Workflows.
Für Organisations-Runner folgen Sie demselben Prozess, starten aber bei Organization Settings → Actions → Runners → New self-hosted runner. Der Vorteil: Sie können den Runner-Zugriff über Policies steuern und ihn mehreren Repositories zur Verfügung stellen.
Bei der Konfiguration können Sie zusätzlich eine Runner-Gruppe angeben:
./config.sh --url https://github.com/YOUR-ORG \
--token TOKEN \
--runnergroup production-runnersDie Runner-Gruppe muss bereits existieren, sonst schlägt die Konfiguration fehl. Wir behandeln Gruppen gleich ausführlicher.
Wenn Sie ./run.sh manuell starten, läuft der Runner nur,
solange Ihre Shell-Session aktiv ist. Für produktive Umgebungen möchten
Sie, dass der Runner automatisch startet und im Hintergrund läuft. Auf
Linux-Systemen mit systemd ist das elegant gelöst:
# Runner-Dienst installieren
sudo ./svc.sh install
# Optional: Als spezifischer Benutzer installieren
sudo ./svc.sh install runner-userDas Script erstellt einen systemd-Service, den Sie nun verwalten können:
# Dienst starten
sudo ./svc.sh start
# Status prüfen
sudo ./svc.sh status
# Dienst stoppen
sudo ./svc.sh stop
# Dienst deinstallieren
sudo ./svc.sh uninstallDer systemd-Service wird unter
/etc/systemd/system/actions.runner.ORG-REPO.RUNNERNAME.service
erstellt. Sie können den Status auch direkt über systemctl
abfragen:
systemctl status actions.runner.myorg-myrepo.runner01.serviceDebian/Ubuntu-Spezialfall: Auf Debian-basierten
Systemen kann das Tool needrestart nach Updates automatisch
Dienste neu starten – auch Ihren Runner, potenziell mitten in einem Job.
Um das zu verhindern:
echo '$nrconf{override_rc}{qr(^actions\.runner\..+\.service$)} = 0;' | \
sudo tee /etc/needrestart/conf.d/actions_runner_services.confDas konfiguriert needrestart so, dass Runner-Dienste
ignoriert werden.
Labels sind der Mechanismus, über den Sie in Workflows bestimmte Runner auswählen. Jeder selbst-gehostete Runner erhält automatisch diese Standard-Labels:
self-hosted – Kennzeichnet alle selbst-gehosteten
Runnerlinux, windows oder
macosx64, ARM oder
ARM64Ein Linux-Runner auf ARM64-Hardware hat also standardmäßig die
Labels: self-hosted, linux,
ARM64.
In einem Workflow verwenden Sie runs-on mit einer Liste
von Labels:
jobs:
build:
runs-on: [self-hosted, linux, ARM64]
steps:
- uses: actions/checkout@v4
- run: make buildDieser Job läuft nur auf Runnern, die alle drei Labels besitzen. Die Label-Auswahl ist konjunktiv – ein UND, kein ODER.
Standard-Labels reichen oft nicht aus. Vielleicht haben Sie Runner mit unterschiedlicher Hardware-Ausstattung, verschiedenen Netzwerk-Zonen oder speziellen Software-Installationen. Dafür erstellen Sie benutzerdefinierte Labels.
Via GitHub UI:
gpu,
high-memory, dmz)Das Label wird dem Runner zugewiesen. Unbenutzte Labels (die keinem Runner zugeordnet sind) werden automatisch nach 24 Stunden gelöscht.
Via Konfigurationsscript:
Beim Hinzufügen eines neuen Runners können Sie Labels direkt mitgeben:
# Einzelnes Label
./config.sh --url REPO_URL --token TOKEN --labels gpu
# Mehrere Labels (kommagetrennt)
./config.sh --url REPO_URL --token TOKEN --labels gpu,high-memory,nvme-storageWichtig: Wenn Sie Standard-Labels explizit angeben
(z.B. --labels linux), überschreibt GitHub die automatische
Erkennung nicht. Das heißt, Sie können einen Windows-Runner nicht durch
--labels linux zu einem Linux-Runner machen. GitHub prüft
das nicht – es wird einfach als zusätzliches Label behandelt.
Ein praktisches Beispiel: Sie haben GPU-Runner für Machine Learning und wollen sicherstellen, dass Jobs auf Linux-Systemen mit GPU laufen:
jobs:
train-model:
runs-on: [self-hosted, linux, gpu]
steps:
- name: Train Model
run: python train.py --use-gpuOder Sie unterscheiden zwischen verschiedenen Umgebungen:
jobs:
deploy-staging:
runs-on: [self-hosted, linux, staging]
steps:
- run: ./deploy.sh staging
deploy-production:
runs-on: [self-hosted, linux, production]
steps:
- run: ./deploy.sh productionFür spezielle Anwendungsfälle können Sie die automatischen Standard-Labels deaktivieren:
./config.sh --url REPO_URL --token TOKEN --no-default-labelsDer Runner erhält dann nur die Labels, die Sie explizit angeben. Das ist selten nötig, kann aber sinnvoll sein, wenn Sie eine sehr granulare Kontrolle über die Label-Struktur benötigen.
Runner-Gruppen sind ein mächtiges Werkzeug für Organisationen, um Runner zu organisieren und den Zugriff zu kontrollieren. Jede Organisation hat eine Default-Gruppe, in die neue Runner automatisch eingefügt werden. Mit GitHub Team oder höheren Plänen können Sie zusätzliche Gruppen erstellen.
Stellen Sie sich vor, Sie haben: - Runner in verschiedenen Netzwerk-Zonen (DMZ, Internal, Production) - Runner mit unterschiedlichen Sicherheitsstufen - Runner für verschiedene Teams oder Projekte
Mit Gruppen können Sie festlegen, welche Repositories auf welche Runner zugreifen dürfen.
Navigieren Sie zu Organization Settings → Actions → Runner groups und klicken Sie auf New runner group.
Sie konfigurieren:
1. Gruppen-Name: Beschreibend, z.B. “Production Runners” oder “GPU Cluster”
2. Repository-Zugriff: Welche Repositories dürfen Runner aus dieser Gruppe nutzen? - Alle Repositories - Ausgewählte Repositories - Nur private Repositories (Standard)
Das ist die Zugriffskontrolle: Auch wenn ein Workflow einen Runner mit passenden Labels anfordert, kann er ihn nur nutzen, wenn das Repository Zugriff auf die Runner-Gruppe hat.
Bei der Erstkonfiguration:
./config.sh --url ORG_URL --token TOKEN --runnergroup production-runnersBestehende Runner verschieben:
Sie sprechen Gruppen direkt im Workflow an:
jobs:
deploy:
runs-on:
group: production-runners
steps:
- run: ./deploy.shDas wählt einen beliebigen verfügbaren Runner aus der Gruppe “production-runners”. Sie können Gruppen auch mit Labels kombinieren:
jobs:
gpu-training:
runs-on:
group: ml-runners
labels: [self-hosted, linux, gpu]
steps:
- run: python train.pyHier muss der Runner sowohl zur Gruppe “ml-runners” gehören als auch alle drei Labels besitzen.
Für Organisations-Runner können Sie den aktuellen Zustand überwachen:
Verfügbare Runner anzeigen:
Navigieren Sie zu Settings → Actions → Runners. Sie sehen eine Liste aller Runner mit: - Name - Status (Idle, Active, Offline) - Labels - Gruppe - Betriebssystem
Klicken Sie oben auf “Self-hosted”, um nur selbst-gehostete Runner zu sehen (filtert GitHub-gehostete Runner aus).
Runner-Status verstehen:
| Status | Bedeutung |
|---|---|
| Idle | Verbunden und bereit für Jobs |
| Active | Führt gerade einen Job aus |
| Offline | Nicht verbunden – Maschine aus, Service gestoppt oder Netzwerkproblem |
Aktive Jobs überwachen:
Klicken Sie auf den Eintrag für Ihre Runner-Gruppe. Im Abschnitt “Active Jobs” sehen Sie alle derzeit laufenden Jobs mit: - Job-Name - Repository - Laufzeit
Das ist wertvoll beim Debugging: Wenn ein Runner als “Active” angezeigt wird, aber nichts in den Logs erscheint, können Sie hier sehen, ob tatsächlich ein Job läuft.
Ein leistungsfähiges Feature selbst-gehosteter Runner: Sie können Lifecycle-Hooks definieren – Skripts, die automatisch vor oder nach einem Job ausgeführt werden.
GitHub Actions unterstützt zwei Hooks:
ACTIONS_RUNNER_HOOK_JOB_STARTED: Läuft,
bevor der Job startetACTIONS_RUNNER_HOOK_JOB_COMPLETED: Läuft,
nachdem der Job beendet istErstellen Sie ein Script (Bash oder PowerShell):
#!/bin/bash
# cleanup.sh - Aufräumen vor jedem Job
echo "Cleaning up workspace..."
rm -rf /tmp/runner-workspace/*
docker container prune -f
echo "Cleanup complete"
exit 0Wichtig: Der Exitcode bestimmt, ob der Job
fortfährt: - exit 0: Success – Job startet - Jeder andere
Exitcode: Job wird als fehlgeschlagen markiert
Speichern Sie das Script außerhalb des Runner-Verzeichnisses, z.B. in
/opt/runner-hooks/cleanup.sh, und machen Sie es
ausführbar:
chmod +x /opt/runner-hooks/cleanup.shNun konfigurieren Sie die Umgebungsvariable. Sie haben zwei Optionen:
Option 1: .env-Datei im Runner-Verzeichnis
Erstellen Sie eine .env-Datei im Anwendungsverzeichnis
des Runners:
# /home/runner/actions-runner/.env
ACTIONS_RUNNER_HOOK_JOB_STARTED=/opt/runner-hooks/cleanup.shOption 2: Systemweite Umgebungsvariable
Für systemd-Services setzen Sie die Variable in der Service-Konfiguration:
sudo systemctl edit actions.runner.myorg-myrepo.runner01.serviceFügen Sie hinzu:
[Service]
Environment="ACTIONS_RUNNER_HOOK_JOB_STARTED=/opt/runner-hooks/cleanup.sh"Nach Änderungen an .env oder der Service-Konfiguration
müssen Sie den Runner neu starten:
sudo ./svc.sh stop
sudo ./svc.sh startHook-Ausführungen erscheinen in den Workflow-Logs:
Set up runner
Running hook script: /opt/runner-hooks/cleanup.sh
Cleaning up workspace...
Cleanup complete
Hook script completed successfully
Es gibt kein eingebautes Timeout für Hooks. Wenn Ihr Script hängt, blockiert es den Job indefinit. Implementieren Sie daher eigene Timeouts in Ihren Scripts:
#!/bin/bash
# cleanup.sh mit Timeout
timeout 60 docker container prune -f || {
echo "Cleanup timed out after 60 seconds"
exit 1
}Wenn Ihre Workflows Container nutzen
(container:-Direktive), startet der Runner standardmäßig
Docker-Container. Für spezielle Anforderungen – etwa
Kubernetes-Orchestrierung oder Podman statt Docker – können Sie den
Container-Lifecycle anpassen.
Achtung: Dieses Feature ist experimentell und nur für Linux-Runner verfügbar. Root-Zugriff ist nicht erforderlich.
GitHub Actions definiert vier Hook-Punkte:
| Befehl | Zeitpunkt | Aufgabe |
|---|---|---|
prepare_job |
Job-Start | Container pullen, Netzwerk erstellen, Container starten |
cleanup_job |
Job-Ende | Container stoppen und löschen |
run_container_step |
Pro Container-Action | Container-Action ausführen |
run_script_step |
Pro Script-Step | Script im Container ausführen |
Jeder Befehl wird als JSON-Datei definiert. GitHub hat ein
Beispiel-Repository mit Implementierungen für Docker und Kubernetes:
actions/runner-container-hooks.
Klonen Sie das Repository:
cd /opt
git clone https://github.com/actions/runner-container-hooks.git
cd runner-container-hooksInstallieren Sie Dependencies und bauen Sie das Script:
npm install
npm run bootstrap
npm run build-allDas erzeugt packages/k8s/dist/index.js – das
Anpassungs-Script für Kubernetes. Aktivieren Sie es:
# In der Runner .env-Datei
ACTIONS_RUNNER_CONTAINER_HOOKS=/opt/runner-container-hooks/packages/k8s/dist/index.js
ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER=trueDie zweite Variable (REQUIRE_JOB_CONTAINER) erzwingt,
dass Jobs Container nutzen müssen. Jobs ohne
container:-Direktive werden abgelehnt.
Nach Runner-Neustart verwendet GitHub Actions nun Kubernetes-Pods statt Docker-Container für containerbasierte Jobs.
Für die meisten Anwendungsfälle ist die Standard-Docker-Integration ausreichend. Container-Anpassung ist ein Advanced-Feature für spezielle Infrastruktur-Anforderungen.
Selbst-gehostete Runner benötigen Wartung. Hier die wichtigsten Diagnose- und Monitoring-Techniken.
Der Basis-Check: Ist der Runner verbunden?
# Status des systemd-Service
sudo systemctl status actions.runner.myorg-myrepo.runner01.service
# Oder via svc.sh
sudo ./svc.sh statusIn der GitHub-UI sehen Sie den Status unter Settings → Actions → Runners. Ein “Offline”-Runner bedeutet: - Die Maschine ist heruntergefahren - Der Runner-Service läuft nicht - Netzwerk-Konnektivität ist unterbrochen
Der Runner muss mit verschiedenen GitHub-Services kommunizieren. Testen Sie das mit dem eingebauten Check:
./config.sh --check --url REPO_URL --pat TOKENErsetzen Sie TOKEN durch ein Personal Access Token mit
workflow-Scope. Das Script testet alle erforderlichen
Verbindungen:
Checking GitHub connectivity...
PASS GitHub.com
PASS Actions API
PASS Codeload API
PASS Results API
PASS Packages API
Schlägt ein Test fehl, finden Sie Details in den Log-Dateien unter
_diag/. Der exakte Pfad wird in der Ausgabe angezeigt.
Häufiges Problem: Firewalls und Proxies
Selbst-gehostete Runner benötigen ausgehenden HTTPS-Zugriff (Port
443) zu: - github.com - api.github.com -
*.actions.githubusercontent.com -
*.pkg.github.com
Wenn Ihre Firewall diese blockiert, wird der Runner nicht funktionieren.
In Unternehmensumgebungen mit TLS-Interception kann die Zertifikat-Validierung fehlschlagen. Nur für Tests können Sie die Validierung deaktivieren:
export GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY=1
./config.sh --url REPO_URL --token TOKEN
./run.shWarnung: Das ist ein Sicherheitsrisiko. Produktiv sollten Sie das GitHub-Zertifikat (oder das Ihrer TLS-Inspection-Infrastruktur) zum System-Truststore hinzufügen.
Der Runner schreibt mehrere Log-Typen im
_diag/-Verzeichnis:
Runner-Logs (Runner_*.log): Zeigen den
Lifecycle der Runner-Anwendung – Starts, Verbindungen, Fehler.
2024-12-13 10:23:45Z INFO RunnerListener] Connected to GitHub
2024-12-13 10:24:12Z INFO JobDispatcher] Running job: Build Application
Worker-Logs (Worker_*.log): Details zur
Job-Ausführung – was in jedem Step passiert.
Wichtig bei kurzlebigen Runnern: Diese Logs werden lokal gespeichert. Wenn Ihre Runner nach jedem Job zerstört werden (Auto-Scaling), gehen die Logs verloren. Leiten Sie sie an ein zentrales Logging-System weiter (Syslog, ELK, CloudWatch, etc.).
Auf Linux können Sie Echtzeit-Logs über journalctl
verfolgen:
sudo journalctl -u actions.runner.myorg-myrepo.runner01.service -fDie -f-Option (follow) zeigt neue Logs sofort an.
Beispielausgabe:
Dec 13 10:23:45 runner01 runsvc.sh[1234]: Started listener process
Dec 13 10:24:12 runner01 runsvc.sh[1234]: Running job: testAction
Dec 13 10:24:45 runner01 runsvc.sh[1234]: Job testAction completed: Succeeded
Das ist wertvoll für Live-Debugging: Sie sehen sofort, wenn Jobs starten oder fehlschlagen.
Die Runner-Anwendung aktualisiert sich selbst automatisch. Diesen Prozess sollten Sie überwachen, da veraltete Runner keine Jobs mehr annehmen.
Update-Aktivitäten erscheinen in Runner_*.log:
[Dec 13 10:15:23 INFO SelfUpdater] An update is available
[Dec 13 10:15:24 INFO SelfUpdater] Downloading version 2.311.0
[Dec 13 10:15:45 INFO SelfUpdater] Update complete, restarting
Zusätzlich finden Sie Details in SelfUpdate_*.log im
_diag/-Verzeichnis.
Wichtig: Das Runner-Update erfolgt automatisch. Sie müssen keine manuellen Updates durchführen. Aber: Das Betriebssystem und andere Software (Docker, etc.) müssen Sie selbst aktuell halten.
Wenn Jobs Container nutzen, muss Docker korrekt konfiguriert sein.
Docker läuft?
sudo systemctl is-active docker.serviceRunner hat Docker-Zugriff?
# Finden Sie den Runner-User heraus
sudo systemctl show -p User actions.runner.myorg-myrepo.runner01.service
# Prüfen Sie die Docker-Gruppe
groups runner-userDer Runner-User muss Mitglied der docker-Gruppe
sein:
sudo usermod -aG docker runner-userNach Gruppenänderungen Runner neu starten.
Welche Docker-Engine?
Wenn Actions mit Fehlern wie “Input required and not supplied” abbrechen, kann das an einer inkompatiblen Docker-Installation liegen. Snap-basierte Docker-Installationen sind problematisch:
which docker
# /snap/bin/docker <- ProblematischInstallieren Sie Docker über das offizielle Repository statt über snap.
Wenn Sie einen Runner außer Betrieb nehmen möchten, gibt es zwei Szenarien.
Manchmal möchten Sie einen Runner nur vorübergehend offline nehmen – für Wartung, Updates oder Tests. Einfach den Service stoppen:
sudo ./svc.sh stopDer Runner erscheint in der GitHub-UI als “Offline”, bleibt aber
registriert. Nach sudo ./svc.sh start nimmt er Jobs wieder
an.
Um einen Runner dauerhaft zu entfernen:
1. Via GitHub UI:
Navigieren Sie zu Settings → Actions → Runners, klicken Sie auf den Runner und dann auf “Remove”. GitHub zeigt Ihnen einen Befehl:
./config.sh remove --token REMOVAL_TOKENFühren Sie diesen auf dem Runner aus. Das: - Deregistriert den Runner bei GitHub - Löscht lokale Konfigurationsdateien - Entfernt systemd-Services (falls als Service installiert)
2. Wenn Sie keinen Zugriff auf den Runner haben:
Klicken Sie in der UI auf “Force remove this runner”. Das entfernt den Runner aus GitHub, aber lokale Dateien bleiben auf der Maschine.
3. Automatisches Entfernen:
Runner werden automatisch entfernt, wenn sie sich zu lange nicht verbinden: - Standard-Runner: 14 Tage Inaktivität - Kurzlebige Runner: 1 Tag Inaktivität - JIT-Runner (Just-in-Time): Sofort nach dem Job oder bei Nicht-Ausführung
Wenn Sie einen Runner-Computer für einen neuen Runner nutzen wollen, ohne die Anwendung neu herunterzuladen:
rm .runnerDas löscht die Registrierungsdatei. Sie können dann
./config.sh erneut ausführen, um den Runner neu zu
registrieren.
Abschließend einige bewährte Strategien für selbst-gehostete Runner in Produktion:
Isolation: Führen Sie Runner in isolierten VMs oder Containern aus. Ein kompromittierter Runner sollte keinen Zugriff auf sensible Produktionssysteme haben.
Monitoring: Integrieren Sie Runner-Logs in Ihr zentrales Monitoring. Alerting bei Offline-Runnern oder fehlgeschlagenen Jobs ist essenziell.
Skalierung: Nutzen Sie Auto-Scaling für dynamische Workloads. Tools wie der Kubernetes Operator oder Terraform-Module helfen dabei.
Regelmäßige Updates: Während die Runner-Anwendung sich selbst aktualisiert, müssen Sie OS-Updates und Dependencies manuell pflegen. Automatisieren Sie das.
Backup der Logs: Bei kurzlebigen Runnern (z.B. Spot-Instances) gehen Logs bei Beendigung verloren. Leiten Sie sie extern weiter.
Labels konsistent verwenden: Etablieren Sie eine Namenskonvention für Labels. Dokumentieren Sie, welche Labels was bedeuten. Das verhindert Verwirrung in großen Teams.
Gruppen für Zugriffskontrolle: Nutzen Sie Runner-Gruppen konsequent, um zu kontrollieren, welche Repositories auf welche Runner zugreifen. Das ist eine wichtige Sicherheitsebene.
Selbst-gehostete Runner geben Ihnen volle Kontrolle über die Ausführungsumgebung – zu dem Preis, dass Sie diese Umgebung selbst verwalten müssen. Mit den richtigen Werkzeugen und Prozessen ist das jedoch gut handhabbar und ermöglicht Workflows, die mit GitHub-gehosteten Runnern nicht möglich wären.