SpyBara
Go Premium

self-hosted-environments-deploy.md 2026-10-09 23:02 UTC to 2026-10-10 17:02 UTC

This page contains 135 additions and 18 deletions.

2026
Fri 2 22:59 Sun 4 23:58 Mon 5 23:58 Tue 6 23:59 Sat 10 18:02

Selbstgehostete Umgebungen in der Produktion bereitstellen

Führen Sie selbstgehostete Runner in der Produktion aus: Sicherheitshärtung, Netzwerk-Egress-Kontrolle, Git-Anmeldedaten, Kubernetes- und Compose-Rezepte und Fehlerbehebung.

Eine selbstgehostete Umgebung führt Claude Code Cloud-Sitzungen auf Runnern aus, die Sie in Ihrem Netzwerk bereitstellen, und in der Produktion führen diese Sitzungen modellgesteuerten Code im Namen aller aus, die eine Sitzung in der Umgebung starten können. Diese Seite ist für den Operator, der eine funktionierende Umgebung in die Produktion nimmt. Sie durchläuft die Bereitstellung der Reihe nach: was vor dem Verbinden mit echten Systemen gesperrt werden muss, welcher Egress die Flotte benötigt, wie Sitzungen sich bei Ihrem Git-Host authentifizieren, die Bereitstellungsrezepte selbst und was zu überprüfen ist, wenn Sitzungen nicht ordnungsgemäß funktionieren.

Härten Sie Ihre Bereitstellung

Ein selbstgehosteter Runner führt beliebigen, modellgesteuerten Code auf Ihrer Infrastruktur im Namen aller aus, die eine Sitzung in seiner Umgebung starten können. Das ist jedes Mitglied Ihrer Anthropic-Organisation und jeder, der eine Claude Tag-Kanalsitzung in einem Bereich starten kann, den ein Owner zur Umgebung weitergeleitet hat. Arbeiten Sie jedes Element durch, bevor Sie eine Umgebung mit Produktionssystemen verbinden:

  • Ephemere, sitzungsspezifische Container: Führen Sie jeden Runner-Prozess in einem frischen Container oder einer VM aus, die zerstört wird, wenn der Prozess beendet wird, mit --capacity 1 und dem Standard --drain-grace-sec 0, sodass jeder Container genau eine Sitzung bedient. Bei einer höheren Kapazität oder mit einer positiven Drain-Grace bedient ein Container mehrere Sitzungen vom selben gesperrten Owner; siehe Runner-Lebenszyklus. Verwenden Sie kein Dateisystem zwischen Runner-Neustarts wieder, außer in der absichtlichen vorgewärmten Checkout-Einrichtung, und niemals über Owners hinweg.

    • Wenn der Runner eine Sitzung beendet, sendet er kein Signal an einen Prozess, der nach dem Beenden seines Shell-Befehls noch läuft, etwa einen Dienst, der sich als Daemon abgelöst hat. Das Zerstören des Containers oder der VM beendet diesen Prozess.
  • Keine breiten Anmeldedaten im Image: Fügen Sie keine langlebigen SSH-Schlüssel, Cloud-Provider-Anmeldedaten oder persönliche Zugriffstokens ein, die mehr gewähren als eine Sitzung benötigt. Erstellen Sie Anmeldedaten, die während einer Sitzung verwendet werden, wie Push- oder API-Tokens, pro Sitzung aus Ihrem Wrapper-Skript. Der anfängliche Clone findet statt, bevor der Wrapper ausgeführt wird. Verwenden Sie dafür daher einen checkout-Lebenszyklus-Hook oder --use-anthropic-git-proxy, wenn alle Repositorys einer Sitzung auf github.com liegen. Zu beiden siehe Git konfigurieren.

  • Halten Sie die GitHub-Anmeldedaten des Hosts von Sitzungen fern: Claude kann alle GitHub-Anmeldedaten verwenden, die eine Sitzung lesen kann, mit dem Zugriff, den diese Anmeldedaten gewähren. Halten Sie die eigenen, weit gefassten GitHub-Anmeldedaten des Runner-Hosts aus allem heraus, was eine Sitzung lesen kann. Solche Anmeldedaten können ein persönliches Zugriffstoken sein, das Token, das gh auth login für Ihr Konto speichert, oder ein GH_TOKEN in der Umgebung des Runners.

  • Halten Sie das Umgebungsgeheimnis von sitzungsausführenden Hosts fern: Das Umgebungsgeheimnis kann Runner registrieren und jede Sitzung abholen, die in der Umgebung in die Warteschlange eingereiht ist. In einer festen Flotte lebt es auf jedem Runner-Host, wo jeder Sitzungscode das Geheimnisdatei lesen kann. Bevorzugen Sie On-Demand-Runner, bei denen das Geheimnis auf dem Orchestrator-Host bleibt, der niemals Benutzercode ausführt, und jeder Runner einen einmaligen Arbeitsauftrag erhält, der genau einen Runner registriert. Behandeln Sie in einer festen Flotte die Umgebungsgeheimnisdatei als von jeder Sitzung lesbar und rotieren Sie das Geheimnis nach jedem vermuteten Sitzungskompromiss.

  • Standard-Deny-Netzwerk-Egress: Beschränken Sie den ausgehenden Datenverkehr von Runner- und Sitzungs-Containern an Ihrer eigenen Netzwerkgrenze in jeder Umgebung; Standard-Deny-Egress behandelt, was erlaubt ist und warum.

  • Least-Privilege-Host-IAM: Die Compute-Identität, die an den Runner-Host angehängt ist, wie ein Instance-Profil oder ein Node-Service-Konto, sollte nur das gewähren, was der Runner selbst benötigt. Sitzungen sollten ihre eigenen Anmeldedaten über Ihr Wrapper-Skript erhalten, anstatt die des Hosts zu erben.

  • Blockieren Sie den Cloud-Metadaten-Endpunkt von Sitzungen: Um Sitzungen von der Host-Identität fernzuhalten, müssen Sie ihren Zugriff auf den Cloud-Metadaten-Endpunkt blockieren, und Subnetz-Level-Egress-Richtlinien unterbrechen keinen Link-Local-Metadaten-Datenverkehr, daher blockieren Sie ihn im Container selbst:

    • IMDSv2 mit einem Hop-Limit von eins
    • GKE Workload Identity mit Metadaten-Verbergung
    • Ein explizites Deny für 169.254.169.254 im Netzwerk-Namespace des Sitzungs-Containers

    Der Block gilt auch für Ihr Wrapper-Skript und Lebenszyklus-Hooks, da sie den Container teilen. Authentifizieren Sie jeden Token-Austausch mit dem Sitzungs-JWT gegen Ihren eigenen Token-Service über zulassungslisten-Egress, oder verwenden Sie eine dateibasierte Web-Identität wie IAM Roles for Service Accounts (IRSA) auf Amazon EKS.

  • Pro-Runner-Dateisystem-Isolation: Jeder Runner-Prozess erhält sein eigenes Arbeitsverzeichnis, das kein anderer Prozess auf dem Host lesen oder schreiben kann. Machen Sie --hooks-dir, das Wrapper-Skript und das ~/.claude/-Verzeichnis des Hosts für die Sitzung schreibgeschützt, entweder in das Image eingebaut oder schreibgeschützt eingebunden.

  • Dispatch hat keine Pro-Umgebungs-Zugriffskontrolle: Jedes Mitglied Ihrer Anthropic-Organisation kann eine Sitzung in jede ihrer Umgebungen starten. Wenn ein Owner Claude Tag-Kanäle zur Umgebung leitet, kann jeder, den die Claude Tag-Zugriffssetting zulässt, Kanalsitzungen starten, die dort ausgeführt werden. Standardmäßig ist das jeder im verbundenen Slack-Workspace, mit oder ohne Claude-Konto. Behandeln Sie jeden Runner-Host als erreichbar für die Codeausführung durch jeden, der ihn starten kann, und platzieren Sie auf einem Runner-Host nur Daten und Anmeldedaten, die alle diese Personen lesen dürfen. --lock-to-account begrenzt, welche Konten-Sitzungen ein bestimmter Host ausführt, aber es verengt nicht, wer in die Umgebung starten kann. Um selbstgehostete Umgebungen zur einzigen Picker-Option zu machen, kann ein Owner Anthropic-gehostete Umgebungen für die ganze Organisation auf der Cloud-Umgebungen-Seite ausblenden.

  • Erzwingen Sie die Repo-Settings-Guard: Wählen Sie den Guard-Modus mit --confine-repo-settings. Der Standard warn protokolliert eine Verletzung und startet die Sitzung trotzdem, enforce lehnt die Sitzung ab, und off deaktiviert den Scan. Der Runner scannt die festgeschriebenen Einstellungen jedes Repositorys auf:

    • Eine Berechtigung, die außerhalb des eigenen Workspace dieser Sitzung aufgelöst wird: ein additionalDirectories-Eintrag, eine Edit-, Write- oder NotebookEdit-Regel in permissions.allow, oder ein sandbox.filesystem.allowWrite- oder allowRead-Eintrag
    • Ein nicht leerer env-Block
    • Eine Operator-Haltungs-Überschreibung wie sandbox.enabled: false

    Die Guard läuft unabhängig von --trust-workspace und deckt keine Repository-Hooks, .mcp.json oder Bash-Regeln ab; siehe Berechtigungen und Tool-Genehmigung für den Ort dieser Berechtigungen.

Netzwerkanforderungen

Der Runner und die Sitzungs-Kinder, die er spawnt, stellen ausgehende Verbindungen zu den folgenden Hosts her. Beschränken Sie den Sitzungs-Container-Egress auf diese Hosts und die spezifischen internen Services, die Sitzungen erreichen müssen; Standard-Deny-Egress behandelt wie und warum.

Diese Hosts sind immer erforderlich:

Host Port Verwendet für
api.anthropic.com 443, HTTPS; WSS für von Anthropic verwaltetes Git Runner-Kontrollebene und Sitzungs-Streaming, Modell-Inferenz, Feature-Flags, Produkt-Analytik, JWKS-Schlüssel-Abrufe, Commit-Signierung und von Anthropic verwaltetes Git, wenn --use-anthropic-git-proxy gesetzt ist
Ihr Git-Host, wie github.com oder Ihr GitHub Enterprise-Host 443 oder 22 Klonen und Pushen von Repositorys auf jedem Git-Host, den die Sitzungen des Runners verwenden. Auf einem Runner, der --use-anthropic-git-proxy verwendet, siehe wann der github.com-Pfad weiterhin benötigt wird.

Ein Runner, der --use-anthropic-git-proxy verwendet, leitet seinen Git-Datenverkehr für github.com über api.anthropic.com und benötigt daher den Git-Host-Pfad für github.com nicht. Er benötigt diesen Pfad weiterhin, wenn Sie --push-outcome-on-release setzen oder aus einem post-session-Hook pushen.

Ob diese Hosts erforderlich sind, hängt von Ihrer Konfiguration ab:

Host Port Wenn erforderlich
downloads.claude.ai 443 Zur Installationszeit, wenn Sie Claude Code auf dem Host mit dem nativen Installer installieren oder aktualisieren; das install.sh-Skript selbst wird von claude.ai bereitgestellt. Zur Sitzungs-Laufzeit nur, wenn Sitzungen Plugins vom offiziellen Anthropic-Marketplace installieren.
storage.googleapis.com 443 Zur Sitzungs-Laufzeit für die Plugin-Installationszähler und Metadaten, die in /plugin angezeigt werden.
code.claude.com und claude.com 443 Dokumentations-Lookups durch den integrierten Claude-Code-Guide-Agent und vorab genehmigte WebFetch-Anfragen während Sitzungen. Das Blockieren dieser Hosts betrifft nur Dokumentations-Lookups.
*.frame.claudeusercontent.com 443 Nur wenn das Artifact-Tool für Sitzungen in Ihrer Organisation verfügbar ist; die Standardwerte variieren je nach Plan, gemäß der Verfügbarkeitstabelle dort. Setzen Sie CLAUDE_CODE_DISABLE_ARTIFACT=1 auf dem Runner, um das Tool unabhängig von der Organisationseinstellung deaktiviert zu halten.
registry.npmjs.org 443 Wenn eine Sitzung ein Plugin installiert, sowohl zum Abrufen von npm-Quell-Plugin-Paketen als auch zum Installieren der Node.js-Abhängigkeiten eines Plugins, oder wenn ein npx-gestarteter MCP-Server läuft
http-intake.logs.us5.datadoghq.com 443 Anthropic-Betriebsmetriken. Nur wenn CLAUDE_CODE_BYOC_ENABLE_DATADOG=1 gesetzt ist; standardmäßig in selbstgehosteten Umgebungen deaktiviert.
browser-intake-us5-datadoghq.com 443 Anthropic-Fehlerberichts-Uploads, nur gesendet wenn Fehlerberichterstattung für das Konto der Sitzung aktiviert ist. Unterdrückt durch DISABLE_ERROR_REPORTING=1 oder DISABLE_TELEMETRY=1.
Die Endpunkte Ihres Cloud-Anbieters für Modellanfragen, Modell-Lookups und das Erneuern von Anmeldedaten, wie bedrock-runtime.us-east-1.amazonaws.com oder aiplatform.googleapis.com 443 Nur wenn der Runner Modellanfragen an Amazon Bedrock oder die Agent Platform von Google Cloud sendet

Diese Hosts müssen Sie für Runner- oder Sitzungs-Datenverkehr nicht in die Allowlist aufnehmen:

  • statsig.anthropic.com, *.sentry.io, claude.ai und platform.claude.com: Diese Hosts erscheinen in einigen älteren Enterprise-Netzwerk-Checklisten, aber der Runner erreicht sie nicht. Feature-Flag-Abrufe gehen zu api.anthropic.com, und der Runner authentifiziert sich mit dem Umgebungsgeheimnis anstelle von interaktivem OAuth.
  • mcp-proxy.anthropic.com: Selbstgehostete Sitzungen verwenden es nicht. Wenn die Bereitstellung von Konnektoren für Ihre Organisation aktiviert ist, erreichen die claude.ai-Konnektoren Ihrer Organisation die Sitzungen über api.anthropic.com. Siehe MCP-Server.

Diese Host-seitigen Flows erreichen claude.ai, führen Sie sie daher von einem Host aus, dessen Egress dies erlaubt, anstatt den Sitzungs-Container-Egress zu erweitern:

  • Der Einzeilen-Installer: Ruft install.sh zur Installationszeit von claude.ai ab.
  • Interaktives claude auth login: Meldet sich über claude.ai, claude.com und platform.claude.com an. Das geführte Setup, der angemeldete Modus von doctor und CI-Dispatch verwenden es. Der Browser, mit dem Sie sich anmelden, lädt außerdem die Browser-Prüfungen der claude.ai-Anmeldeseite von hcaptcha.com, *.hcaptcha.com und challenges.cloudflare.com.

Standard-Deny-Egress

Stellen Sie Runner- und Sitzungs-Container in einem Netzwerk-Segment oder Namespace bereit, dessen ausgehender Datenverkehr auf die Hosts in der Netzwerkanforderungs-Tabelle, Ihren Git-Host und die spezifischen internen Services begrenzt ist, die Sitzungen erreichen müssen. Das Produkt kann dies nicht überprüfen oder erzwingen, daher wenden Sie es an Ihrer eigenen Netzwerkgrenze in jeder Umgebung an. Sitzungscode ist modellgesteuert und kann Verbindungen zu beliebigen Hosts versuchen; Standard-Deny-Egress auf der Netzwerkebene begrenzt, wo diese Versuche landen können. Dies gilt unabhängig vom Berechtigungsmodus: Der Standard-Vorab-Genehmigungstool-Satz enthält bereits Bash, daher läuft Shell-Egress ohne Eingabeaufforderung auch ohne Auto-Modus.

Für Details darüber, welche Telemetrie jede Sitzung aussendet und wie man sie ausschaltet, siehe Telemetrie.

Authentifizieren Sie sich bei einem Egress-Proxy

Einige Corporate-Egress-Proxys erfordern einen Proxy-Authorization-Header bei jeder Verbindung. Das Token in diesem Header rotiert oft zu schnell, um es in die Proxy-URL zu schreiben, die Sie in HTTPS_PROXY setzen. Setzen Sie HTTPS_PROXY oder HTTP_PROXY wie gewohnt auf die URL Ihres Proxys, dann setzen Sie --proxy-authorization-command oder --proxy-authorization-file, um dem Runner zu sagen, wo er den Header-Wert lesen soll. Beide Flags erfordern Claude Code v2.1.238 oder später.

Wählen Sie, woher der `Proxy-Authorization`-Wert kommt

Wählen Sie das Flag, das der Art entspricht, wie Sie das Proxy-Authorization-Token erzeugen:

  • --proxy-authorization-command <command>: Wählen Sie dies für ein Token, das Sie bei Bedarf generieren. Der Runner führt das Shell-Kommando aus und verwendet seine getrimmte Standardausgabe als Header-Wert, zum Beispiel Bearer <token>.
  • --proxy-authorization-file <path>: Wählen Sie dies für ein Token, das ein anderer Prozess an Ort und Stelle rotiert. Der Runner liest die Datei und verwendet ihren getrimmten Inhalt als Header-Wert.

Konfigurationen, die der Runner ablehnt zu starten

Jedes Flag hat auch eine Umgebungsvariablen-Form, die neben ihm in der Runner-CLI-Flags-Referenz aufgelistet ist. Bevor der Runner Ihren Proxy oder die Kontrollebene kontaktiert, überprüft er die Flags und ihre Variablen und lehnt in drei Fällen ab zu starten:

  • Beide Flags gesetzt: Ein Flag plus die Umgebungsvariable des anderen Flags zählt als Setzen beider.
  • Keine Proxy-URL: Weder HTTPS_PROXY noch HTTP_PROXY enthält eine http://- oder https://-URL. Der Runner liest beide Variablen in Groß- oder Kleinbuchstaben und konsultiert nicht ALL_PROXY.
  • Eines der Flags an den Orchestrator-Subcommand übergeben: self-hosted-runner orchestrator akzeptiert die Flags oder ihre Umgebungsvariablen nicht. Übergeben Sie das Flag stattdessen an jeden Runner, den der Orchestrator startet.

Was der Runner ändert, während ein Proxy-Autorisierungs-Flag gesetzt ist

Mit einem der Flags gesetzt, startet der Runner seinen eigenen Listener und sendet Proxy-Datenverkehr von sich selbst, seinen Lebenszyklus-Hooks und seinen Sitzungen durch diesen Listener. Der Listener fügt den Proxy-Authorization-Header auf dem Weg zu Ihrem Proxy hinzu.

  • Listener: Der Listener ist ein Forward-Proxy auf 127.0.0.1. Der Runner startet den Listener vor der Registrierung bei der Kontrollebene und beendet sich beim Start, wenn der Listener nicht starten kann.
  • Proxy-Variablen: Der Runner schreibt whichever von HTTPS_PROXY und HTTP_PROXY um, die Sie setzen, damit es auf den Listener zeigt. Dieser umgeschriebene Wert erreicht den Runner selbst, seine Lebenszyklus-Hooks und jede Sitzung, die er ausführt.
  • Token-Rotation: Ein rotiertes Token wird ohne Neustart wirksam. Für jede Verbindung, die der Listener zu Ihrem Proxy öffnet, führt der Runner Ihren Befehl aus oder liest Ihre Datei erneut und fügt das Ergebnis als Header hinzu.
  • Sitzungs-Umgebung: Eine Sitzung erreicht Ihren Proxy nur durch den Listener. In der Umgebung jeder Sitzung entfernt der Runner ALL_PROXY, entfernt jede Schreibweise von HTTPS_PROXY oder HTTP_PROXY, die Sie nicht gesetzt haben, und pinnt NO_PROXY auf den Wert des Runners.
  • Logs: Der Runner protokolliert niemals den Header-Wert.

Git konfigurieren

Der Runner verwaltet Repository-Checkouts, konfiguriert aber standardmäßig nicht die Git-Identität oder Anmeldedaten. Sie kontrollieren das Runner-Image und die Prozessumgebung, daher kontrollieren Sie die Git-Konfiguration. Wählen Sie einen von zwei Ansätzen:

  • Lassen Sie den Runner Git konfigurieren: Starten Sie den Runner mit --configure-git, um die gleiche Identität und Commit-Signierungskonfiguration zu schreiben, die Anthropic-gehostete Sitzungen verwenden
  • Versenden Sie Git-Konfiguration in Ihrem Image: Setzen Sie Identität und Push-Anmeldedaten selbst, zum Beispiel um unter Ihrer eigenen Bot-Identität zu committen

Für Repositorys auf github.com können Sie den Runner auch mit --use-anthropic-git-proxy starten oder CLAUDE_RUNNER_USE_GIT_PROXY=1 setzen, um Anthropic zu bitten, Git für die Sitzungen des Runners bereitzustellen.

Git-Versionsuntergrenzen auf dem Runner-Host: --configure-git SSH-Commit-Signierung erfordert Git 2.34 oder neuer, --use-anthropic-git-proxy erfordert 2.32 oder neuer, und das Fortsetzen von Sitzungen von Branches, die von --push-outcome-on-release gepusht werden, erfordert 2.29 oder neuer. Git 2.24 ist ausreichend, wenn Sie alle drei weglassen und die Git-Identität selbst verwalten.

Lassen Sie den Runner Git konfigurieren

Starten Sie den Runner mit --configure-git, oder setzen Sie SELF_HOSTED_RUNNER_CONFIGURE_GIT=1, um die globale Git-Konfiguration beim Start zu schreiben:

  • user.name = Claude und user.email = noreply@anthropic.com, passend zu Anthropic-gehosteten Sitzungen
  • SSH-Format-Commit- und Tag-Signierung, geleitet durch einen Runner-verwalteten Shim, der jeden Commit über Anthropic's Signierungsservice mit den Anmeldedaten der Sitzung signiert. Signaturen sind auf GitHub gegen Anthropic's veröffentlichten SSH-Signierungsschlüssel überprüfbar.
  • push.negotiate = true, damit Git Ihren Git-Host fragt, welche Commits er bereits hat, bevor er einen Push packt. Erfordert Claude Code v2.1.257 oder später.
  • core.hooksPath, das auf ein Runner-verwaltetes Hooks-Verzeichnis zeigt. Seine commit-msg- und prepare-commit-msg-Hooks fügen jedem Commit einen Co-authored-by:-Trailer für den Ersteller der Sitzung hinzu. Der Trailer wird aus der E-Mail in CCR_SESSION_ACCOUNT_EMAIL erstellt und weggelassen, wenn diese Variable nicht gesetzt ist. Wenn Ihr Image bereits core.hooksPath setzt und der Runner kein Anthropic-verwaltetes Git verwendet, behält der Runner Ihre Einstellung bei, überspringt die Installation dieser Hooks und gibt eine [runner:git]-Warnung aus.

Commit-Signierung erfordert Git 2.34 oder neuer; der Runner überprüft beim Start und beendet sich mit einem Fehler, wenn Ihr Git älter ist. Dieses Flag konfiguriert keine Push-Anmeldedaten, die Sie immer noch im Image bereitstellen.

Auf einem Runner mit v2.1.280 oder später werden Commits, die Sie aus einem checkout- oder post-session-Lebenszyklus-Hook erstellen, ebenfalls als die Sitzung signiert, ohne den Co-authored-by:-Trailer. Git-Konfiguration innerhalb von Lebenszyklus-Hooks beschreibt die Git-Einstellungen, die der Runner innerhalb dieser Hooks festlegt.

Mit oder ohne --configure-git weist Claude Code Claude an, seine Commit-Nachrichten mit einem Claude-Session: <url>-Trailer und seine Pull-Request-Beschreibungen mit der URL der Sitzung abzuschließen. Um beides wegzulassen, setzen Sie attribution.sessionUrl in der ~/.claude/settings.json des Runner-Hosts auf false und starten Sie den Runner anschließend neu.

Versenden Sie Git-Konfiguration in Ihrem Image

Git-Identität ist für jeden Commit erforderlich. Setzen Sie sie systemweit in Ihrem Dockerfile, damit die Konfiguration unabhängig davon gilt, welcher Benutzer den Runner-Prozess ausführt:

RUN git config --system user.name "Claude" && \
    git config --system user.email "noreply@anthropic.com"

Ohne eine Identität schlägt git commit mit Please tell me who you are fehl und Sitzungen können nicht voranschreiten. Sie können stattdessen Ihre eigene Bot-Identität verwenden; der Runner überschreibt diese Werte nicht.

Backen Sie keine langlebigen oder breit gefassten Push-Anmeldedaten in ein gemeinsames Runner-Image: Anmeldedaten im Image sind für jede Sitzung verfügbar, die das Image ausführt, wer auch immer sie gestartet hat. Erstellen Sie stattdessen ein kurzlebiges, minimal gefasstes Token pro Sitzung aus Ihrem Wrapper-Skript, unter Verwendung der Identität des Sitzungs-Erstellers, die aus dem Sitzungs-JWT dekodiert ist. Paaren Sie es mit einem ephemeren Pro-Sitzungs-Container, der --capacity 1 erfordert, damit keine Anmeldedaten die Sitzung überleben, die sie erstellt hat; siehe den Härtungsabschnitt.

Wenn Sie Push-Anmeldedaten auf Image-Ebene konfigurieren müssen, zum Beispiel für einen schreibgeschützten Deploy-Schlüssel, begrenzen Sie sie so eng wie Ihr Git-Host erlaubt:

  • Ein SSH-Deploy-Schlüssel, der auf ein Repository mit einer url.<base>.insteadOf-Umschreibung begrenzt ist
  • Ein credential.helper, der ein minimal gefasstes Token zurückgibt
  • GIT_SSH_COMMAND, das auf einen eng gefassten Schlüssel zeigt

Welcher Mechanismus Sie auch konfigurieren, muss ohne Eingabeaufforderung funktionieren, da der integrierte Clone und Fetch des Runners die Eingabeaufforderungen deaktivieren, die Git, SSH und Git Credential Manager sonst zeigen würden:

  • Der Runner setzt GIT_TERMINAL_PROMPT=0, daher fragt Git nicht nach Benutzername oder Passwort.
  • Der Runner führt SSH mit BatchMode=yes aus, angehängt an Ihren GIT_SSH_COMMAND, wenn Sie einen setzen, daher fragt SSH nicht nach einer Passphrase oder Host-Bestätigung.
  • Der Runner setzt GCM_INTERACTIVE=never, daher öffnet Git Credential Manager keinen Anmeldedialog.
  • Der Runner löscht core.askPass, daher setzen Sie es, wenn Sie einen Askpass-Helper verwenden, stattdessen durch die GIT_ASKPASS-Umgebungsvariable.

Wenn Ihr Git-Host die Anmeldedaten ablehnt, oder Sie haben keine konfiguriert, versucht der Runner ein paar Mal erneut und schlägt dann fehl bei der Repository-Vorbereitung, wenn das Repository das ist, in das die Sitzung Ergebnisse pusht. Für ein Repository, das die Sitzung nur liest, behandelt Troubleshooting den Fall, wenn der Runner es stattdessen überspringt. Der Runner übergibt diese Einstellungen nicht in die Umgebung der Sitzung.

Halten Sie jedes Programm, das Sie in GIT_SSH_COMMAND oder GIT_ASKPASS benennen, dort, wo Sitzungen nicht darauf schreiben können, wie die Härtungs-Checkliste für das Hooks-Verzeichnis und das Wrapper-Skript verlangt. Das Gleiche gilt für jeden Schlüssel oder jede Datei in der Befehlszeile dieses Programms. Der Runner's eigenes Git führt dieses Programm aus, wenn es klont oder abruft.

Wenn Checkout-Verzeichnisse einem anderen uid als dem Runner-Prozess gehören, weigert sich Git, auf ihnen zu arbeiten; fügen Sie safe.directory hinzu:

RUN git config --system --add safe.directory '*'

Verwenden Sie den Anthropic-Git-Proxy

Mit dem Anthropic-Git-Proxy, auch Anthropic-verwaltetes Git genannt, benötigt das Runner-Image für die Sitzung selbst keine SSH-Schlüssel, keinen Credential-Helper, keine .netrc und keine anderen Git-Anmeldedaten. Stattdessen bittet der Runner Anthropic, Git für seine Sitzungen bereitzustellen. Bei einer Benutzersitzung, für die Anthropic Git bereitstellt, laufen der Clone des Runners sowie die eigenen Fetches und Pushes der Sitzung über Anthropic, das das für den Ersteller der Sitzung gespeicherte GitHub-OAuth-Token verwendet. Wie Anthropic Git für eine Sitzung bereitstellt behandelt Bot- und Agentensitzungen.

Der Git-Proxy ist ausgeschaltet, sofern Sie ihn nicht einschalten. Ein Runner, der Ihren Git-Host mit eigenen Anmeldedaten erreicht, benötigt ihn nicht, und sein Git funktioniert mit jedem Git-Host.

Im Gegenzug schränkt der Git-Proxy ein, was der Runner unterstützt, und ändert, was er benötigt:

  • Nur github.com: Anthropic stellt Git für eine Sitzung nur bereit, wenn sich alle ihre Repositorys auf github.com befinden, und der Git-Proxy unterstützt GitHub Enterprise Server noch nicht. Auf einem Runner mit dem Git-Proxy startet eine Sitzung nicht, wenn sie ein Repository auf einem anderen Git-Host hat.
  • Anmeldedaten nur für die Repositorys der Sitzung: Anthropic stellt Git-Anmeldedaten für die Repositorys bereit, die Teil der Sitzung sind, nicht für andere Repositorys auf demselben Git-Host. Ein privates Submodul, eine Abhängigkeit, die Ihr Paketmanager mit Git abruft, oder ein Plugin-Marketplace in einem anderen Repository erhält keine Anmeldedaten von Anthropic. Bitten Sie die Personen, die Sitzungen erstellen, beim Erstellen jedes Repository hinzuzufügen, das eine Sitzung benötigt.
  • Nur Branch-Pushes: Ein Push, der einen Branch löscht, schlägt fehl, ebenso ein Push auf jede andere Art von Ref, etwa ein Tag. Welche Branches ein Push aktualisieren kann, erfahren Sie unter GitHub-Proxy.
  • Verbundene GitHub-Konten: Die Person, die eine Benutzersitzung erstellt hat, muss GitHub auf claude.ai verbunden haben, sonst startet die Sitzung nicht.
  • --capacity 1: Der Git-Proxy erfordert eine Sitzung pro Runner-Prozess, führen Sie daher mehr Replicas für Parallelität aus. Den Anthropic-Git-Proxy einschalten listet die Anforderungen auf.
  • Ersetzte globale Git-Konfiguration: Der Runner löscht und ersetzt die globale Git-Konfiguration des Benutzers, unter dem er läuft. Führen Sie ihn als dedizierten Benutzer oder in einem Container aus.
  • Host-Anmeldedaten für Host-Pushes: Der Push des Runners über --push-outcome-on-release und jeder Push, den Ihr post-session-Hook ausführt, verwenden weiterhin die eigenen Git-Anmeldedaten des Runner-Hosts und dessen Netzwerkpfad zu github.com. Informationen zu diesen Anmeldedaten finden Sie unter Versenden Sie Git-Konfiguration in Ihrem Image.
  • Entscheidung pro Sitzung: Anthropic entscheidet für jede Sitzung auf dem Runner, ob es deren Git bereitstellt, und eine Sitzung, für die es das nicht tut, startet nicht. Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten behandelt die Ursachen.

Bewahren Sie Git-Einstellungen, die nicht geheim sind, wie die Identität und safe.directory, in der System-Git-Konfiguration auf.

Den Anthropic-Git-Proxy einschalten

Bevor Sie den Runner mit --use-anthropic-git-proxy starten, vergewissern Sie sich, dass der Runner-Host jede dieser Anforderungen erfüllt. Der Runner verweigert den Start, wenn die Kapazitäts- oder Git-Anforderung nicht erfüllt ist:

  • Claude Code v2.1.267 oder später: Frühere Versionen akzeptieren das Flag, melden Anthropic aber nicht die Anfrage, Git bereitzustellen, und geben die Zeile Registering as opted in nicht aus, daher stellt Anthropic für ihre Sitzungen kein Git bereit.
  • --capacity 1, der Standardwert: Jeder Runner-Prozess verarbeitet jeweils eine Sitzung, daher führen Sie mehr Replicas für Parallelität aus.
  • Git 2.32 oder neuer: Älteres Git ignoriert die Git-Konfiguration pro Sitzung, die der Runner für den Git-Proxy einrichtet.

Um den Git-Proxy einzuschalten, fügen Sie dem Befehl des Runners --use-anthropic-git-proxy hinzu oder setzen Sie CLAUDE_RUNNER_USE_GIT_PROXY=1 in der Umgebung des Runners. Dieser Befehl, in einer Shell auf dem Runner-Host ausgeführt, startet den Runner aus dem Schnellstart mit eingeschaltetem Git-Proxy:

claude self-hosted-runner --environment-secret-file '/etc/claude/environment-secret' --base-dir '<writable-dir>' --use-anthropic-git-proxy

Beim Start gibt der Runner Registering as opted in to Anthropic-managed git (--use-anthropic-git-proxy) aus. Anthropic entscheidet dann für jede Sitzung auf diesem Runner, ob es deren Git bereitstellt. Für jede Sitzung, für die es Git bereitstellt, protokolliert der Runner eine [runner:session]-Zeile, die governed git ACTIVE enthält. Wenn eine Sitzung stattdessen nicht startet, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten.

Wie Anthropic Git für eine Sitzung bereitstellt

Bei einer Sitzung, für die Anthropic Git bereitstellt, laufen der Clone des Runners sowie die eigenen Fetches und Pushes der Sitzung über Anthropic, authentifiziert mit dem eigenen kurzlebigen Token der Sitzung:

  • Benutzersitzungen: Anthropic verwendet das für den Ersteller der Sitzung gespeicherte GitHub-OAuth-Token.
  • Bot- und Agentensitzungen: Anthropic verwendet das GitHub-App-Installations-Token Ihrer Organisation.
  • URL-Umschreibungen: --git-host-rewrite und --git-ssh-rewrite haben keine Auswirkung auf ein Repository, das der Git-Proxy bereitstellt.

Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten

Auf einem Runner, der mit --use-anthropic-git-proxy gestartet wurde, startet eine Sitzung nicht, wenn Anthropic kein Git für sie bereitstellt. Suchen Sie im Log des Runners nach einem Git-Fehler, der eine api.anthropic.com-Adresse mit /git_proxy/ nennt.

Für jede Sitzung protokolliert ein Runner mit Claude Code v2.1.267 oder später außerdem entweder eine [runner:session]-Zeile mit governed git ACTIVE, wenn Anthropic Git für die Sitzung bereitstellt, oder eine [runner:warn]-Zeile mit the server withheld Anthropic-managed git for this session, wenn nicht. Suchen Sie die Zeile, die Sie sehen, unter diesen Fällen:

  • Weder governed git ACTIVE noch die withheld-Zeile: Ein Runner, der älter als Claude Code v2.1.267 ist, protokolliert keine der beiden Zeilen, und Anthropic stellt für seine Sitzungen kein Git bereit. Aktualisieren Sie den Runner auf v2.1.267 oder später, indem Sie Die Version festlegen folgen.
  • Die withheld-Zeile: Anthropic hat kein Git für die Sitzung bereitgestellt. Ein Runner, der zuvor mit dem Git-Proxy funktioniert hat, kann auf diese Weise fehlschlagen, ohne dass Sie etwas geändert haben.
    • Ein Repository liegt nicht auf github.com: Für eine Sitzung mit auch nur einem Repository auf einem anderen Git-Host, etwa GitHub Enterprise Server, wird kein Git bereitgestellt, auch nicht für ihre github.com-Repositorys. Schalten Sie den Anthropic-Git-Proxy aus für die Runner dieser Umgebung.
    • Jedes Repository liegt auf github.com: Melden Sie den Fehler Ihrem Anthropic-Account-Team mit der Sitzungs-ID aus der withheld-Zeile. Anthropic erfasst den Grund auf seiner Seite.
  • Eine Zeile mit remote: access denied by the git proxy: Auch eine Sitzung, für die Anthropic Git bereitstellt, kann abgewiesen werden, zum Beispiel wenn eine Organisationsrichtlinie den Git-Zugriff für die Sitzung verweigert oder die Sitzung nicht für das Repository autorisiert ist. Das Log des Runners zeigt dann eine Zeile mit remote: access denied by the git proxy, und der Rest dieser Zeile nennt den Grund.
  • GitHub authentication required: Dies erscheint, wenn der Ersteller der Sitzung keine funktionierende GitHub-Verbindung auf claude.ai hat. Der Clone der Sitzung schlägt fehl, und der Git-Fehler lautet GitHub authentication required. Please reconnect your GitHub account. Bitten Sie diese Person, GitHub in ihren claude.ai-Einstellungen zu verbinden oder erneut zu verbinden.

Nachdem Sie die Ursache behoben haben, starten Sie die fehlgeschlagenen Sitzungen erneut.

Den Anthropic-Git-Proxy ausschalten

Wenn Sitzungen in einer Umgebung ein Repository auf einem anderen Git-Host als github.com verwenden, etwa GitHub Enterprise Server, schalten Sie --use-anthropic-git-proxy für die Runner dieser Umgebung aus.

1

Flag entfernen

Entfernen Sie --use-anthropic-git-proxy aus dem Befehl des Runners. Wenn Sie CLAUDE_RUNNER_USE_GIT_PROXY in der Umgebung des Runners gesetzt haben, etwa in einer Pod-Spezifikation oder einer Compose-Datei, entfernen Sie es dort. Heben Sie es in einer Shell auf:

unset CLAUDE_RUNNER_USE_GIT_PROXY
2

Dem Runner Git-Anmeldedaten geben

Stellen Sie Anmeldedaten bereit, die ohne Eingabeaufforderung für jeden Git-Host funktionieren, den die Sitzungen der Runner verwenden, github.com eingeschlossen. Alle Anmeldedaten, die in der globalen Git-Konfiguration des Runner-Benutzers lagen, sind verloren, weil der Runner diese Konfiguration gelöscht hat, während --use-anthropic-git-proxy gesetzt war. Liefern Sie Anmeldedaten in Ihrem Image mit oder verwenden Sie einen checkout-Lebenszyklus-Hook.

3

Netzwerkpfad öffnen

Erlauben Sie dem Runner, jeden Git-Host, den die Sitzungen der Runner verwenden, über Port 443 oder 22 zu erreichen. Siehe die Zeile für den Git-Host unter Netzwerkanforderungen.

4

Runner neu starten

Starten Sie die Runner neu, damit sie sich ohne den Git-Proxy registrieren. Starten Sie dann jede fehlgeschlagene Sitzung erneut.

GitHub-API-Zugriff ohne die GitHub CLI

Wenn Ihr Runner-Image die GitHub CLI nicht enthält, kann Claude Code ein integriertes gh bereitstellen, sodass Claude weiterhin Pull Requests öffnen, kommentieren und CI-Ergebnisse lesen kann. Das integrierte gh ist für Runner gedacht, die Anthropic-verwaltetes Git verwenden. Es unterstützt einen einzigen Befehl, gh api, der die REST-API von GitHub aufruft. Erfordert Claude Code v2.1.287 oder später im Runner-Image.

Dieser Befehl öffnet einen Pull Request anstelle von gh pr create. Das integrierte gh füllt {owner} und {repo} für das aktuelle Repository aus:

gh api repos/{owner}/{repo}/pulls -f title='Fix' -f head='my-branch' -f base='main'
  • Anmeldedaten: Das integrierte gh sendet seine REST-Anfragen über Anthropic-verwaltetes Git, das die GitHub-Anmeldedaten auf Anthropic's Seite bereitstellt, daher benötigt das Image dafür kein GitHub-Token
  • Welche Sitzungen es erhalten: Anthropic entscheidet pro Sitzung, ob Anthropic-verwaltetes Git das gh der Sitzung bedient. Wenn ja, zeigt die Zeile [runner:session] governed git ACTIVE, die der Runner für die Sitzung protokolliert, gh_path_shim=true. Wenn nicht, hat die Sitzung kein gh
  • jq: Installieren Sie jq im Image, wenn --jq funktionieren soll
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: Wenn die Sitzungsumgebung diese Variable setzt, stellt Claude Code das integrierte gh nicht bereit, und die Sitzung hat kein gh

Wenn das Image die GitHub CLI enthält, verwenden Sitzungen diese.

Vertrauen Sie einer privaten Zertifizierungsstelle mit Anthropic-verwaltetem Git

Dieser Abschnitt gilt, wenn Sie GIT_SSL_CAINFO oder GIT_SSL_NO_VERIFY in der Umgebung eines Runners setzen, dessen Sitzungen Anthropic-verwaltetes Git verwenden. Die hier beschriebene Behandlung erfordert, dass der Runner Claude Code v2.1.283 oder später ausführt.

Wenn Git auf dem Runner einer privaten Zertifizierungsstelle (CA) vertrauen muss, wie beispielsweise der, die ein TLS-inspizierender Proxy signiert, funktionieren die üblichen Ansätze wie folgt:

  • System-Zertifikatspeicher: Installieren Sie Ihre CA im System-Zertifikatspeicher des Runner-Hosts, und Git vertraut ihr ohne eine der beiden Variablen.
  • GIT_SSL_CAINFO: Setzen Sie sie auf eine PEM-Datei Ihrer CAs, zum Beispiel GIT_SSL_CAINFO=/etc/ssl/corp-ca.pem.
  • GIT_SSL_NO_VERIFY: hilft nicht hinter einem Neu-Signierungs-Proxy. Der Runner's eigener Clone durch Anthropic-verwaltetes Git überprüft Zertifikate auch wenn die Variable gesetzt ist, daher schlägt dieser Clone fehl, bis Git Ihrer CA durch einen der anderen beiden Ansätze vertraut.

Für Git-Verbindungen, die ein Sitzungs-Token zu Anthropic-verwaltetem Git tragen, wendet der Runner die beiden Variablen wie folgt an. Ein command-Hook beginnt mit der Umgebung der Sitzung, daher erhält er, was Git innerhalb der Sitzung erhält:

  • GIT_SSL_CAINFO: Was Git gegen Anthropic-verwaltetes Git überprüft, hängt davon ab, wo Git ausgeführt wird:
    • Runner's eigener Clone und Abrufe: Laufen ohne die Variable und überprüfen Anthropic-verwaltetes Git gegen eine Pro-Sitzungs-Zertifikatsdatei, die der Runner schreibt. Diese Datei enthält das System-CA-Bundle des Runner-Hosts plus die Zertifikate aus Ihrer Datei.
    • Git innerhalb der Sitzung: Erhält http.sslCAInfo-Konfiguration, die Ihre Datei anstelle der Variable benennt, plus http.<url>.sslCAInfo-Einträge, die Anthropic-verwaltetes Git gegen die Pro-Sitzungs-Datei überprüfen.
    • checkout- und post-session-Hooks: Erben die Variable unverändert.
  • GIT_SSL_NO_VERIFY: Welche Zertifikatsüberprüfungen ausgeschaltet bleiben, hängt davon ab, wo Git ausgeführt wird:
    • Runner's eigener Clone und Abrufe: Laufen ohne die Variable und überprüfen das Zertifikat, das ihnen präsentiert wird.
    • Git innerhalb der Sitzung: Erhält http.sslVerify=false-Konfiguration anstelle der Variable, daher bleiben Überprüfungen für andere Hosts ausgeschaltet. Es erhält auch http.<url>.sslVerify=true-Einträge, die Überprüfungen für Anthropic-verwaltetes Git eingeschaltet halten.
    • checkout- und post-session-Hooks: Wenn die Sitzung ein Repository auf Anthropic-verwaltetem Git hat, erhalten http.sslVerify=false-Konfiguration anstelle der Variable. Sie erhalten auch http.<url>.sslVerify=true-Einträge, die Überprüfungen für Anthropic-verwaltetes Git eingeschaltet halten.

Die Pro-Sitzungs-Zertifikatsdatei benötigt ein System-CA-Bundle unter /etc/ssl/certs/ca-certificates.crt oder /etc/pki/tls/certs/ca-bundle.crt auf dem Runner-Host. Sie benötigt auch eine GIT_SSL_CAINFO-Datei, die der Runner's Benutzer lesen kann, die PEM-CERTIFICATE-Blöcke enthält, und die höchstens 1 MiB groß ist. Wenn der Runner die Pro-Sitzungs-Datei nicht erstellen kann, protokolliert er eine [runner:warn]-Zeile, die did not build the certificate file und den Grund enthält. Git verwendet dann Ihre Datei wie sie ist für Anthropic-verwaltetes Git. Beheben Sie, was die Zeile benennt.

Für jede Sitzung, die Anthropic-verwaltetes Git verwendet, protokolliert der Runner auch eine [runner:warn]-Zeile, die mit governed git: GIT_SSL_CAINFO is set oder governed git: GIT_SSL_NO_VERIFY is set beginnt. Die Zeile sagt, was der Runner mit dieser Variable für sein eigenes Git, für Git innerhalb der Sitzung und für Ihre Lebenszyklus-Hooks getan hat. Sie endet damit, ob Sie etwas ändern müssen.

Schreiben Sie Git-URLs für private Netzwerke um

Repository-URLs kommen von der Kontrollebene als HTTPS mit dem Hostnamen Ihres Git-Hosts; für GitHub Enterprise ist das der Hostname, den Sie für die GitHub Enterprise-Integration auf claude.ai konfiguriert haben. Zwei wiederholbare Flags schreiben diese URLs vor dem Clone um:

  • --git-host-rewrite <from>=<to>: für Split-Horizon-DNS, wo Anthropic Ihren Git-Host über einen externen Hostnamen erreicht, aber Runner einen internen verwenden müssen
  • --git-ssh-rewrite <host>: für Git-Hosts, die nur SSH akzeptieren, Umschreiben von https://<host>/owner/repo zu git@<host>:owner/repo

Host-Umschreibung läuft zuerst, daher listen Sie den internen Hostnamen in --git-ssh-rewrite auf, wenn Sie beide benötigen. Für vollständige Kontrolle über Checkout verwenden Sie einen checkout-Lebenszyklus-Hook.

Erstellen Sie das Runner-Image

Anthropic veröffentlicht kein vorgefertigtes Runner-Image. Erstellen Sie Ihr eigenes um die claude-Binärdatei, schichten Sie ein, was auch immer Ihre Repositorys benötigen: Sprach-Laufzeiten, Compiler, Paket-Manager und MCP-Sidecars.

Die Rezepte unten verwenden --capacity 4, daher bedient ein Container bis zu vier gleichzeitige Sitzungen vom selben gesperrten Owner. Das bietet nicht die Pro-Sitzungs-Container-Isolation im Härtungsabschnitt: Bevor Sie eine Umgebung mit Produktionssystemen verbinden, führen Sie entweder die Rezepte bei --capacity 1 mit einem Container pro Sitzung aus, oder verwenden Sie On-Demand-Runner, die auch das Umgebungsgeheimnis von sitzungsausführenden Hosts fernhalten. Wenn Sie den Anthropic-Git-Proxy zu einem dieser Rezepte hinzufügen, ändern Sie auch --capacity auf 1.

Dieses Dockerfile ist ein minimaler Ausgangspunkt:

FROM debian:bookworm-slim
ARG CLAUDE_CODE_VERSION
RUN apt-get update && apt-get install -y --no-install-recommends git curl ca-certificates openssh-client jq \
 && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL "https://downloads.claude.ai/claude-code-releases/${CLAUDE_CODE_VERSION:?set with --build-arg CLAUDE_CODE_VERSION}/linux-x64/claude" \
      -o /usr/local/bin/claude && chmod +x /usr/local/bin/claude
RUN git config --system user.name "Claude" \
 && git config --system user.email "noreply@anthropic.com" \
 && git config --system --add safe.directory '*'
ENTRYPOINT ["claude"]

Tauschen Sie linux-x64 gegen linux-arm64 aus, wenn Ihre Knoten ARM sind, oder gegen linux-x64-musl oder linux-arm64-musl auf einem musl-basierten Image wie Alpine; siehe Alpine Linux-Setup für die zusätzlichen Pakete, die musl-Images benötigen. Die URL ist der Standard-Claude-Code-Release-Ort, daher können Sie die heruntergeladene Binärdatei gegen das signierte Manifest des Release überprüfen, wie in Binäre Integrität und Code-Signierung beschrieben. Der Runner erfordert Claude Code Version 2.1.224 oder später. Erstellen Sie das Image, pushen Sie es dann in Ihre Registry und referenzieren Sie es in den Rezepten unten:

docker build \
  --build-arg CLAUDE_CODE_VERSION="$(curl -fsSL https://downloads.claude.ai/claude-code-releases/stable)" \
  -t <your-registry>/claude-runner:latest .

Die Befehlsersetzung schlägt die aktuelle stable-Release-Nummer nach und übergibt sie als Build-Argument, daher wird das Image nach einer neuen stabilen Release durch Ausführung desselben Befehls mit der neueren Binärdatei neu erstellt. Um eine bestimmte Release für reproduzierbare Builds zu fixieren, übergeben Sie die Versionsnummer direkt als CLAUDE_CODE_VERSION. Ersetzen Sie stable durch latest in der Nachschlag-URL, wenn Sie eine Release benötigen, die neuer als der stabile Kanal ist, z. B. eine, die ein neu gestartetes Modell erfordert.

Dimensionieren Sie CPU und Speicher für Sitzungen

Dimensionieren Sie einen Runner-Container oder Host für die Sitzungen, die er ausführt, anstatt für den Runner-Prozess. Der Runner selbst fragt nach Arbeit ab, bereitet den Checkout jeder Sitzung vor, führt Ihre Lebenszyklus-Hooks aus und startet und überwacht die Sitzungs-Prozesse. Die Last kommt von den Sitzungen: Jede ist ein Claude Code-Prozess plus alles, was sie startet, wie Builds, Test-Suites, Paket-Installationen und MCP-Server.

Für eine Sitzung beginnen Sie mit den folgenden Werten, angegeben als Kubernetes-Anfragen und Limits oder das Äquivalent Ihrer Plattform, und behandeln Sie sie als Ausgangspunkt anstatt als Anforderung:

  • Speicher: eine Anfrage und ein Limit von jeweils 4 GiB, was das 4-GB-Minimum in Claude Code's Systemanforderungen erfüllt. Halten Sie die beiden gleich, damit der Scheduler die volle Speicherkapazität des Containers berücksichtigt. Wenn der Container sein Speicherlimit erreicht, tötet der Kernel Prozesse darin, was eine Sitzung mitten in einer Aufgabe beenden kann.
  • CPU: eine Anfrage von 2 CPUs und ein Limit von 4 CPUs, daher kann eine Sitzung während Builds über die Anfrage hinaus platzen. Der Kernel drosselt einen Container bei seinem CPU-Limit, anstatt Prozesse darin zu töten, daher laufen Sitzungen am Limit langsamer, aber laufen weiter.

In einer Kubernetes-Container-Spezifikation setzen Sie diese Startwerte mit dem folgenden resources-Block:

resources:
  requests:
    cpu: "2"
    memory: 4Gi
  limits:
    cpu: "4"
    memory: 4Gi

Builds und Tests sind normalerweise der größte und variabelste Teil der Last einer Sitzung, daher führen Sie einen repräsentativen Build Ihres Repositorys aus, messen Sie seinen Peak-CPU und Speicher, und erhöhen Sie jeden Startwert, der keinen Platz für den Claude Code-Prozess auf diesem Peak lässt.

Der Runner verwendet --capacity, um zu begrenzen, wie viele Sitzungen er gleichzeitig ausführt. Er teilt CPU oder Speicher nicht zwischen ihnen, daher teilen sich die Sitzungen auf einem Runner die CPU und den Speicher des Containers. Um die Freigabe einer Sitzung zu begrenzen, wenden Sie Limits aus Ihrem Wrapper-Skript an. Was Sie einem Container geben, hängt daher davon ab, wie viele Sitzungen er gleichzeitig bedient:

  • Eine Sitzung pro Runner: Geben Sie jedem Container die Werte einer Sitzung. Verwenden Sie diese Dimensionierung bei --capacity 1, das der Härtungsabschnitt empfiehlt, und für On-Demand-Runner, wo Sie die Werte auf der Workload setzen, die Ihr spawn-runner-Hook einreicht, wie ein Kubernetes Job's Pod-Template.
  • Mehrere Sitzungen pro Runner: Bei einem --capacity über eins multiplizieren Sie die Werte einer Sitzung mit der Kapazität, weil bis zu so viele Sitzungen gleichzeitig im Container laufen können. Die Kubernetes- und Docker Compose-Rezepte führen --capacity 4 ohne CPU- oder Speicherlimits aus, daher fügen Sie Limits hinzu, die für die Kapazität dimensioniert sind, die Sie ausführen.

Kubernetes

Der Runner bedient GET /healthz auf Port 8080 standardmäßig, konfigurierbar mit --health-port, daher funktionieren Kubernetes-Probes ohne zusätzliches Setup. Der Endpunkt gibt 200 zurück, wann immer der Prozess lebt, daher erkennen die Probes unten einen toten Prozess, nicht einen steckengebliebenen; um einen Runner zu fangen, der aufgehört hat zu pollen, warnen Sie die last_poll_age_seconds-Serie von /metrics. Die Deployment unten bindet das Umgebungsgeheimnis von einem Kubernetes Secret, zeigt die Liveness- und Readiness-Probes auf /healthz und setzt eine 90-Sekunden-Terminierungs-Grace-Periode. Siehe Shutdown-Timing für warum die Grace-Periode wichtig ist.

Das Manifest setzt keine CPU- oder Speicher-resources auf dem Runner-Container. Fügen Sie einen Block hinzu, der für die Kapazität dimensioniert ist, die Sie ausführen, wie Dimensionieren Sie CPU und Speicher für Sitzungen beschreibt.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: claude-runner
  namespace: claude-runners
spec:
  replicas: 3
  selector:
    matchLabels:
      app: claude-runner
  template:
    metadata:
      labels:
        app: claude-runner
        app.kubernetes.io/part-of: claude-code-self-hosted-runner
    spec:
      terminationGracePeriodSeconds: 90
      containers:
        - name: runner
          image: <your-registry>/claude-runner:latest
          args:
            - self-hosted-runner
            - --environment-secret-file
            - /etc/claude/environment-secret
            - --capacity
            - "4"
          volumeMounts:
            - name: environment-secret
              mountPath: /etc/claude
              readOnly: true
          ports:
            - name: health
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 30
      volumes:
        - name: environment-secret
          secret:
            secretName: claude-runner-environment-secret

Die Deployment oben lebt in einem claude-runners-Namespace. Erstellen Sie den Namespace zuerst:

kubectl create namespace claude-runners

Erstellen Sie das zugrunde liegende Secret aus einer lokalen Datei, die den Wert enthält, den Sie im Copy environment key-Schritt der Admin-UI kopiert haben, damit das Geheimnis niemals in Ihrer Shell-Historie erscheint. Führen Sie (umask 077 && cat > ./environment-secret) aus, fügen Sie das Geheimnis ein, drücken Sie Enter und dann Ctrl-D. Erstellen Sie anschließend das Secret und löschen Sie die Datei:

kubectl create secret generic claude-runner-environment-secret -n claude-runners --from-file=environment-secret=./environment-secret

Docker Compose

Der Compose-Service unten startet den Runner neu, wann immer er beendet wird, was sowohl Crashes als auch den normalen Exit nach dem Draining abdeckt. Eine Docker-Restart-Richtlinie startet den gleichen Container mit seiner beschreibbaren Schicht intakt neu, daher kommt der Runner auf einem wiederverwendeten Dateisystem anstatt dem frischen, das die Härtungs-Haltung empfiehlt; verwenden Sie dieses Rezept zur Evaluierung, und für die Produktion entweder den Container pro Lauf neu erstellen oder einen Orchestrator verwenden, der das tut.

Docker wartet länger, bevor jeder Neustart eines Containers erfolgt, der weiterhin beendet wird, bis zu einer Obergrenze, daher startet ein Runner, der nicht gestartet werden kann, nicht in einer engen Schleife unter diesem Rezept neu. Wenn der Runner beendet wird beschreibt, was zu überprüfen ist, wenn das passiert.

services:
  claude-runner:
    image: <your-registry>/claude-runner:latest
    command:
      - self-hosted-runner
      - --environment-secret-file
      - /run/secrets/environment-secret
      - --capacity
      - "4"
    secrets:
      - environment-secret
    restart: always
    stop_grace_period: 90s

secrets:
  environment-secret:
    file: ./environment-secret

Zeitverhalten beim Herunterfahren

Nach SIGTERM benötigt ein Runner Zeit, um seine Sitzungen sauber herunterzufahren, bevor Ihr Orchestrator ihn beendet. Wie lange, protokolliert er beim Start in einer Zeile, die bei Standardeinstellungen This runner needs up to 80s enthält. Setzen Sie das Stopp-Timeout Ihres Orchestrators auf mindestens so viele Sekunden: terminationGracePeriodSeconds unter Kubernetes, stop_grace_period unter Docker Compose oder das Äquivalent Ihrer Plattform. Kubernetes verwendet standardmäßig 30 Sekunden, sodass es ohne diese Einstellung den Pod stoppen kann, bevor der Runner fertig ist.

Bei SIGTERM nimmt der Runner keine neuen Sitzungen mehr an. Anschließend beginnt er ein geordnetes Herunterfahren, den sogenannten Drain, sofern Sie nicht --defer-shutdown-max-min setzen, um ihn aufzuschieben. Der Drain besteht aus drei Schritten:

  1. Der Runner wartet bis zu --drain-wait-sec Sekunden, standardmäßig 0, darauf, dass noch laufende Turns abgeschlossen werden.
  2. Er beendet den Prozessbaum jeder Sitzung, einschließlich aller Befehle, die Claude noch ausgeführt hat, jedoch nicht einen Prozess, der nach dem Ende seines Shell-Befehls noch läuft.
  3. Er führt den post-session-Lifecycle-Hook aus.

Der Runner fragt während des gesamten Drains weiterhin bei Anthropic ab. Dadurch bleiben seine Sitzungen ihm zugewiesen, sodass kein anderer Runner eine davon übernimmt, während Ihr post-session-Hook noch nicht committete Arbeit sichert.

Da --drain-wait-sec standardmäßig 0 ist, unterbricht ein Rolling Restart jeden noch laufenden Turn, und die Sitzung wird auf einem anderen Runner ohne ihre nicht gepushte Arbeit fortgesetzt. Damit Turns zuerst abgeschlossen werden können, setzen Sie --drain-wait-sec und erhöhen Sie Ihr Stopp-Timeout entsprechend.

Die protokollierte Dauer ist die Summe dieser Werte:

Mit Standardeinstellungen ergibt das 0 + 5 + 60 + 15 = 80 Sekunden. Eine höhere --capacity erhöht diesen Wert nicht, da der Runner alle seine Sitzungen gleichzeitig leert.

Planen Sie mehr Zeit ein, wenn Sie eines dieser Flags setzen:

  • Mit --retire-at: Bemessen Sie den Abstand zwischen dem Retire-Zeitpunkt und dem Stopp-Zeitpunkt des Hosts so, dass er typische Turns abdeckt, zuzüglich der Wartezeit für Hintergrundaufgaben, die unter Runner-Lebenszyklus beschrieben ist, zuzüglich der protokollierten Dauer. Berechnen Sie den Retire-Zeitpunkt bei jedem Start, beispielsweise date +%s plus die vorgesehene Lebensdauer des Runners.
  • Mit --defer-shutdown-max-min: Das Stopp-Timeout muss zusätzlich die von Ihnen konfigurierten Minuten abdecken sowie eine weitere Wartezeit vor Beginn des Drains, mit Standardeinstellungen 75 Sekunden. Das Leeren über das erste Signal hinaus aufschieben erläutert beides. Der Runner protokolliert diese längere Dauer ebenfalls beim Start.

Das Leeren über das erste Signal hinaus aufschieben

Setzen Sie --defer-shutdown-max-min <n>, wenn ein Runner, den Sie neu starten, die von ihm gehaltenen Sitzungen noch bis zu n Minuten weiter bedienen soll, statt sie beim ersten Signal zu leeren. Beim ersten SIGTERM oder SIGINT nimmt der Runner keine neue Arbeit mehr an und bedient die von ihm gehaltenen Sitzungen weiter. Er fragt weiterhin ab, damit die Control Plane diese Sitzungen nicht neu einreiht. Erfordert Claude Code v2.1.238 oder höher.

Was nach dem ersten Signal mit den vom Runner gehaltenen Sitzungen geschieht

In den ersten beiden Phasen nach dem Signal gibt der Runner Sitzungen frei, und eine freigegebene Sitzung wird auf einem neuen Runner fortgesetzt, wenn ihr Benutzer die nächste Nachricht sendet. Ab dem ersten Signal gerechnet durchläuft der Runner drei Phasen:

  • Während der ersten n Minuten: Der Runner bedient seine Sitzungen normal und setzt --startup-timeout-min und --kill-session-after-min weiterhin durch. Wenn Sie zusätzlich --release-idle-session-min setzen, gibt der Runner jede Sitzung frei, deren Benutzer so lange inaktiv war; ohne dieses Flag bleiben inaktive Sitzungen auf dem Runner.
  • Wenn die n Minuten abgelaufen sind: Der Runner gibt jede Sitzung frei, die er noch hält, ob inaktiv oder nicht. Bei einer Sitzung mitten in einem Turn wartet der Runner, bis der Turn endet, und bis zu 60 weitere Sekunden auf die Hintergrundaufgaben des Turns, bevor er diese Sitzung freigibt.
  • Wenn die Grace nach der Freigabe abgelaufen ist: Der Runner leert alle Sitzungen, die er noch hält, und die Control Plane reiht jede geleerte Sitzung sofort bei einem anderen Runner neu ein. Die Grace nach der Freigabe beginnt, wenn die n Minuten abgelaufen sind, und beträgt mit Standardwerten 75 Sekunden. Wenn Sie --drain-wait-sec auf mehr als 60 Sekunden setzen, beträgt die Grace nach der Freigabe stattdessen --drain-wait-sec plus 15 Sekunden.

In jeder Phase beendet sich der Runner mit Exit-Code 0, sobald er keine Sitzungen mehr hält. Ein zweites Signal verkürzt die Phasen: Der Runner leert sofort, so wie er es beim ersten Signal ohne --defer-shutdown-max-min tut. Sobald ein Leeren im Gange ist, erzwingt das nächste Signal das Beenden des Runners. Das gilt unabhängig davon, ob ein zweites Signal oder der Ablauf der Grace nach der Freigabe das Leeren ausgelöst hat.

Das Stopp-Timeout bemessen

Geben Sie dem Stopp-Timeout Ihres Hosts mindestens die Summe aus drei Anteilen: die von Ihnen konfigurierten n Minuten, die Grace nach der Freigabe und den Drain, der unter Zeitverhalten beim Herunterfahren beschrieben ist. Mit Standardeinstellungen beträgt die Grace nach der Freigabe 75 Sekunden und der Drain dauert bis zu 80 Sekunden, planen Sie also n Minuten plus 155 Sekunden ein. Der Runner gibt diese Summe beim Start aus, wann immer --defer-shutdown-max-min gesetzt ist.

Wenn das Stopp-Timeout abläuft, bevor der Runner fertig ist, beendet der Host den Runner zwangsweise. Die Sitzungen, die er noch hält, erhalten keinen post-session-Hook. Der Runner meldet sich nicht ab, und die Control Plane reiht die Sitzungen innerhalb weniger Minuten neu ein. Wenn Sie dem Stopp-Timeout diese Summe nicht geben können, lassen Sie --defer-shutdown-max-min ungesetzt, damit der Runner stattdessen beim ersten Signal leert.

Was einen laufenden post-session-Hook erreicht

Der post-session-Hook und der Claude-Sitzungs-Kindprozess laufen jeweils in einer eigenen POSIX-Prozessgruppe, getrennt von der des Runners, sodass Stopp-Mechanismen sie unterschiedlich erreichen:

  • Ein SIGTERM, während der Runner bereits leert: erzwingt das sofortige Beenden des Runners und überspringt den verbleibenden Rest des Drains. Ohne --defer-shutdown-max-min ist das das zweite SIGTERM, das der Runner empfängt. Nichts sendet einem laufenden post-session-Hook ein Signal, sodass er auf einem Bare-Host, auf dem ein Init-Prozess verwaiste Prozesse übernimmt, eigenständig zu Ende läuft, jedoch unbeaufsichtigt: Sein Timeout-Budget gilt nicht mehr, und ein Schreibvorgang in die geschlossene Log-Pipe kann ihn mit SIGPIPE beenden. Ein Hook, der dort ein erzwungenes Beenden überstehen muss, sollte seine eigene Ausgabe daher in eine Datei umleiten. In den Container-Rezepten auf dieser Seite ist der Runner PID 1 des Containers und sein Beenden beendet den Container, und unter dem systemd-Standard KillMode=control-group erreicht das cgroup-weite Beenden auch den Hook, wie der Eintrag Cgroup-weite Kills beschreibt; behandeln Sie in beiden Fällen ein erzwungenes Beenden als fatal für den Hook und verlassen Sie sich stattdessen auf die Grace Period.
  • Prozessgruppenweite Signale, etwa kill -- -<pid> in einem Wrapper-Skript, Shell-Jobsteuerung oder ein gruppenweiter Watchdog: erreichen den Runner und einen Unterprozess eines laufenden checkout-Hooks, der absichtlich an die Gruppe gebunden bleibt, aber keinen laufenden post-session-Hook und nicht den Sitzungs-Kindprozess.
  • Cgroup-weite Kills, etwa der systemd-Standard KillMode=control-group oder das SIGKILL, das Kubernetes an den gesamten Container sendet, wenn terminationGracePeriodSeconds abläuft: erreichen alles, einschließlich des Hooks. Die Isolation der Prozessgruppe schützt davor nicht, weshalb die Grace Period den gesamten Drain abdecken muss.
  • Das eigene Timeout des Hooks: Wenn ein Hook --post-session-hook-timeout-sec überschreitet, sendet der Runner SIGTERM an die gesamte Prozessgruppe des Hooks und zwei Sekunden später SIGKILL, sodass ein vom Hook abgespaltener Worker, etwa tar, rsync oder git, zusammen mit der Wrapper-Shell beendet wird, statt als verwaister Prozess weiterzuleben. Die Überwachung durch den Runner endet, sobald die stdio des Hooks geschlossen wird: Ein Worker, der seine eigene Ausgabe in eine Datei umgeleitet hat und die SIGTERM-Phase überlebt, liegt außerhalb der Reichweite des Runners.

Wenn das Leeren beginnt, und erneut bei einem erzwungenen Beenden, protokolliert der Runner, wie viele post-session-Hooks noch laufen, sodass Sie ein ruhiges Leeren von einem unterscheiden können, das sich mitten in einem Snapshot befindet.

Halten Sie das Basis-Verzeichnis und die Kapazität über Runner identisch

Wenn ein Runner Mid-Sitzung stirbt, requeued der Server die Sitzung und ein anderer Runner in der Umgebung hebt sie auf. Dieser Runner leitet den Checkout-Pfad von seinem eigenen --base-dir und --capacity ab: --capacity 1 checkt direkt unter --base-dir aus, und ein --capacity über 1 verwendet stattdessen Pro-Sitzungs-Worktrees. Wenn Runner in der gleichen Umgebung unterschiedliche Werte für eines der Flags verwenden, ändert sich das Arbeitsverzeichnis der fortgesetzten Sitzung, und absolute Pfade, die der Agent früher aufgezeichnet hat, in Edits, Tool-Aufrufen oder seinen eigenen Notizen, zeigen auf einen Ort, der nicht mehr existiert.

Verwenden Sie den gleichen --base-dir und --capacity auf jedem Runner in einer Umgebung, und verwenden Sie keinen Pro-Host-Wert wie eine Instance-ID oder einen Hostnamen.

Das Basis-Verzeichnis standardmäßig auf /workspace, mit der Ausnahme, die die --base-dir-Referenz-Zeile aufzeichnet. Der Runner benötigt Schreibzugriff darauf. Beim Start, vor der Registrierung, erstellt der Runner das Verzeichnis und bestätigt, dass er darin schreiben kann, und beendet sich mit cannot create or write to base directory, wenn er nicht kann. Ein Runner, der als Root gestartet wird, erstellt das Standard /workspace selbst. Für einen Non-Root-Runner erstellen Sie das Verzeichnis und geben Sie dem Runner's Benutzer Eigentum, bevor Sie den Runner starten, oder zeigen Sie --base-dir auf ein Verzeichnis, das dieser Benutzer bereits besitzt.

Wiederverwendung eines vorgewärmten Checkouts

Bei großen Repositories kann das Klonen den Sitzungsstart dominieren. Um das kalte Klonen zu überspringen, stellen Sie selbst einen Klon unter dem Pfad bereit, an dem der Runner seinen eigenen Klon ablegt. Ohne checkout Hook behält der Runner einen kanonischen Klon pro Repository unter <base-dir>/<repo-owner>/<repo> und verwendet ihn über Sitzungen hinweg erneut:

  • Bei --capacity 1: Der Runner ruft die angeforderte Referenz ab, trennt HEAD ab und setzt hart darauf zurück, was nahezu augenblicklich ist, wenn sich wenig geändert hat.
  • Bei einer --capacity größer als eins: Der Runner ruft in diesen Klon ab und checkt dann für jede Sitzung einen separaten Worktree daraus aus. Ein vorgewärmter Klon spart den Download, aber nicht den Checkout.

Stellen Sie den Klon im Image oder auf einem persistenten Volume bereit:

  • Klon im Image: Erstellen Sie den Klon in Ihrem Runner-Image unter diesem Pfad. Jeder neue Container startet dann mit dem warmen Klon, ohne eine Festplatte wiederzuverwenden.
  • Klon auf einem persistenten Volume: Bei Runnern, die Sie mit --lock-to-account auf das Konto eines Benutzers sperren, verweisen Sie --base-dir auf ein persistentes Volume, sodass die Festplatte nur diesem Konto dient. Ein gesperrter Runner akzeptiert niemals Claude Tag Channel-Sitzungen, daher gilt diese Option nicht für Runner, die diese bedienen.

Was der Wiederverwendungspfad garantiert und nicht garantiert:

  • Jede Klonform funktioniert: Ein vollständiger, flacher oder Single-Branch-Klon unter dem Pfad wird unverändert verwendet. Der Runner übergibt niemals --depth beim Abrufen in einen vorhandenen Klon, daher behält ein vollständiger Vorwärm seine vollständige Historie und ein flacher bleibt flach. CLAUDE_RUNNER_FETCH_DEPTH (full, 0 oder eine Zahl; Standard 50) steuert nur den kalten Klon, den der Runner erstellt, wenn noch kein Klon vorhanden ist.

  • Nachverfolgte Änderungen werden zurückgesetzt, nicht nachverfolgte Dateien bleiben erhalten: Bei --capacity 1 beginnt jede Sitzung mit einem harten Zurücksetzen, das die nachverfolgten Änderungen der vorherigen Sitzung löscht, aber der Runner führt niemals git clean aus, daher bleiben nicht nachverfolgte Dateien aus früheren Sitzungen des gesperrten Besitzers im Baum.

  • Per-Session-Verzeichnisse bleiben ebenfalls erhalten: Neben dem Checkout erstellt der Runner für jede Sitzung, die er ausführt, Einträge pro Sitzung unter <base-dir>/_sessions/. Das Claude-Konfigurationsverzeichnis der Sitzung enthält eine lokale Kopie des Gesprächstranskripts. Daneben befinden sich die hochgeladenen Dateien der Sitzung, falls die Sitzung welche hat. Das Sitzungsverzeichnis befindet sich auch dort: Es enthält alle Pro-Session-Worktrees und checkout Hook-Checkouts während der Sitzung ausgeführt wird, und es behält alles andere, was Claude darin geschrieben hat.

    Standardmäßig lässt der Runner diese an Ort und Stelle, wenn die Sitzung endet, daher sammeln sie sich auf einer Festplatte an, die den Runner-Prozess überlebt. Jede Sitzung wird als eigener Benutzer des Runners ausgeführt, daher kann jede spätere Sitzung, die diese Festplatte bedient, sie lesen. Wenn Sie ein persistentes --base-dir beibehalten, dimensionieren Sie das Volume für dieses Wachstum. Das Gleiche gilt für jedes Setup, das den Runner auf demselben Dateisystem neu startet, einschließlich des Docker Compose-Rezepts.

  • Mit --remove-session-state bleiben Per-Session-Verzeichnisse nicht erhalten: Starten Sie den Runner mit --remove-session-state, um ihn dazu zu bringen, die Per-Session-Verzeichnisse jeder Sitzung zu löschen, wenn die Sitzung endet. Das Löschen ist bestmöglich: Die Verzeichnisse bleiben erhalten, wenn der Runner beendet wird, bevor seine Bereinigung ausgeführt wird. Der kanonische Klon und Dateien, die eine Sitzung an anderer Stelle auf dem Host geschrieben hat, wie das temporäre Verzeichnis, bleiben unabhängig davon erhalten.

  • Mit dem Git-Proxy wird das Zurücksetzen zu einem Checkout: Mit --use-anthropic-git-proxy bereinigt der Runner das .git/-Verzeichnis des Klons vor jeder Sitzung, behält den Objektspeicher, Referenzen und den flachen Zustand, löscht aber den Index, sodass jede Sitzung einen vollständigen Working-Tree-Checkout anstelle eines nahezu augenblicklichen Zurücksetzen zahlt; es wird immer noch nie neu geklont. Submodul-Vorwärme wird unter dem Proxy nicht unterstützt.

  • Lange Klone benötigen keine Umgehung: Der Runner begrenzt jede Git-Operation mit einem 120-Sekunden-Watchdog ohne Fortschritt und einer 30-Minuten-Obergrenze, nicht mit einem flachen Timeout, daher wird ein langsamer kalter Klon, der weiterhin Fortschritt meldet, abgeschlossen.

Pinnen Sie die Version

Jeder Sitzungs-Kind-Claude-Code-Prozess führt die Binärdatei des Runners selbst aus, und der Runner schaltet Auto-Update in den Sitzungen, die er spawnt, aus, daher führt jede Sitzung die Version aus, die Sie auf dem Host installiert oder in das Image eingebaut haben. Ein Host-Level-Update wird wirksam, das nächste Mal, wenn der Runner startet.

Legen Sie fest, welche Version Ihre Sitzungen ausführen und wann sie sich ändert:

  • Bevor Sie eine Version pinnen: Überprüfen Sie die Claude-Code-Versionen, die Modelle erfordern für jedes Modell, das Ihre Sitzungen verwenden. Wenn ein Modell eine neuere Version erfordert als die, die Ihre Sitzungen ausführen, lehnt der Server Anfragen für dieses Modell mit Claude Code unterstützt dieses Modell nicht ab.
  • Um eine Flotte auf einer Version zu halten: Erstellen Sie das Image mit einer gepinnten Version, oder installieren Sie auf einem bloßen Host eine spezifische Version und deaktivieren Sie Auto-Updates
  • Um eine feste Flotte zu aktualisieren: Lesen Sie die Changelog-Einträge zwischen Ihrer Version und der Version, die Sie installieren, und installieren Sie dann die neuere Version oder bauen Sie das Image neu und starten Sie die Runner neu
  • Um bedarfsgesteuerte Runner zu aktualisieren: Lesen Sie die Changelog-Einträge zwischen Ihrer Version und der Version, die Sie installieren, und ändern Sie dann das Image, das Ihr spawn-runner-Hook startet. Jeder neue Runner erhält die neue Version. Ein bereits laufender Runner, einschließlich eines Standby-Runners, den --min-idle gestartet hat, behält seine Version, bis er beendet wird. Starten Sie ihn nicht neu, da sein Arbeitsauftrag nur einmal verwendet werden kann.
  • Plugins: Plugin-Marktplätze auto-updaten auch nicht; setzen Sie FORCE_AUTOUPDATE_PLUGINS=1 in der Runner's Umgebung, um Plugins auto-updaten zu lassen, während die Binärdatei gepinnt bleibt

Skalieren Sie die Flotte

Ihr Orchestrator entscheidet, wann Runner hinzugefügt oder entfernt werden. Wegen der One-Owner-Per-Runner-Lock ist die minimale Replica-Anzahl die Anzahl der Benutzer und Claude Tag-Agenten, die Sie gleichzeitig aktiv erwarten; --capacity kontrolliert Parallelismus innerhalb einer Owner's Sitzungen, nicht über Owners.

Zwei Skalierungs-Ansätze sind verfügbar:

  • Feste Flotte: Führen Sie einen statischen Satz von Runner-Replicas aus und skalieren Sie auf den Prometheus-Metriken, die jeder Runner bedient
  • On-Demand-Runner: Führen Sie den claude self-hosted-runner orchestrator-Subcommand aus, der Anthropic auf Sitzungen abfragt, die mit keinem verfügbaren Runner in die Warteschlange eingereiht sind und Ihren spawn-runner-Hook aufruft, um einen pro Sitzung zu starten. Siehe On-Demand-Runner.

Bekannte Probleme und Einschränkungen

Die folgenden sind die Einschränkungen in dieser Version, mit Umgehungen, wo eine existiert.

Connector-Datenverkehr verlässt Ihr Netzwerk

Anthropic ruft Connector-Tools von seiner eigenen Infrastruktur anstatt von Ihrem Runner auf. Connector-Tools sind die claude.ai-Connectoren, wie GitHub, Slack und Linear. Wenn Claude einen Connector in einer selbstgehosteten Sitzung verwendet, geht dieser Datenverkehr durch api.anthropic.com anstatt von innerhalb Ihrer Netzwerkgrenze zu stammen.

Um einen Connector aus selbstgehosteten Sitzungen zu halten, filtern Sie ihn mit den allowedMcpServers- und deniedMcpServers-Richtlinien-Einstellungen. Claude Code wendet diese Einstellungen auf die Connectoren an, die Anthropic liefert, sowie auf die Server, die Sie vom Runner-Host seeden, und die Server, die Benutzer hinzufügen. Wenn Sie also eine Zulassungsliste für andere Server bereitstellen, blockiert Claude Code auch gelieferte Connectoren. Um Connectoren neben einer URL-basierten Zulassungsliste verfügbar zu halten, fügen Sie Einträge hinzu, die den Anthropic-Proxy-Pfaden für gelieferte Connectoren entsprechen:

  • https://api.anthropic.com/v2/ccr-sessions/*
  • https://api.anthropic.com/v1/code/sessions/*
  • https://api.anthropic.com/v1/code/mcp/*

Wenn Tool-Datenverkehr in Ihrem Netzwerk bleiben muss, führen Sie die äquivalenten Tools als lokale MCP-Server auf dem Runner-Image stattdessen aus. Siehe MCP-Server.

Einige Sitzungen zählen nicht als untätig

Eine Sitzung, die einen Hintergrund-Task hält, der niemals fertig wird, zählt nicht als untätig, daher wird --release-idle-session-min diese Sitzung nicht freigeben. Eine Sitzung, die auf eine Genehmigung wartet, die von innerhalb eines laufenden Tool-Aufrufs angefordert wird, zählt auch nicht als untätig. Setzen Sie immer --kill-session-after-min daneben als harten Backstop, damit keine Sitzung einen Slot unbegrenzt halten kann.

--kill-session-after-min ist ein Backstop für Runaway-Sitzungen. Auf einem Runner mit v2.1.260 oder später wird eine Sitzung, die das Limit erreicht, nicht sofort beendet. Der Runner gibt ihr ein Kulanzfenster, standardmäßig 15 Minuten, das Sie mit SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS ändern können:

  • Wenn die Sitzung auf ihren Benutzer wartet, gibt der Runner sie frei. Wenn ihr Zug beendet ist und sie hält nur Hintergrund-Tasks, wartet der Runner bis zu 60 Sekunden, damit diese Tasks fertig werden, und gibt sie dann frei. Die Sitzung wird fortgesetzt, wenn ihr Benutzer ihre nächste Nachricht sendet.
  • Wenn ein Zug noch läuft, wartet der Runner darauf, dass der Zug fertig wird, oder dass die Sitzung das nächste Mal auf ihren Benutzer wartet, und gibt sie dann frei.
  • Wenn die Sitzung noch auf dem Runner ist, wenn das Kulanzfenster endet, beendet der Runner sie, und jede laufende Zug-Arbeit geht verloren. Ein Zug, der auf eine Genehmigung wartet, die von innerhalb eines laufenden Tool-Aufrufs angefordert wird, ist eine Möglichkeit, wie eine Sitzung das Fenster überlebt.

Eine freigegebene Sitzung wird von einem frischen Klon fortgesetzt, daher ist Arbeit, die sie nicht gepusht hat, sowieso weg; siehe Fortgesetzte Sitzungen verlieren unpushed Arbeit. Vor v2.1.260 beendete der Runner jede Sitzung beim Limit, nachdem er höchstens das Kulanzfenster wartete, damit ein laufender Zug fertig wird.

Setzen Sie das Flag über Ihre längste erwartete Sitzung, wie --kill-session-after-min 480 für 8 Stunden. Um Slots aus Gesprächen freizugeben, die untätig werden, verwenden Sie stattdessen --release-idle-session-min.

Zusätzliche Einschränkungen

  • Fortgesetzte Sitzungen verlieren nicht gepushte Arbeit: Ein frischer Runner klont das Repository erneut von seinem Start-Branch, daher ist Arbeit, die die Sitzung nicht gepusht hat, verloren.
    • Um committete Arbeit zu behalten: Setzen Sie --push-outcome-on-release auf jedem Runner in der Umgebung, da ein Runner ohne das Flag die Sitzung von ihrem Start-Branch aus fortsetzt. Ein Runner mit dem Flag führt vor der Freigabe einen Best-Effort-Push der Ergebnis-Branches der Sitzung durch, und die fortgesetzte Sitzung startet von diesen Commits. Der Push verwendet die eigenen Git-Anmeldedaten des Runner-Hosts, auch auf einem Runner, der von Anthropic verwaltetes Git verwendet. Nicht committete Änderungen gehen weiterhin verloren.
    • Mit einem checkout-Hook: Repositorys, die über einen checkout-Lifecycle-Hook ausgecheckt werden, werden nicht gepusht. Sichern Sie diese stattdessen über den post-session-Hook.
    • Bevor Sie das Flag aktivieren: Beschränken Sie, wer zu claude/*-Refs auf dem Quell-Remote pushen kann. Beim Fortsetzen ruft der Runner den zuvor gepushten Branch ab, ohne zu überprüfen, wer ihn gepusht hat.
  • Ein während der Sitzung hinzugefügtes Repository kann beim Klonen fehlschlagen: Claude klont es mit git clone über HTTPS. Auf einem Runner ohne --use-anthropic-git-proxy schlägt das Klonen mit einem Git-Authentifizierungsfehler fehl, wenn nichts auf dem Host das Repository lesen kann. Wählen Sie nach Möglichkeit jedes Repository, das die Sitzung benötigt, bereits beim Erstellen aus.
  • Einige Connectoren erscheinen nicht in selbstgehosteten Sitzungen: Ein Connector, den Sie noch nicht in claude.ai Settings verbunden haben, wird nicht in einer selbstgehosteten Sitzung aufgelistet, und die Sitzung wird Sie nicht auffordern, ihn zu verbinden. Verbinden Sie ihn zuerst in Settings, dann starten Sie eine frische Sitzung. Das Hinzufügen eines Connectors zu einer bereits laufenden Sitzung macht seine Tools auch nicht für Claude verfügbar; starten Sie eine frische Sitzung, um einen neu hinzugefügten Connector aufzugreifen.

Melden Sie ein Problem

Für Probleme mit selbstgehosteten Umgebungen kontaktieren Sie Ihr Anthropic-Account-Team.

Fehlerbehebung

Für geführte Diagnose führen Sie den Doctor-Subcommand auf dem Runner-Host aus. Der Doctor-Subcommand startet eine interaktive Claude Code-Sitzung mit den Logs und dem Zustand des Runners angehängt. Melden Sie sich zuerst mit claude auth login auf diesem Host an, daher kann die Sitzung Ihre Umgebung, ihre Runner und ihre in die Warteschlange eingereihten Sitzungen abfragen. Ohne diese Anmeldung, zum Beispiel wenn der Host mit einem API-Schlüssel authentifiziert, ist es auf den lokalen Health-Endpunkt, Metriken und das Runner-Log begrenzt, und es liest das Log nur, wenn Sie den Runner mit --log-file gestartet haben.

claude self-hosted-runner doctor

Häufige Probleme:

  • Runner erscheint nicht in der Umgebung: Bestätigen Sie, dass der Host api.anthropic.com über HTTPS erreichen kann, das Umgebungsgeheimnis aktuell ist und die Host-Uhr innerhalb von fünf Minuten der echten Zeit liegt; größere Abweichung verursacht, dass die Authentifizierung fehlschlägt. Der Runner protokolliert [runner:fatal] mit dem Ablehnungsgrund bei Auth-Fehler.

  • Runner beendet sich beim Start mit cannot create or write to base directory: Der Runner kann --base-dir nicht erstellen oder schreiben, das standardmäßig auf /workspace ist. Beheben Sie das Verzeichnis's Eigentum oder zeigen Sie --base-dir auf einen beschreibbaren Pfad, wie in Halten Sie das Basis-Verzeichnis und die Kapazität über Runner identisch beschrieben. Wenn der Runner stattdessen [runner:fatal] protokolliert, dass die Basis-Verzeichnis-Überprüfung abgelaufen ist, ist das Verzeichnis auf einem hängenden NFS- oder CSI-Mount. Überprüfen Sie die Mount-Gesundheit anstatt der Berechtigungen. Der Runner druckt beide dieser Startup-Fehler zu stderr, bevor er --log-file öffnet, daher suchen Sie nach ihnen im Terminal oder Ihren Plattform-Container-Logs anstatt der Log-Datei. Vor v2.1.225 überprüfte der Runner das Basis-Verzeichnis nicht beim Start, und diese Fehlkonfiguration schlug Sitzungen nach der Aufnahme fehl.

  • Sitzungen bleiben in der Warteschlange: Jeder Online-Runner kann auf einen anderen Owner gesperrt sein. Überprüfen Sie die claude_code_self_hosted_runner_locked_account-Metrik jedes Runners oder das locked_account-Feld seiner [runner:health]-Log-Zeile, um zu sehen, wer sie hält. Beide zeigen die Email des Owners nur, nachdem der Runner ein Sitzungs-Token mit einem act.email-Claim ausgestellt bekommen hat, das die Sitzungen eines Claude Tag-Agenten niemals tun. Ohne den Claim sendet der Runner keine locked_account-Serie aus und protokolliert locked_account=yes, was Ihnen sagt, dass der Runner gesperrt ist, aber nicht auf welchen Owner. Fügen Sie Replicas hinzu, oder warten Sie, bis ein bestehender Runner drainiert und neu startet. Wenn die Umgebung On-Demand-Runner verwendet, überprüfen Sie stattdessen den Orchestrator; siehe On-Demand-Runner.

  • Sitzungen schlagen sofort nach der Aufnahme fehl: Öffnen Sie die Sitzung in claude.ai/code, um den Fehler zu sehen. Die häufigsten Ursachen sind fehlende Git-Anmeldedaten im Runner-Image und Build-Tools, die nicht installiert sind. Bei einem Runner, der mit --use-anthropic-git-proxy gestartet wurde, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten. Ein nicht beschreibbares Basis-Verzeichnis stoppt den Runner beim Start anstatt Sitzungen zu fehlschlagen. Siehe den Runner beendet sich beim Start mit cannot create or write to base directory-Eintrag in dieser Liste.

  • Sitzungen starten nicht auf einem Runner, der --use-anthropic-git-proxy gesetzt hat: Suchen Sie im Log des Runners nach access denied by the git proxy oder nach einem Git-Fehler, der eine api.anthropic.com-Adresse mit /git_proxy/ nennt. Um festzustellen, ob Anthropic die Sitzung bedient hat, und die Ursache zu beheben, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten.

  • Sitzungen können das Netzwerk nicht durch einen authentifizierenden Egress-Proxy erreichen: Wenn die Quelle, die Sie mit --proxy-authorization-command oder --proxy-authorization-file setzen, fehlschlägt, nach 30 Sekunden abläuft oder einen leeren Wert ergibt, antwortet der Runner dieser Verbindung 502 Bad Gateway und protokolliert warum. Der Runner redigiert das Kommando's stderr in diesem Log und protokolliert niemals den Header-Wert. Mit --proxy-authorization-command führen Sie das Kommando selbst auf dem Host aus, um zu bestätigen, dass es den ganzen Header-Wert auf stdout druckt. Wenn der Runner stattdessen beim Start mit could not start the proxy-authorization listener beendet wird, konnte er seinen Loopback-Listener nicht öffnen.

  • Runner protokolliert Poll failed-Zeilen, die rejecting the malformed poll response enthalten: Der Runner erhielt eine Work-Poll-Antwort, deren Body nicht das erwartete JSON der Warteschlange ist, am häufigsten weil etwas zwischen dem Runner und api.anthropic.com, wie ein abfangender Proxy oder ein Captive Portal, seine eigene Seite antwortet. Der Runner lehnt die Antwort ab, zählt sie unter der transport-Art der claude_code_self_hosted_runner_poll_errors_total-Metrik, und versucht erneut auf dem fehlgeschlagenen Poll-Plan, der in Sitzungs-Lebenszyklus beschrieben ist. Der Runner bedient weiterhin seine Live-Sitzungen. Konfigurieren Sie den Proxy, um Antworten von api.anthropic.com unverändert durchzulassen. Vor v2.1.246 las der Runner eine solche Antwort als eine leere Warteschlange, die seine Live-Sitzungen beenden oder ihn zum Exit bringen könnte.

  • Ein Sitzungs-Branch existiert nicht mehr auf dem Remote: Für eine Git-Quelle, die die Sitzung nur liest, überspringt der Runner diese Quelle und setzt auf den verbleibenden fort. Für die Quelle, zu der die Sitzung Ergebnisse pusht, schlägt ein gelöschter Branch, typischerweise weil er gemergt und auto-gelöscht wurde, die Sitzung mit einem Fehler fehl, der das Repository und den Branch benennt und Sie auffordert, den Branch wiederherzustellen und erneut zu versuchen. Der Runner schlägt die Sitzung mit dem gleichen Fehler fehl, wenn das Überspringen sie mit keinem Repository überhaupt verlassen würde. Vor v2.1.228 startete eine solche Sitzung in einem leeren Verzeichnis.

  • Eine Sitzung startet ohne eines ihrer Repositories: Auf einem Runner ohne checkout Hook kann der Git-Host den Zugriffsprüfung des Runners für ein Repository, das die Sitzung nur liest, ablehnen. Der Runner überspringt dann dieses Repository, protokolliert eine [runner:warn] could not access context source-Zeile, die die Ablehnung benennt, und startet die Sitzung auf den verbleibenden.

    Der Runner überspringt nur eine klare Ablehnung: Der Host antwortet, dass das Repository nicht gefunden wurde, Git findet keine Anmeldedaten für den Host, oder die Authentifizierung schlägt fehl. Ein Netzwerkfehler, ein Timeout oder ein HTTP 403 schlägt immer noch den Sitzungsstart fehl, ebenso wie eine Ablehnung für ein Repository, zu dem die Sitzung Ergebnisse pusht. Der Runner schlägt immer noch eine Sitzung fehl, die das Überspringen ohne Repository überhaupt verlassen würde. Mit --use-anthropic-git-proxy überspringt der Runner nur ein Repository, das der Git-Proxy selbst ablehnt.

    Die Zugriffsprüfung läuft jedes Mal erneut, wenn die Sitzung auf einem Runner startet, daher sobald die Git-Identität des Runners Lesezugriff hat, klont der nächste Start das Repository. Vor v2.1.274 schlugen jede dieser Ablehnungen den Sitzungsstart fehl.

  • Sitzungen dauern Minuten zum Start: Der anfängliche Clone dominiert normalerweise. Beobachten Sie die claude_code_self_hosted_runner_session_init_duration_seconds-Metrik, um zu bestätigen, und schneiden Sie den Clone mit einem vorgewärmten Checkout oder einem kleineren CLAUDE_RUNNER_FETCH_DEPTH.

  • Turns schlagen mit einem 401 fehl: Wenn ein Turn mit einem 401 oder 403 von der Anthropic API endet, ruft der Runner ein frisches CLAUDE_CODE_OAUTH_TOKEN von Anthropic ab und übergibt es der Sitzung. Der fehlgeschlagene Turn wird nicht erneut versucht. Dieses Token ist kurzlebig, und der Runner rotiert es über die stdin der Sitzung.

    Wenn ein Abruf fehlschlägt, protokolliert der Runner eine inference_token refresh failed-Zeile, die sagt, wann er erneut versuchen wird, und er versucht es weiterhin erneut, solange die Sitzung läuft.

    Wenn jeder Aufruf etwa 30 Minuten in eine Sitzung hinein fehlschlägt, hat ein Wrapper-Skript wahrscheinlich die Sitzungs-stdin unterbrochen, daher können Token-Rotationen sie nicht erreichen; siehe Halten Sie stdin und Dateideskriptor 3 angehängt.

    Vor v2.1.274 stoppte der Runner das erneute Versuchen eines fehlgeschlagenen Abrufs nach einigen Versuchen und wartete auf den nächsten geplanten. Ein fehlgeschlagener Turn löste keinen Abruf aus, daher schlugen alle Turns mit einem 401 fehl, bis zum nächsten geplanten Abruf.

  • Pod wird Mid-Drain getötet: Erhöhen Sie terminationGracePeriodSeconds auf mindestens den Wert, den der Runner beim Start protokolliert. Siehe Shutdown-Timing.

Sobald das Logging initialisiert ist, schreibt der Runner sein Lebenszyklus-Log, einschließlich [runner:fatal]-Zeilen, zu stdout, und Debug-Ausgabe zu stderr, alles als Plain-Text-Zeilen anstatt JSON. Die Startup-Fehler, die in den Fehlerbehebungs-Einträgen oben beschrieben sind, drucken zu stderr vor diesem Punkt. Erfassen Sie beide Streams mit --log-file, was auch self-hosted-runner doctor ermöglicht, sie zu tailing, oder mit Ihrer Plattform's Log-Sammlung.

Jeder Sitzungs-Kind-Prozess schreibt ein separates Debug-Log. Bei Fehler bewahrt der Runner das Log's Tail neben der Sitzung in claude.ai/code. Sofern Sie den Runner nicht mit --remove-session-state gestartet haben, behält er auch das Log einer fehlgeschlagenen Sitzung auf der Festplatte und druckt seinen Pfad im Runner-Log.

Wenn der Runner beendet wird

Starten Sie einen On-Demand-Runner nicht neu, da seine Arbeitsorder einmalig ist. Ein Runner, der sich direkt nach dem Start beendet, benötigt eine andere Behandlung als einer, der sich aus einem anderen Grund beendet.

  • Ein normaler Exit: Der Runner hat seine Sitzungen beendet und drainiert, seine Ruhezeit erreicht oder wurde angewiesen zu stoppen. Starten Sie ihn neu, damit die Umgebung wieder Kapazität hat. Runner-Lebenszyklus beschreibt diese Exits.
  • Ein fehlgeschlagener Start: Der Runner kann nicht mit der Konfiguration oder dem Host starten, der ihm gegeben wurde, daher beendet er sich Sekunden nach dem Start, und er beendet sich jedes Mal auf die gleiche Weise, wenn Sie ihn neu starten. Ein schnellerer Neustart hilft nicht. Jemand muss seine Ausgabe lesen und die Ursache beheben.
  • Verlorener Kontakt: Ein Runner, der Anthropic länger als seinen Lease nicht erreichen kann, zum Beispiel während sein Host schläft, kann aus der Umgebung entfernt werden. Wenn sich ein entfernter Runner wieder verbindet, beendet er sich. Sein Log kann eine [runner:fatal]-Zeile zeigen, die runner record gone server-side oder, nach einem längeren Ausfall, poll auth failed enthält. Der Runner registriert sich nicht von selbst erneut, starten Sie ihn also neu.

Konfigurieren Sie Ihren Supervisor, um den Runner jedes Mal neu zu starten, wenn er beendet wird, länger zwischen Neustarts zu warten, wenn der Runner sich weiterhin direkt nach dem Start beendet, und jemandem zu sagen, wenn das weiterhin passiert.

Erkennen Sie einen fehlgeschlagenen Start

Wenn der Runner nicht starten kann, druckt er eine Zeile, die sagt warum, und dann beendet er sich. Für die meisten Ursachen enthält die Zeile [runner:fatal]. Für einige Ursachen beginnt die Zeile stattdessen mit error:, einschließlich wenn der Runner seine Flags nicht parsen kann, das Umgebungsgeheimnis nicht lesen kann oder das Basis-Verzeichnis nicht erstellen oder schreiben kann. Die nächste Zeile zeigt dann auf --help.

Die meisten Log-Zeilen beginnen mit einem Zeitstempel und [self-hosted-runner], das die Beispiel unten auslässt. Zum Beispiel druckt ein Runner, der mit dem Anthropic Git-Proxy gestartet wurde und eine Kapazität über eins hat, eine Zeile wie diese:

[runner:fatal] --use-anthropic-git-proxy requires --capacity 1 (the proxy URL is per-session and linked worktrees share origin). Omit --use-anthropic-git-proxy or set --capacity 1.

Suchen Sie nach der Zeile in der Standard-Ausgabe und Standard-Fehler des Runners, in Ihren Plattform-Container-Logs oder in der Datei, die Sie mit --log-file setzen. Der Runner druckt eine error:-Zeile, bevor er die Log-Datei öffnet, daher suchen Sie nach ihr im Terminal oder Ihren Container-Logs, wie Fehlerbehebung notiert.

Diese helfen auch, wenn Sie einen fehlgeschlagenen Start lesen:

  • Keine Zeile überhaupt: Ein Runner, den der Host tötet, druckt keine. Wenn die Ausgabe mit keiner [runner:fatal]-Zeile und keiner error:-Zeile endet, überprüfen Sie, ob der Host oder Ihr Orchestrator den Prozess gestoppt hat, zum Beispiel für das Überschreiten eines Speicherlimits.
  • Der Exit-Code: Der Runner setzt keinen Exit-Code für Fehler beiseite, die bei jedem Start wiederholt werden. Er beendet sich mit dem gleichen Code für einen Konfigurationsfehler, wie eine nicht unterstützte Kombination von Flags, und für einen Fehler, der sich selbst löschen kann, wie die API, die durch die eigenen Wiederholungen des Runners unerreichbar bleibt. Basieren Sie die Entscheidung, länger zu warten, darauf, wie schnell der Runner beendet wurde, und lesen Sie die Ausgabe des Runners, um zu erfahren warum.
  • Eine Umgebung, die gesund aussieht: Einige Startup-Schritte laufen, nachdem sich der Runner bei Ihrer Umgebung registriert hat, wie --configure-git und die Credential-Einrichtung des Anthropic Git-Proxy. Wenn einer dieser Schritte fehlschlägt, kann die Umgebung diesen Runner für ein paar Minuten nach dem Prozessende weiterhin auflisten, und die Cloud-Umgebungen-Seite kann Gesund lesen, während kein Runner Arbeit aufnimmt. Wenn Sitzungen in einer Umgebung, die gesund aussieht, in der Warteschlange bleiben, überprüfen Sie, ob Ihr Supervisor den Runner neu startet.

Neustart mit einer wachsenden Wartezeit

Wie Sie eine wachsende Wartezeit bekommen, hängt von Ihrem Supervisor ab.

  • Kubernetes: Die Deployment auf dieser Seite benötigt keine Änderung. Nachdem ein Container beendet wird, wartet das kubelet standardmäßig, bevor es den Container neu startet, und die Wartezeit wächst bei jedem Neustart bis zu einer Obergrenze. Die Wartezeit startet von vorne, sobald der Container eine Weile ohne Beendigung läuft.

    Das kubelet wendet die gleiche Wartezeit nach einem normalen Exit an, wenn der Container nur kurz lief. Ein Runner, der oft drainiert, kann daher auch den CrashLoopBackOff-Status zeigen, daher lesen Sie die Ausgabe, bevor Sie schließen, dass der Runner nicht starten kann. Der Befehl unten liest die letzte Lauf-Ausgabe von einem Pod der Deployment:

    kubectl logs --previous -n claude-runners deploy/claude-runner
    

    Wenn der letzte Lauf ein fehlgeschlagener Start war, ist die [runner:fatal]- oder error:-Zeile unter den letzten Zeilen der Ausgabe. Um die letzte Lauf eines anderen Pods zu lesen, benennen Sie diesen Pod anstelle von deploy/claude-runner.

  • Docker und Docker Compose: Die Compose-Rezept auf dieser Seite benötigt keine Änderung. Mit restart: always wartet Docker länger vor jedem Neustart eines Containers, der weiterhin beendet wird, bis zu einer Obergrenze. Ersetzen Sie <container> mit dem Namen des Containers im Befehl unten, der liest, wie oft Docker den Container neu gestartet hat:

    docker inspect --format '{{.RestartCount}}' <container>
    

    Der Befehl druckt eine Zahl. Eine Zahl, die weiterhin klettert, bedeutet Docker startet den Runner weiterhin neu.

  • Eine systemd-Unit: Standardmäßig wartet systemd die gleiche RestartSec vor jedem Neustart und verlängert sie nicht, daher startet eine Unit mit Restart=always einen Runner, der nicht starten kann, in diesem gleichen Intervall jedes Mal neu. Wenn die Starts schnell genug kommen, um die Start-Rate-Grenze der Unit zu erreichen, fünf Starts in 10 Sekunden standardmäßig, stoppt systemd das Neustarten der Unit. Die Unit bleibt gestoppt, bis jemand sie wieder startet, was systemd erlaubt, sobald das Intervall der Rate-Grenze vergangen ist oder nach systemctl reset-failed. Weil RestartSec auf jeden Neustart angewendet wird, verzögert ein längerer Wert auch den Neustart nach einem normalen Exit. Wählen Sie einen Wert, der die beiden ausgleicht, und warnen Sie bei der Neustart-Zählung der Unit.

  • Eine Shell-Schleife oder Ihr eigener Supervisor: Wenden Sie die gleiche Regel selbst an. Beginnen Sie mit einer Wartezeit von fünf Sekunden. Nach jedem Lauf, der innerhalb einer Minute endete, verdoppeln Sie die Wartezeit für den nächsten Neustart, bis zu fünf Minuten. Nach einem Lauf, der eine Minute oder länger dauerte, gehen Sie zurück zu fünf Sekunden.

Überprüfen Sie, warum der Runner weiterhin beendet wird

Wenn der Runner mehrmals hintereinander direkt nach dem Start beendet wurde, stoppen Sie und überprüfen Sie diese, bevor Sie ihn erneut neu starten.

  • Die letzte [runner:fatal]- oder error:-Zeile: Sie sagt, warum der Runner gestoppt wurde. Fehlerbehebung listet die häufigen Ursachen auf.
  • Die Kombination von Flags: Der Anthropic Git-Proxy erfordert --capacity 1. Die Rezepte auf dieser Seite verwenden eine höhere Kapazität, daher senken Sie sie, wenn Sie den Proxy zu einem von ihnen hinzufügen.
  • Was die Umgebung des Service erreichen kann: Wenn der Runner von Hand startet und unter Ihrem Supervisor fehlschlägt, vergleichen Sie den Benutzer, das Home-Verzeichnis, den PATH und das Speicherlimit. --configure-git und der Anthropic Git-Proxy benötigen Git auf dem PATH und ein beschreibbares ~/.gitconfig.
  • Das Umgebungsgeheimnis: Wenn Sie das Geheimnis widerrufen oder falsch eingegeben haben, druckt der Runner eine Zeile, die RegisterRunner auth failed enthält.
  • Die Aktivitäts-Registerkarte der Umgebung: Öffnen Sie die Umgebung und wählen Sie Aktivität. Wenn neue Runner dort weiterhin erscheinen und keiner Arbeit aufnimmt, startet Ihr Supervisor den Runner neu.

Für geführte Diagnose auf dem Runner-Host führen Sie den Doctor-Subcommand aus.

Was kommt als nächstes

  • Passen Sie Sitzungen an: Wrapper-Skripte, Lebenszyklus-Hooks, On-Demand-Runner, MCP-Server und Berechtigungen
  • Testen Sie End-to-End: Überprüfen Sie ein neues Runner-Image von CI, bevor Sie es fördern
  • Referenz: Jedes CLI-Flag, jede Umgebungsvariable und jede Metrik