Zum Inhalt springen
SONOYA.com
Selfhosting & Web

GitHub Actions Minuten aufgebraucht: Runner mit Coolify

Actions-Minuten zu 90 % verbraucht? So richtest Du mit Coolify einen eigenen Runner für Deine GitHub-Organisation ein, auch mit GitHub Free.

Von

GitHub-Logo auf dunklem Verlauf für einen selbst gehosteten GitHub Actions Runner, der per Coolify auf dem eigenen Server läuft

Wer mit Claude Code, Codex oder Copilot viel Code in private Repositories schreibt, erzeugt auch viele Commits, Pull Requests und damit viele Workflow-Läufe. Irgendwann kommt dann eine E-Mail von GitHub, dass 90 % der im Plan enthaltenen Actions-Nutzung verbraucht sind, und kurz darauf bleiben die Builds stehen. Diese Anleitung zeigt Dir, wie Du mit Coolify einen eigenen GitHub Actions Runner auf Deinem Server startest, der für alle privaten Repositories einer kostenlosen GitHub-Organisation arbeitet und keine Minuten mehr verbraucht. Sie zeigt aber auch, wann es klüger ist, einfach Minuten zu kaufen.

Stand der Anleitung ist Coolify 4.7, der GitHub Actions Runner 2.338 und das Abrechnungsmodell von GitHub im November 2026. Der Ablauf ist genau so an einer echten Organisation mit mehreren privaten Repositories eingerichtet und mit der offiziellen Doku von GitHub abgeglichen.

Warum die Minuten plötzlich knapp werden

GitHub rechnet Actions in privaten Repositories nicht mehr in festen Minuten ab, sondern als Guthaben. Laut der Abrechnungsdoku von GitHub enthält GitHub Free monatlich 12 US-Dollar Rechenzeit, GitHub Pro 18 US-Dollar. Eine Minute auf dem Standard-Linux-Runner kostet 0,006 US-Dollar, das entspricht also rund 2.000 Minuten bei Free und 3.000 Minuten bei Pro. Öffentliche Repositories sind davon nicht betroffen, dort bleiben die Standard-Runner kostenlos.

Mit KI-Unterstützung sind 2.000 Minuten schnell weg. Ein Coding-Agent pusht in kurzen Abständen, jeder Push startet Lint, Tests und Build, und wenn ein Lauf rot wird, startet der nächste Versuch gleich hinterher. Auch fehlgeschlagene Läufe zählen voll. Wer zusätzlich die Claude Code GitHub Action mit seinem Max-Abo nutzt oder Copilot Code Review aktiviert hat, verbraucht weitere Minuten, denn beide laufen standardmäßig auf den Runnern von GitHub.

Ist das Guthaben aufgebraucht und keine Zahlungsmethode mit Budget hinterlegt, starten neue Jobs nicht mehr. Im Actions-Tab steht dann sinngemäß, dass der Job nicht gestartet wurde, weil das Ausgabenlimit erhöht werden muss.

Vorher ehrlich abwägen: Vielleicht reicht es, Minuten zu kaufen

Bevor Du einen eigenen Runner aufsetzt, rechne kurz nach. Unter Settings > Billing and licensing hinterlegst Du bei GitHub eine Zahlungsmethode und legst unter Budgets and alerts ein Budget für Actions fest. Danach kostet jede weitere Linux-Minute 0,006 US-Dollar. 1.000 zusätzliche Minuten sind also 6 US-Dollar, 3.000 Minuten 18 US-Dollar im Monat. Mit dem Budget legst Du gleichzeitig eine Obergrenze fest, damit ein Agent in einer Endlosschleife nicht die Rechnung sprengt. Der Wechsel auf GitHub Pro bringt dagegen nur 6 US-Dollar mehr Guthaben, also rund 1.000 Minuten.

Der eigene Runner kostet kein Geld pro Minute, aber Zeit und Aufmerksamkeit:

  • Du musst die Repositories in eine Organisation umziehen und danach Git-Remotes und Deploy-Verbindungen anpassen.
  • Nicht jeder Workflow läuft unverändert. Jobs mit Datenbank-Service-Containern oder Docker Compose bleiben oft besser bei GitHub, und beim Umzug fallen gern alte Probleme auf, die vorher keiner bemerkt hat.
  • Der Runner-Server gehört Dir, also auch seine Updates, sein Plattenplatz und seine Sicherheit.

Wenn Du nur gelegentlich über das Kontingent rutschst, ist der Kauf von Minuten fast immer die bessere Wahl: zwei Minuten Einrichtung, keine Wartung, nichts kann am eigenen Server hängen. Der eigene Runner lohnt sich, wenn Du dauerhaft deutlich mehr verbrauchst, ohnehin einen Server mit Coolify betreibst oder die weiteren Vorteile am Ende dieses Artikels für Dich zählen.

Zur Einordnung: Laut GitHub ist die Nutzung selbst gehosteter Runner kostenlos und zieht nichts vom Inklusivguthaben ab, auch bei GitHub Free. Im Dezember 2025 hatte GitHub zwar eine Plattformgebühr von 0,002 US-Dollar pro Minute für selbst gehostete Runner angekündigt, diese Änderung dann aber verschoben. Den aktuellen Stand findest Du im Changelog-Eintrag von GitHub.

Warum eine Organisation statt eines persönlichen Kontos

Bei einem persönlichen GitHub-Konto kann ein Self-hosted Runner nur an ein einziges Repository gebunden werden. Für fünf Repositories bräuchtest Du fünf Runner-Container, fünf Einträge in Coolify und musst jeden neuen Runner von Hand anlegen, sobald ein Repository dazukommt.

Eine Organisation löst das. Sie ist auch bei GitHub kostenlos, und ein Runner auf Organisationsebene arbeitet die Jobs aller Repositories darin ab, auch von Repositories, die Du später anlegst. Die Inklusivminuten der Organisation (ebenfalls 12 US-Dollar bei GitHub Free) kommen noch dazu, für Jobs, die weiter bei GitHub laufen.

Was Du brauchst

  • Einen Server mit installiertem Coolify 4. Falls Du Coolify noch nicht hast, hilft Dir die offizielle Installationsanleitung von Coolify. Ein kleiner VPS mit 2 vCPUs und 4 GB RAM reicht für typische Node-, Python- oder Astro-Builds. Wenn Du noch keinen Server hast, bekommst Du über diesen Link zu DigitalOcean (Affiliate Link) Startguthaben für ein Droplet.
  • Ein GitHub-Konto (Free genügt) und die privaten Repositories, die den Runner nutzen sollen.
  • Etwa eine halbe Stunde Zeit, plus ein paar Minuten pro Repository zum Umstellen der Workflows.

Wichtig zur Sicherheit: Ein Self-hosted Runner gehört nur zu privaten Repositories. Bei einem öffentlichen Repository könnte jeder über einen Pull Request aus einem Fork Code auf Deinem Server ausführen. Das betont auch GitHub in der Doku zu Self-hosted Runnern. In Schritt 5 prüfen wir, dass öffentliche Repositories der Organisation den Runner nicht benutzen dürfen.

Schritt 1: Organisation anlegen und Repositories übertragen

Klicke bei GitHub oben rechts auf das Plus-Symbol, wähle New organization und dann den kostenlosen Plan. Gib der Organisation einen Namen und ordne sie Deinem persönlichen Konto zu.

Danach überträgst Du jedes Repository einzeln: Öffne im Repository Settings > General, scroll ganz nach unten in die Danger Zone, klicke auf Transfer und wähle die neue Organisation als Ziel. Issues, Pull Requests, Wiki und Verlauf ziehen mit um.

Die Adresse des Repositorys ändert sich dabei von github.com/DEIN_NAME/REPO zu github.com/DEINE_ORG/REPO. GitHub leitet die alte Adresse zwar weiter, Du solltest Dich aber nicht darauf verlassen. Pass deshalb drei Dinge sofort an:

  1. Lokale Klone. Stell in jedem lokalen Klon die Remote-Adresse um, damit git push und git pull direkt gehen:

    Code
    git remote set-url origin [email protected]:DEINE_ORG/REPO.git

    Ersetze DEINE_ORG durch den Namen der Organisation und REPO durch den Namen des Repositorys.

  2. Deployments in Coolify. Ist eine Anwendung in Coolify über die GitHub App mit dem Repository verbunden, hat die App nach dem Umzug keinen Zugriff mehr darauf, denn sie ist nur für Dein persönliches Konto installiert. Installiere die GitHub App von Coolify zusätzlich für die Organisation, gib ihr dort die Repositories frei und wähle das Repository in der Anwendung neu aus. Sonst laufen automatische Deployments nach einem Push ins Leere.

  3. Alles andere, das die Adresse kennt. Badges in der README, Links in der Doku, Webhooks zu externen Diensten und Paketquellen wie git+https://github.com/... in einer package.json.

Wenn Du das für jedes Repository einmal erledigt hast, ist der Umzug durch. Neue Repositories legst Du künftig gleich in der Organisation an.

Schritt 2: Ein Zugriffstoken für die Organisation erstellen

Der Runner meldet sich beim Start selbst bei GitHub an. Dafür braucht er einen Personal Access Token, mit dem er sich einen kurzlebigen Registrierungstoken holt. Anders als der Token aus der Weboberfläche läuft er nicht nach einer Stunde ab, und der Runner meldet sich nach jedem Neustart automatisch wieder an.

  1. Klicke bei GitHub oben rechts auf Dein Profilbild und öffne Settings > Developer settings > Personal access tokens > Fine-grained tokens.
  2. Klicke auf Generate new token.
  3. Gib als Token name zum Beispiel coolify-runner ein.
  4. Wähle bei Resource owner die Organisation, nicht Dein persönliches Konto. Taucht sie nicht auf, sind Fine-grained Tokens für die Organisation noch nicht erlaubt. Das schaltest Du in den Einstellungen der Organisation unter Personal access tokens frei.
  5. Wähle bei Expiration eine Laufzeit. Das Maximum sind 366 Tage, trag Dir das Ablaufdatum in den Kalender.
  6. Repository access kannst Du auf Public repositories lassen, der Runner braucht keinen Zugriff auf die Inhalte.
  7. Klicke unter Permissions auf Add permissions, wähle im Reiter Organizations den Eintrag Self-hosted runners und stell die Zugriffsstufe daneben von Read-only auf Read and write um.
  8. Klicke auf Generate token und kopiere den Token, der mit github_pat_ beginnt.

GitHub zeigt den Token nur dieses eine Mal an. Bewahr ihn in Deinem Passwortmanager auf, bis er in Coolify eingetragen ist. Der Token darf genau eine Sache: Runner der Organisation verwalten. An Deinen Code kommt er nicht heran.

Schritt 3: Den GitHub Runner in Coolify anlegen

Coolify bringt für den Runner ein fertiges Service-Template mit. Es nutzt das verbreitete Open-Source-Image myoung34/docker-github-actions-runner, das den offiziellen Runner von GitHub in einen Docker-Container packt und die Anmeldung über Umgebungsvariablen steuert.

  1. Öffne in Coolify Dein Projekt und die gewünschte Umgebung, etwa production.
  2. Klicke auf + New.
  3. Tippe im Suchfeld GitHub Runner ein und wähle den gleichnamigen Service aus.
  4. Wähle den Server, auf dem der Runner laufen soll, und bestätige.

Coolify legt den Service an. Wird er dabei schon gestartet, erscheint er mit dem Status Degraded, weil der Container ohne Angaben zur Organisation sofort wieder abbricht. Das ist an dieser Stelle normal. Wie Variablen in Compose-Dateien grundsätzlich funktionieren, erklärt der Artikel Docker Compose verstehen: Volumes, Netzwerke und .env.

Schritt 4: Die Environment Variables eintragen und starten

Wechsle im Service auf den Reiter Environment Variables. Das Template hat dort bereits alle Variablen angelegt, jede mit dem Hinweis Used by Compose. Am schnellsten trägst Du die Werte ein, wenn Du oben auf Developer View klickst. Dann siehst Du alle Variablen als Text im Format NAME=Wert und ersetzt den Inhalt durch:

Code
REPO_URL=
RUNNER_NAME_PREFIX=coolify-runner
RUNNER_NAME_SUFFIX=
ACCESS_TOKEN=github_pat_DEIN_TOKEN
RUNNER_SCOPE=org
LABELS=coolify
ORG_NAME=DEINE_ORG

Die Zeilen bedeuten:

VariableWertBedeutung
RUNNER_SCOPEorgDer Runner gilt für die ganze Organisation
ORG_NAMEName der OrganisationGenau so geschrieben wie in der Adresse github.com/DEINE_ORG
ACCESS_TOKENgithub_pat_…Der Token aus Schritt 2
LABELScoolifyEigenes Label, mit dem Workflows den Runner auswählen
RUNNER_NAME_PREFIXcoolify-runnerAnfang des Namens, unter dem der Runner bei GitHub erscheint
REPO_URLleer lassenNur für Runner an einem einzelnen Repository nötig

RUNNER_NAME_SUFFIX bleibt leer, der Runner hängt dann eine zufällige Zeichenfolge an den Namen. Klicke auf Save changes. Die übrigen Einstellungen im Template bleiben, wie sie sind: Der Runner checkt die Repositories in einem Docker-Volume aus, und der eingebundene Docker-Socket erlaubt es Deinen Workflows, selbst Docker-Images zu bauen.

Starte den Service danach oben mit Deploy. Lief er schon im Zustand Degraded, heißt der Knopf Restart, und Coolify fragt mit Confirm Service Restart? nach. Bestätige mit Confirm. Erst der Neustart übernimmt die neuen Variablen.

Schritt 5: Prüfen, ob der Runner online ist

Öffne im Service den Reiter Logs. Nach einigen Sekunden sollten dort, zwischen einem großen Schriftzug, diese Zeilen auftauchen:

Code
Obtaining the token of the runner
√ Connected to GitHub
√ Runner successfully added
√ Settings Saved.
√ Connected to GitHub
Listening for Jobs

Ältere Logzeilen mit REPO_URL required for repo runners stammen aus dem ersten Start ohne Variablen und sind kein Grund zur Sorge, solange am Ende Listening for Jobs steht. Der Status des Service springt auf Running.

Wechsle danach zu GitHub und öffne in der Organisation Settings > Actions > Runners. Dort steht jetzt ein Runner mit einem Namen wie coolify-runner-k3x9pq2mz7w4a, den Labels self-hosted, Linux, X64 und coolify und dem Hinweis Runner group: Default.

Öffne zum Schluss Settings > Actions > Runner groups. Die Gruppe Default sollte den Zusatz All repositories, excluding public repositories tragen. So ist sie ab Werk eingestellt, und genau so soll es bleiben: Private Repositories dürfen den Runner nutzen, öffentliche nicht. Steht dort etwas anderes, öffnest Du die Gruppe und nimmst den Haken bei der Freigabe für öffentliche Repositories heraus.

Schritt 6: Die Workflows auf den eigenen Runner umstellen

Damit ein Job auf Deinem Server läuft, änderst Du in der Workflow-Datei unter .github/workflows/ die Zeile runs-on dieses Jobs. Aus

Code
runs-on: ubuntu-latest

wird

Code
runs-on: [self-hosted, coolify]

GitHub wählt dann nur Runner, die beide Labels tragen. Ein vollständiger kleiner Workflow für ein Node-Projekt sieht damit so aus:

Code
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: [self-hosted, coolify]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - run: npm ci
      - run: npm test

Committe die Änderung und schau im Reiter Actions des Repositorys zu. In den Logs des Service in Coolify erscheint Running job: build, und unter Set up job im Log bei GitHub steht der Name Deines Runners.

Welche Jobs umziehen und welche bei GitHub bleiben

Stell nicht blind jeden Job um, sondern geh die Workflows einmal durch. Bewährt hat sich diese Aufteilung:

  • Umziehen: Jobs, die nur Code auschecken, Abhängigkeiten installieren, prüfen, testen und bauen. Das sind meist die meisten Minuten, und sie laufen auf dem eigenen Runner problemlos.
  • Bei GitHub lassen: Jobs mit einem services:-Block, etwa einer Postgres-Datenbank, die der Job über localhost:5432 anspricht. Auf GitHub laufen Job und Datenbank auf derselben Maschine, auf Deinem Runner läuft der Job dagegen in einem Container, und die Datenbank wird daneben gestartet. localhost zeigt dann ins Leere. Außerdem würde der Port der Datenbank auf Deinem Server geöffnet.
  • Bei GitHub lassen: Jobs, die mit docker compose ganze Umgebungen hochfahren und dabei Verzeichnisse aus dem Repository einbinden. Die Pfade im Runner-Container stimmen nicht mit denen auf dem Server überein.

Ein Unterschied zum Runner von GitHub ist außerdem wichtig: ubuntu-latest bringt Dutzende vorinstallierte Werkzeuge mit, Dein Runner nur das Nötigste wie Git, Docker und curl. Nutze deshalb für Sprachen und Tools die offiziellen Setup-Actions wie actions/setup-node, actions/setup-python oder actions/setup-go.

Rechne beim ersten Lauf damit, dass ein Job rot wird, der vorher grün war, ohne dass der Runner schuld ist. Typisch sind Werkzeuge ohne feste Version, etwa ruff>=0.5 in einer pyproject.toml. Seit dem letzten Lauf ist eine neuere Version mit strengeren Regeln erschienen, und der Linter meldet plötzlich Fehler. Auch Docker-Images, die es nicht mehr gibt, fallen dann auf. Schau Dir bei einem roten Job deshalb immer zuerst die Fehlermeldung an. Hat der Job die Schritte Set up job, checkout und die Setup-Action geschafft, funktioniert der Runner.

Denk auch daran, dass ein Runner immer nur einen Job gleichzeitig ausführt. Startet ein Push mehrere Jobs, warten die übrigen in der Schlange. Brauchst Du mehr Parallelität, legst Du in Coolify einen zweiten Runner-Service mit denselben Werten an. Er meldet sich mit einem anderen Zufallsnamen in derselben Organisation an.

Nur ein Repository und keine Organisation?

Wenn Du wirklich nur ein einziges privates Repository hast, kannst Du auf die Organisation verzichten. Dann setzt Du RUNNER_SCOPE=repo, trägst bei REPO_URL die volle Adresse wie https://github.com/DEIN_NAME/REPO ein und lässt ORG_NAME leer. Der Token bekommt in diesem Fall Dein persönliches Konto als Resource owner, bei Repository access genau dieses Repository und unter Repositories das Recht Administration mit Read and write. Für jedes weitere Repository brauchst Du dann einen weiteren Runner, und spätestens beim zweiten lohnt sich der Umzug in die Organisation.

Wenn es nicht klappt

Der Service bleibt auf Degraded, die Logs zeigen Invalid configuration provided for url. Der Container hat die Variablen nicht bekommen oder mit einem leeren Wert gestartet. Prüf in der Developer View, ob RUNNER_SCOPE=org und ORG_NAME gesetzt sind, speichere und starte den Service mit Restart neu. Nur speichern reicht nicht.

Der Runner taucht bei GitHub nicht auf, in den Logs steht ein Fehler wie 401 oder 403. Der Token stimmt nicht, ist für das falsche Konto ausgestellt oder hat nur Read-only. Erstell ihn mit der Organisation als Resource owner und Self-hosted runners: Read and write neu, trag ihn bei ACCESS_TOKEN ein und starte neu.

Ein Job wartet ewig auf einen Runner. Vergleiche die Labels in runs-on mit denen unter Settings > Actions > Runners der Organisation. Liegt das Repository noch in Deinem persönlichen Konto statt in der Organisation, sieht es den Runner nicht. Bei einem öffentlichen Repository verhindert die Runner-Gruppe die Nutzung absichtlich.

Der Runner war wochenlang offline und ist verschwunden. GitHub entfernt Self-hosted Runner automatisch, die 14 Tage lang keine Verbindung hatten. Ein Neustart des Service meldet ihn mit dem Token neu an. Ist der Token abgelaufen, erstellst Du einen neuen.

Die Festplatte läuft voll. Wenn Deine Workflows Docker-Images bauen, sammeln sich alte Images auf dem Server. Coolify kann sie unter Servers > Dein Server > Docker Cleanup regelmäßig automatisch entfernen lassen.

Ein Wort zur Sicherheit auf dem Server

Der Runner bekommt Zugriff auf den Docker-Socket des Servers. Das ist praktisch, weil Deine Workflows dadurch Docker-Images bauen können, bedeutet aber auch: Wer in ein Repository der Organisation pushen darf, kann über einen Workflow Container auf diesem Server starten und stoppen, auch die von Coolify selbst. Für Deine eigenen privaten Repositories ist das in Ordnung, denn es ist Dein Code. Sobald andere Personen Schreibzugriff haben oder der Server wichtige Produktivdienste trägt, gehört der Runner auf einen eigenen kleinen Server. In Coolify fügst Du dafür unter Servers einen zweiten Server per SSH hinzu und wählst ihn in Schritt 3 als Ziel aus.

Die Workflow-Secrets aus GitHub landen während eines Jobs auf Deinem Server. Behandle den Runner-Server deshalb wie jeden anderen Server mit Zugangsdaten: Updates einspielen, SSH nur mit Schlüssel, keine fremden Dienste daneben.

Mehr als nur gesparte Minuten

Den eigenen Runner richten viele erst ein, wenn die Warnmail kommt. Wenn Du den Aufwand nicht scheust, lohnt es sich aber, ihn grundsätzlich zu nutzen, auch wenn Du Dein Kontingent noch nicht ausschöpfst.

  • Schnellere Builds. Der Runner auf GitHub startet jedes Mal in einer frischen virtuellen Maschine und lädt alle Abhängigkeiten neu. Dein Runner behält heruntergeladene Node-Versionen, Docker-Layer und Paket-Caches, solange der Container läuft.
  • Freie Wahl der Hardware. Du entscheidest über CPU, RAM und Architektur. Ein Runner auf einem ARM-Server baut ARM-Images nativ, ein Runner mit GPU kann Modelle testen, und ein großer Build bekommt einfach mehr Kerne.
  • Zugriff aufs eigene Netz. Der Runner baut nur ausgehende HTTPS-Verbindungen zu GitHub auf, Du musst keinen Port öffnen. Trotzdem erreicht er Datenbanken, Staging-Server oder Deploy-Ziele in Deinem internen Netz, ohne dass Du sie ins Internet stellen musst.
  • Planbare Kosten. Ein Server kostet jeden Monat dasselbe, egal ob Dein Coding-Agent zehn oder tausend Läufe startet.

Genau diese Punkte sind der Grund, warum Unternehmen ihre CI-Pipelines häufig auf eigenen Runnern betreiben. Quellcode, Build-Artefakte und Zugangsdaten verlassen während des Builds die eigene Infrastruktur nicht, was bei Vorgaben zu Datenschutz und Compliance oft entscheidend ist. Die Firma bestimmt selbst, welche Software in der Build-Umgebung installiert ist, wann sie aktualisiert wird und wer darauf zugreift, und kann jeden Build nachvollziehbar protokollieren. Außerdem macht sie sich weniger abhängig von Preisänderungen und Kontingenten eines einzelnen Anbieters, und genau das hat die angekündigte und dann verschobene Gebühr für Self-hosted Runner gezeigt. Wer diesen Gedanken konsequent weiterführt, holt sich am Ende auch das Git-Hosting ins eigene Haus, etwa mit Forgejo: eigener Git-Server mit Docker statt GitHub, dessen Workflows sich stark an GitHub Actions anlehnen.

Für ein paar Monate mit knappem Kontingent ist ein Budget bei GitHub der schnellere Weg. Wer aber dauerhaft viel mit KI-Agenten arbeitet und ohnehin Coolify betreibt, hat mit einem Runner für die ganze Organisation die Warnmails einmal sauber erledigt.

Weiterlesen.