セルフホスト環境は Team および Enterprise プランで公開ベータ版です。利用可能性と制限事項では有効化パスについて説明しています。このページではフリートを本番環境で実行する方法について説明します。最初のランナーとセッションについてはクイックスタートを参照してください。
デプロイを強化する
セルフホストランナーは、環境にセッションをディスパッチできるすべてのユーザーに代わって、インフラストラクチャ上で任意のモデル指向のコードを実行します。これは Anthropic 組織のすべてのメンバーと、Owner が環境にルーティングしたスコープで Claude Tag チャネルセッションを開始できるすべてのユーザーです。本番環境システムに環境を接続する前に、各項目を確認してください:-
エフェメラルなセッションごとのコンテナ:各ランナープロセスを、プロセスが終了するときに破棄される新しいコンテナまたは VM で実行します。
--capacity 1とデフォルトの--drain-grace-sec 0を使用して、各コンテナが正確に 1 つのセッションを処理するようにします。容量が高い場合、またはドレイングレースが正の場合、1 つのコンテナが同じロックされたオーナーからの複数のセッションを処理します。ランナーのライフサイクルを参照してください。ランナーの再起動間でファイルシステムを再利用しないでください。ただし、意図的なプリウォーミングされたチェックアウトセットアップは除きます。また、オーナー間では再利用しないでください。- ランナーがセッションを停止するとき、シェルコマンドの終了後も実行を続けているプロセス(デーモン化したサービスなど)にはシグナルを送信しません。コンテナまたは VM を破棄すると、そのプロセスは終了します。
-
イメージに広範な認証情報を含めない:長期的な SSH キー、クラウドプロバイダーの認証情報、またはセッションが必要とする以上の権限を付与するパーソナルアクセストークンを含めないでください。セッション中に使用される認証情報(プッシュトークンや API トークン)は、ラッパースクリプトからセッションごとにミントしてください。初期クローンはラッパーが実行される前に発生するため、
checkoutライフサイクルフックで処理するか、セッションのすべてのリポジトリが github.com 上にある場合は--use-anthropic-git-proxyで処理してください。どちらについても、git を設定するを参照してください。 -
ホストの GitHub 認証情報をセッションから遠ざける:Claude は、セッションが読み取れる任意の GitHub 認証情報を、その認証情報が付与するアクセス権の範囲で使用できます。ランナーホスト自身の広範なスコープを持つ GitHub 認証情報は、セッションが読み取れる場所に置かないでください。このような認証情報には、パーソナルアクセストークン、
gh auth loginがアカウント用に保存するトークン、ランナーの環境内のGH_TOKENなどがあります。- Anthropic 管理の git を使用する場合:このような認証情報があると、Claude は Anthropic 管理の git を経由せずに GitHub に直接アクセスします。
- Anthropic 管理の git を使用しない場合:イメージに git 設定を含めるで説明しているとおりに厳密にスコープを限定すれば、クローン用の認証情報をイメージに残しておくことができます。
- 環境シークレットをセッション実行ホストに置かない:環境シークレットはランナーを登録し、環境でキューに入っているセッションを取得できます。固定フリートでは、シークレットはすべてのランナーホストに存在し、どのセッションのコードもシークレットファイルを読み取ることができます。オンデマンドランナーを優先してください。この場合、シークレットはユーザーコードを一切実行しないオーケストレーターホストに留まり、各ランナーは正確に 1 つのランナーを登録する単一使用の作業指示を受け取ります。固定フリートでは、環境シークレットファイルをすべてのセッションで読み取り可能として扱い、セッション侵害が疑われる場合はその後にシークレットをローテーションしてください。
- デフォルト拒否ネットワーク出力:すべての環境でランナーとセッションコンテナのアウトバウンドトラフィックをネットワーク境界で制限してください。デフォルト拒否出力では、許可する内容と理由について説明しています。
- 最小権限ホスト IAM:ランナーホストに接続されたコンピュート ID(インスタンスプロファイルやノードサービスアカウントなど)は、ランナー自体が必要とするもののみを付与する必要があります。セッションは、ホストの ID を継承するのではなく、ラッパースクリプトを通じて独自の認証情報を取得する必要があります。
-
セッションからクラウドメタデータエンドポイントをブロックする:セッションにホスト ID を使わせないようにするには、クラウドメタデータエンドポイントへのアクセスをブロックする必要があります。サブネットレベルの出力ポリシーはリンクローカルメタデータトラフィックをインターセプトしないため、コンテナ自体でブロックしてください:
- ホップリミットが 1 の IMDSv2
- メタデータ隠蔽を備えた GKE Workload Identity
- セッションコンテナのネットワーク名前空間で
169.254.169.254の明示的な拒否
-
ランナーごとのファイルシステム分離:各ランナープロセスは、ホスト上の他のプロセスが読み取りまたは書き込みできない独自の作業ディレクトリを取得します。
--hooks-dir、ラッパースクリプト、ホストの~/.claude/をセッションに対して読み取り専用にします。イメージに組み込むか、読み取り専用でマウントしてください。 -
ディスパッチには環境ごとのアクセス制御がない:Anthropic 組織のすべてのメンバーは、セッションを任意の環境にディスパッチできます。Owner が Claude Tag チャネルを環境にルーティングする場合、Claude Tag アクセス設定が許可するすべてのユーザーがそこで実行されるチャネルセッションを開始できます。デフォルトでは、Claude アカウントの有無に関わらず、接続された Slack ワークスペース内のすべてのユーザーです。すべてのランナーホストを、それにディスパッチできるすべてのユーザーがコード実行に到達可能として扱い、ランナーホストには、それらのユーザーすべてが読み取ることを許可されているデータと認証情報のみを配置してください。
--lock-to-accountは、特定のホストが実行するアカウントのセッションを制限しますが、環境にディスパッチできるユーザーを絞り込みません。セルフホスト環境を唯一のピッカーオプションにするには、Owner が Cloud environments ページから組織全体の Anthropic ホスト環境を非表示にできます。 -
リポジトリ設定ガードを適用する:
--confine-repo-settingsでガードモードを選択してください。デフォルトのwarnは違反をログに記録してもセッションを生成し、enforceはセッションを拒否し、offはスキャンを無効にします。ランナーは各リポジトリのコミットされた設定をスキャンして、次の項目を検出します:- そのセッション独自のワークスペースの外で解決される付与:
additionalDirectoriesエントリ、permissions.allowのEdit、Write、またはNotebookEditルール、またはsandbox.filesystem.allowWriteまたはallowReadエントリ - 空でない
envブロック sandbox.enabled: falseなどのオペレーター姿勢の上書き
--trust-workspaceに関係なく実行され、リポジトリフック、.mcp.json、または Bash ルールはカバーしません。権限とツール承認では、これらの付与がどこに属するかについて説明しています。 - そのセッション独自のワークスペースの外で解決される付与:
組織で IP 許可リストが有効になっている場合は、ランナーとセッションコンテナを起動する前に、それらのパブリック出力アドレスを許可リストに追加してください。オンデマンドランナーを実行する場合は、オーケストレーターホストのアドレスも追加してください。ランナーまたはセッショントラフィックのネットワーク制御として許可リストに依存しないでください。代わりに、独自のネットワーク境界でデフォルト拒否出力を適用してください。
ネットワーク要件
ランナーとそれが生成するセッション子は、以下のホストへのアウトバウンド接続を行います。セッションコンテナの出力をこれらのホストとセッションが到達する必要がある特定の内部サービスに制限してください。デフォルト拒否出力では、方法と理由について説明しています。 これらのホストは常に必須です:--use-anthropic-git-proxy を使用するランナーは、github.com の git トラフィックを api.anthropic.com 経由でルーティングするため、github.com 向けの git ホストへのパスは不要です。ただし、--push-outcome-on-release を設定する場合や post-session フックからプッシュする場合は、引き続きそのパスが必要です。
これらのホストが必要かどうかは、設定によって異なります:
ランナーまたはセッションのトラフィックのために、以下のホストを許可リストに登録する必要はありません:
statsig.anthropic.com、*.sentry.io、claude.ai、platform.claude.com:これらのホストは一部の古いエンタープライズネットワークチェックリストに記載されていますが、ランナーはこれらに到達しません。機能フラグのフェッチはapi.anthropic.comに送られ、ランナーはインタラクティブ OAuth ではなく環境シークレットで認証します。mcp-proxy.anthropic.com:セルフホストセッションはこれを使用しません。組織でコネクタ配信が有効な場合、組織の claude.ai コネクタはapi.anthropic.comを通じてセッションに届きます。MCP サーバーを参照してください。
claude.ai に到達するため、セッションコンテナの出力を広げるのではなく、出力でこれを許可しているホストから実行してください:
- ワンラインインストーラー:インストール時に
claude.aiからinstall.shをフェッチします。 - インタラクティブな
claude auth login:claude.ai、claude.com、platform.claude.comを通じてサインインします。ガイド付きセットアップ、doctorのサインイン済みモード、CI ディスパッチがこれを使用します。サインインに使用するブラウザーは、claude.ai サインインページのブラウザーチェックもhcaptcha.com、*.hcaptcha.com、challenges.cloudflare.comから読み込みます。組織でシングルサインオンを使用している場合、そのブラウザーはsso.claude.com経由でリダイレクトされることもあります。
デフォルト拒否出力
ランナーとセッションコンテナを、アウトバウンドトラフィックがネットワーク要件テーブルのホスト、git ホスト、セッションが到達する必要がある特定の内部サービスに制限されるネットワークセグメントまたは名前空間にデプロイします。製品はこれを検証または適用できないため、すべての環境でネットワーク境界に適用してください。セッションコードはモデル指向であり、任意のホストへの接続を試みることができます。ネットワークレイヤーでのデフォルト拒否出力は、これらの試みが到達できる場所を制限します。これは権限モードに関係なく適用されます:デフォルトの事前承認ツールセットには既にBash が含まれているため、自動モードがなくてもシェル出力はプロンプトなしで実行されます。
各セッションが出力するテレメトリとそれをオフにする方法の詳細については、テレメトリを参照してください。
出力プロキシに認証する
一部の企業出力プロキシは、すべての接続でProxy-Authorization ヘッダーを必要とします。そのヘッダーのトークンは、HTTPS_PROXY に設定するプロキシ URL に書き込むには速すぎるペースでローテーションすることが多いです。通常どおり HTTPS_PROXY または HTTP_PROXY をプロキシの URL に設定してから、--proxy-authorization-command または --proxy-authorization-file を設定して、ランナーにヘッダー値を読み取る場所を指示してください。両方のフラグには Claude Code v2.1.238 以降が必要です。
Proxy-Authorization 値の出所を選択する
Proxy-Authorization トークンを生成する方法に一致するフラグを選択してください:
--proxy-authorization-command <command>:オンデマンドで生成するトークンの場合はこれを選択してください。ランナーはシェルコマンドを実行し、トリミングされた stdout をヘッダー値として使用します。例えばBearer <token>。--proxy-authorization-file <path>:別のプロセスがローテーションするトークンの場合はこれを選択してください。ランナーはファイルを読み取り、トリミングされた内容をヘッダー値として使用します。
ランナーが起動を拒否する設定
各フラグには環境変数形式もあり、ランナー CLI フラグリファレンスに記載されています。ランナーがプロキシまたはコントロールプレーンに接続する前に、フラグとその変数をチェックし、3 つの場合に起動を拒否します:- 両方のフラグが設定されている:1 つのフラグと他のフラグの環境変数は、両方を設定することとしてカウントされます。
- プロキシ URL がない:
HTTPS_PROXYもHTTP_PROXYもhttp://またはhttps://URL を保持していません。ランナーは両方の変数を大文字または小文字で読み取り、ALL_PROXYを参照しません。 - フラグがオーケストレーターサブコマンドに渡される:
self-hosted-runner orchestratorはフラグまたはそれらの環境変数を受け入れません。代わりに、オーケストレーターが開始する各ランナーにフラグを渡してください。
プロキシ認可フラグが設定されている間にランナーが変更する内容
いずれかのフラグが設定されている場合、ランナーは独自のリスナーを開始し、プロキシトラフィックをそれ自体、ライフサイクルフック、セッションからそのリスナーを通じて送信します。リスナーはプロキシへの途中でProxy-Authorization ヘッダーを追加します。
- リスナー:リスナーは
127.0.0.1上のフォワードプロキシです。ランナーはコントロールプレーンに登録する前にリスナーを開始し、リスナーが開始できない場合は起動時に終了します。 - プロキシ変数:ランナーは、設定した
HTTPS_PROXYとHTTP_PROXYのいずれかをリスナーを指すように書き直します。その書き直された値はランナー自体、ライフサイクルフック、実行するすべてのセッションに到達します。 - トークンローテーション:ローテーションされたトークンは再起動なしで有効になります。リスナーがプロキシに開く各接続について、ランナーはコマンドを実行するか、ファイルを再度読み取り、結果をヘッダーとして追加します。
- セッション環境:セッションはリスナーを通じてのみプロキシに到達します。各セッションの環境で、ランナーは
ALL_PROXYを削除し、設定しなかったHTTPS_PROXYまたはHTTP_PROXYのスペルを削除し、NO_PROXYをランナー独自の値にピンします。 - ログ:ランナーはヘッダー値をログに記録しません。
git を設定する
ランナーはリポジトリチェックアウトを管理しますが、デフォルトでは git ID または認証情報を設定しません。ランナーのイメージとプロセス環境を制御するため、git 設定を制御します。2 つのアプローチのいずれかを選択してください:- ランナーに git を設定させる:
--configure-gitでランナーを開始して、Anthropic ホストセッションが使用する同じ ID とコミット署名設定を書き込ませます - イメージに git 設定を含める:ID とプッシュ認証情報を自分で設定します。例えば、独自のボット ID でコミットするため
--use-anthropic-git-proxy でランナーを開始するか、CLAUDE_RUNNER_USE_GIT_PROXY=1 を設定して、ランナーのセッションの git を提供するよう Anthropic に求めることもできます。
ランナーホストの Git バージョンフロア:--configure-git SSH コミット署名には Git 2.34 以降が必要です。--use-anthropic-git-proxy には 2.32 以降が必要です。--push-outcome-on-release でプッシュされたブランチからセッションを再開するには 2.29 以降が必要です。3 つすべてを省略して git ID を自分で管理する場合は、Git 2.24 で十分です。
ランナーに git を設定させる
--configure-git でランナーを開始するか、SELF_HOSTED_RUNNER_CONFIGURE_GIT=1 を設定して、起動時にグローバル git 設定を書き込ませます:
user.name = Claudeおよびuser.email = noreply@anthropic.com。Anthropic ホストセッションと一致します- SSH 形式のコミットとタグ署名。ランナー管理のシムを通じてルーティングされ、セッション独自の認証情報を使用して Anthropic の署名サービスを通じて各コミットに署名します。署名は GitHub で Anthropic の公開 SSH 署名キーに対して検証可能です。
push.negotiate = true。git がプッシュをパックする前に git ホストが既に持っているコミットを尋ねます。Claude Code v2.1.257 以降が必要です。core.hooksPathはランナー管理のフックディレクトリを指します。そのcommit-msgおよびprepare-commit-msgフックは、各コミットにセッションの作成者のCo-authored-by:トレーラーを追加します。CCR_SESSION_ACCOUNT_EMAILのメールから構築され、その変数が設定されていない場合は省略されます。イメージが既にcore.hooksPathを設定していて、ランナーが Anthropic 管理の git を使用していない場合、ランナーは設定を保持し、これらのフックのインストールをスキップし、[runner:git]警告を出力します。
checkout または post-session ライフサイクルフックから行ったコミットもセッションとして署名されます。ただし、Co-authored-by: トレーラーは付きません。ライフサイクルフック内の git 設定では、ランナーがこれらのフック内で固定する git 設定について説明しています。
--configure-git の有無にかかわらず、Claude Code は Claude に対して、コミットメッセージの末尾に Claude-Session: <url> トレーラーを付け、プルリクエストの説明の末尾にセッションの URL を付けるよう指示します。両方を省略するには、ランナーホストの ~/.claude/settings.json で attribution.sessionUrl を false に設定してから、ランナーを再起動してください。
イメージに git 設定を含める
git ID はすべてのコミットに必須です。Dockerfile でシステム全体に設定して、ランナープロセスが実行されるユーザーに関係なく設定が適用されるようにします:git commit は Please tell me who you are で失敗し、セッションは進行できません。代わりに独自のボット ID を使用できます。ランナーはこれらの値をオーバーライドしません。
長期的または広くスコープされたプッシュ認証情報を共有ランナーイメージにベイクしないでください:イメージの認証情報は、イメージが実行するすべてのセッションで利用可能です。誰が開始したかに関係なく。代わりに、セッション JWT からデコードされたセッション作成者の ID を使用して、ラッパースクリプトからセッションごとに短期的で最小スコープのトークンをミントしてください。エフェメラルなセッションごとのコンテナと組み合わせます。これには --capacity 1 が必要です。認証情報がセッションを超えて存続しないようにします。強化セクションを参照してください。
イメージレベルでプッシュ認証情報を設定する必要がある場合(例えば、読み取り専用デプロイキーの場合)、git ホストが許可する限りスコープを厳しくしてください:
url.<base>.insteadOf書き直しで 1 つのリポジトリに制限された SSH デプロイキー- 最小限のスコープトークンを返す
credential.helper - 狭くスコープされたキーを指す
GIT_SSH_COMMAND
- ランナーは
GIT_TERMINAL_PROMPT=0を設定するため、git はユーザー名またはパスワードを要求しません。 - ランナーは
BatchMode=yesで SSH を実行します。GIT_SSH_COMMANDを設定した場合は追加されます。SSH はパスフレーズまたはホスト確認を要求しません。 - ランナーは
GCM_INTERACTIVE=neverを設定するため、Git Credential Manager はサインインダイアログを開きません。 - ランナーは
core.askPassをクリアするため、askpass ヘルパーを使用する場合は、GIT_ASKPASS環境変数を通じて設定してください。
GIT_SSH_COMMAND または GIT_ASKPASS で名前を付けるプログラムを、セッションが書き込めない場所に保持してください。強化チェックリストがフックディレクトリとラッパースクリプトに要求する方法と同じです。そのプログラムのコマンドラインのキーまたはファイルについても同じです。ランナー独自の git は、クローンまたはフェッチするときにそのプログラムを実行します。
チェックアウトディレクトリがランナープロセスと異なる uid で所有されている場合、git は操作を拒否します。safe.directory を追加してください:
Anthropic git プロキシを使用する
Anthropic git プロキシ(Anthropic 管理の git とも呼ばれます)を使用すると、ランナーイメージはセッション自体のために SSH キー、認証情報ヘルパー、.netrc、その他の git 認証情報を必要としません。代わりに、ランナーはセッションの git を提供するよう Anthropic に求めます。Anthropic が提供するユーザーのセッションでは、ランナーのクローンとセッション独自のフェッチおよびプッシュは Anthropic を経由し、Anthropic はセッション作成者用に保存された GitHub OAuth トークンを使用します。ボットおよびエージェントセッションについては、Anthropic がセッションの git を提供する仕組みで説明しています。
git プロキシは、オンにしない限りオフです。独自の認証情報で git ホストに到達するランナーには不要であり、そのランナーの git はどの git ホストでも動作します。
その代わり、git プロキシはランナーがサポートする範囲を制限し、ランナーに必要なものを変更します:
- github.com のみ:Anthropic は、セッションのすべてのリポジトリが github.com 上にある場合にのみそのセッションを提供します。また、git プロキシはまだ GitHub Enterprise Server をサポートしていません。git プロキシを使用するランナーでは、別の git ホスト上のリポジトリを持つセッションは開始に失敗します。
- セッションのリポジトリのみの認証情報:Anthropic は、セッションに含まれるリポジトリに対して git 認証情報を提供し、同じ git ホスト上の他のリポジトリに対しては提供しません。プライベートサブモジュール、パッケージマネージャーが git で取得する依存関係、または別のリポジトリにあるプラグインマーケットプレイスは、Anthropic から認証情報を受け取りません。セッションを作成するユーザーに、作成時にセッションが必要とするすべてのリポジトリを追加するよう依頼してください。 クラウドスケジュールタスクの各実行は、そのタスクのリポジトリを持つセッションです。そのため、各タスクの所有者に、実行に必要なすべてのリポジトリを追加するよう依頼してください。
- ブランチへのプッシュのみ:ブランチを削除するプッシュは失敗し、タグなど他の種類の ref へのプッシュも失敗します。プッシュで更新できるブランチについては、GitHub プロキシを参照してください。
- 接続済みの GitHub アカウント:リポジトリを含むユーザーセッションを作成する各ユーザーに、GitHub を接続するよう依頼してください。本人の接続がない場合、それらのセッションは開始されません。
-
--capacity 1:git プロキシはランナープロセスごとに 1 つのセッションを必要とするため、並列処理のためにより多くのレプリカを実行してください。要件は Anthropic git プロキシをオンにするに記載されています。 - グローバル git 設定の置き換え:ランナーは、実行ユーザーのグローバル git 設定を削除して置き換えます。専用ユーザーとして、またはコンテナ内で実行してください。
-
ホストからのプッシュにはホストの認証情報:ランナーの
--push-outcome-on-releaseによるプッシュと、post-sessionフックが行うプッシュは、引き続きランナーホスト独自の git 認証情報とgithub.comへのネットワーク経路を使用します。これらの認証情報はグローバル git 設定に置かないでください。提供方法についてはイメージに git 設定を含めるを参照してください。 - セッションごとの判断:Anthropic はランナー上の各セッションについて git を提供するかどうかを決定し、提供されないセッションは開始に失敗します。原因については git プロキシを使用するランナーでセッションの開始に失敗する場合で説明しています。
safe.directory など、機密ではない git 設定はシステムの git 設定に保持してください。
Anthropic git プロキシをオンにする
--use-anthropic-git-proxy でランナーを開始する前に、ランナーホストが次の各要件を満たしていることを確認してください。容量または git の要件が満たされていない場合、ランナーは起動を拒否します:
- Claude Code v2.1.267 以降:それより前のバージョンはフラグを受け入れますが、Anthropic に git の提供を求めるリクエストを報告せず、
Registering as opted in行も出力しないため、Anthropic はそれらのセッションを提供しません。 --capacity 1(デフォルト):各ランナープロセスは一度に 1 つのセッションを処理するため、並列処理のためにより多くのレプリカを実行してください。- Git 2.32 以降:古い git は、ランナーが git プロキシ用に設定するセッションごとの git 設定を無視します。
--use-anthropic-git-proxy を追加するか、ランナーの環境で CLAUDE_RUNNER_USE_GIT_PROXY=1 を設定します。ランナーホスト上のシェルで実行する次のコマンドは、クイックスタートのランナーを git プロキシをオンにした状態で開始します:
Registering as opted in to Anthropic-managed git (--use-anthropic-git-proxy) を出力します。その後、Anthropic はそのランナー上の各セッションについて git を提供するかどうかを決定します。提供する各セッションについて、ランナーは governed git ACTIVE を含む [runner:session] 行をログに記録します。代わりにセッションの開始に失敗した場合は、git プロキシを使用するランナーでセッションの開始に失敗する場合を参照してください。
Anthropic がセッションの git を提供する仕組み
Anthropic が提供するセッションでは、ランナーのクローンとセッション独自のフェッチおよびプッシュは、セッション独自の短期トークンで認証されて Anthropic を経由します:- ユーザーセッション:Anthropic はセッション作成者用に保存された GitHub OAuth トークンを使用します。
- ボットおよびエージェントセッション:Anthropic は組織の GitHub App インストールトークンを使用します。
- URL の書き直し:
--git-host-rewriteと--git-ssh-rewriteは、git プロキシが提供するリポジトリには効果がありません。
git プロキシを使用するランナーでセッションの開始に失敗する場合
--use-anthropic-git-proxy で開始したランナーでは、Anthropic がセッションの git を提供しない場合、セッションは開始に失敗します。ランナーのログで、/git_proxy/ を含む api.anthropic.com アドレスを示す git エラーを探してください。
各セッションについて、Claude Code v2.1.267 以降のランナーは、Anthropic がセッションの git を提供する場合は governed git ACTIVE を含む [runner:session] 行を、提供しない場合は the server withheld Anthropic-managed git for this session を含む [runner:warn] 行を 1 つログに記録します。表示されている行を次のケースから探してください:
governed git ACTIVEもwithheld行もない:Claude Code v2.1.267 より古いランナーはどちらの行もログに記録せず、Anthropic はそのセッションを提供しません。バージョンを固定するの手順に従って、ランナーを v2.1.267 以降に更新してください。withheld行:Anthropic はセッションを提供しませんでした。以前は git プロキシで動作していたランナーでも、ユーザー側で何も変更していないのにこのように失敗することがあります。- github.com 上にないリポジトリがある:GitHub Enterprise Server など別の git ホスト上のリポジトリが 1 つでもあるセッションは、その github.com リポジトリも含めて提供されません。その環境のランナーでは Anthropic git プロキシをオフにしてください。
- すべてのリポジトリが github.com 上にある:
withheld行のセッション ID を添えて、Anthropic アカウントチームに失敗を報告してください。Anthropic は理由を自社側で記録しています。
remote: access denied by the git proxyを含む行:Anthropic が提供するセッションでも拒否される場合があります。たとえば、組織のポリシーがセッションの git アクセスを拒否する場合や、セッションがリポジトリに対して認可されていない場合です。その場合、ランナーのログにremote: access denied by the git proxyを含む行が表示され、その行の残りの部分に理由が示されます。GitHub authentication required:セッションの作成者が claude.ai で有効な GitHub 接続を持っていない場合に表示されます。セッションのクローンは失敗し、git エラーにはGitHub authentication required. Please reconnect your GitHub account.と表示されます。そのユーザーに、claude.ai の設定で GitHub を接続または再接続するよう依頼してください。
Anthropic git プロキシをオフにする
環境内のセッションが GitHub Enterprise Server など github.com 以外の git ホスト上のリポジトリを使用する場合は、その環境のランナーで--use-anthropic-git-proxy をオフにしてください。
1
フラグを削除する
ランナーのコマンドから
--use-anthropic-git-proxy を削除します。Pod 仕様や Compose ファイルなど、ランナーの環境で CLAUDE_RUNNER_USE_GIT_PROXY を設定している場合は、そこから削除します。シェルでは設定を解除します:2
ランナーに git 認証情報を与える
github.com を含め、ランナーのセッションが使用するすべての git ホストに対して、プロンプトなしで動作する認証情報を提供してください。ランナーユーザーのグローバル git 設定にあった認証情報は、
--use-anthropic-git-proxy が設定されている間にランナーがその設定を削除したため、失われています。イメージに認証情報を含めるか、checkout ライフサイクルフックを使用してください。3
ネットワーク経路を開く
ランナーのセッションが使用する各 git ホストに、ランナーがポート 443 または 22 で到達できるようにしてください。ネットワーク要件の git ホストの行を参照してください。
4
ランナーを再起動する
git プロキシなしで登録されるようにランナーを再起動します。その後、失敗した各セッションを再度開始してください。
GitHub CLI なしで GitHub API にアクセスする
ランナーイメージに GitHub CLI が含まれていない場合、Claude Code は組み込みのgh を提供できるため、Claude は引き続きプルリクエストの作成、コメント、CI 結果の読み取りを行えます。組み込みの gh は、Anthropic 管理の git を使用するランナー向けです。サポートするコマンドは GitHub の REST API を呼び出す gh api の 1 つのみです。ランナーイメージに Claude Code v2.1.287 以降が必要です。
次のコマンドは、gh pr create の代わりにプルリクエストを作成します。組み込みの gh は、現在のリポジトリの {owner} と {repo} を自動で埋めます:
- 認証情報:組み込みの
ghは REST リクエストを Anthropic 管理の git 経由で送信し、GitHub の認証情報は Anthropic 側で提供されるため、イメージにそのための GitHub トークンは不要です - 利用できるセッション:Anthropic 管理の git がセッションの
ghを提供するかどうかは、Anthropic がセッションごとに決定します。提供する場合、ランナーがそのセッションについてログに記録する[runner:session] governed git ACTIVE行にgh_path_shim=trueが表示されます。提供しない場合、そのセッションにはghがありません jq:--jqを使用したい場合は、イメージにjqをインストールしてくださいCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:セッション環境でこれが設定されている場合、Claude Code は組み込みのghを提供せず、セッションにはghがありません
Anthropic 管理の git でプライベート認証局を信頼する
このセクションは、セッションが Anthropic 管理の git を使用するランナーの環境でGIT_SSL_CAINFO または GIT_SSL_NO_VERIFY を設定した場合に適用されます。説明する処理には、ランナーが Claude Code v2.1.283 以降を実行する必要があります。
ランナー上の git が TLS 検査プロキシが署名するプライベート認証局(CA)などのプライベート認証局を信頼する必要がある場合、通常のアプローチは次のように機能します:
- システム証明書ストア:ランナーホストのシステム証明書ストアに CA をインストールし、git は変数なしでそれを信頼します。
GIT_SSL_CAINFO:CA の PEM ファイルに設定します。例えばGIT_SSL_CAINFO=/etc/ssl/corp-ca.pem。GIT_SSL_NO_VERIFY:再署名プロキシの背後では役に立ちません。Anthropic 管理の git を通じたランナー独自のクローンは、変数が設定されている場合でも証明書をチェックするため、git が他の 2 つのアプローチのいずれかを通じて CA を信頼するまで、そのクローンは失敗します。
command フックはセッションの環境で開始するため、git がセッション内で取得するものを取得します:
GIT_SSL_CAINFO:git が Anthropic 管理の git に対してチェックするものは、git が実行される場所によって異なります:- ランナー独自のクローンとフェッチ:変数なしで実行され、ランナーが書き込むセッションごとの証明書ファイルに対して Anthropic 管理の git をチェックします。ランナーは、ランナーホストのシステム CA バンドルと指定したファイル内の証明書からそのファイルを作成します。
- セッション内の git:変数の代わりに
http.sslCAInfo設定を取得し、ファイルに名前を付けます。また、セッションごとのファイルに対して Anthropic 管理の git をチェックするhttp.<url>.sslCAInfoエントリを取得します。 checkoutおよびpost-sessionフック:変数を変更されずに継承します。
GIT_SSL_NO_VERIFY:証明書チェックが無効のままであるかは、git が実行される場所によって異なります:- ランナー独自のクローンとフェッチ:変数なしで実行され、提示される証明書をチェックします。
- セッション内の git:変数の代わりに
http.sslVerify=false設定を取得するため、他のホストのチェックは無効のままです。また、Anthropic 管理の git のチェックを有効に保つhttp.<url>.sslVerify=trueエントリを取得します。 checkoutおよびpost-sessionフック:セッションが Anthropic 管理の git 上のリポジトリを持つ場合、変数の代わりにhttp.sslVerify=false設定を取得します。また、Anthropic 管理の git のチェックを有効に保つhttp.<url>.sslVerify=trueエントリを取得します。
/etc/ssl/certs/ca-certificates.crt または /etc/pki/tls/certs/ca-bundle.crt のシステム CA バンドルが必要です。また、ランナーのユーザーが読み取ることができ、PEM CERTIFICATE ブロックを保持し、最大 1 MiB である GIT_SSL_CAINFO ファイルが必要です。ランナーがセッションごとのファイルを構築できない場合、[runner:warn] 行を記録します。これには did not build the certificate file と理由が含まれます。git はその後、Anthropic 管理の git のファイルをそのまま使用します。行が名前を付けるものを修正してください。
Anthropic 管理の git を使用する各セッションについて、ランナーは [runner:warn] 行をログに記録します。これは governed git: GIT_SSL_CAINFO is set または governed git: GIT_SSL_NO_VERIFY is set で始まります。行は、ランナーが独自の git、セッション内の git、およびライフサイクルフックのその変数で何をしたかを示します。何かを変更する必要があるかどうかで終わります。
Claude Tag チャンネルのセッションに github.com のリポジトリを追加する
Claude が Claude Tag チャンネルのセッションに github.com のリポジトリを追加できない場合は、ランナーがそのリポジトリをクローンできる場合でも、チャンネルがそのリポジトリにアクセスできることを確認してください。このアクセス権は、ランナーの git 認証情報ではなく、GitHub と Claude 組織の設定によって決まります。1
Claude GitHub App をインストールする
リポジトリを所有する GitHub 組織またはアカウントに Claude GitHub App をインストールし、そのリポジトリをインストール対象に含めます。
2
GitHub 組織またはアカウントをリンクする
Organization settings > Git providers で、その組織またはアカウントを Claude 組織にリンクします。GitHub 組織のオーナーでもある Claude 組織の Owner がリンクできます。GitHub 組織をリンクするを参照してください。
3
リポジトリへのアクセスを付与する
Claude Tag 管理設定で、チャンネル、またはそのチャンネルを含むより広いスコープ(その Slack ワークスペースまたは Slack 全体)にリポジトリへのアクセスを付与します。Owner ロールまたは Claude Tag Admin 権限を持つユーザーが付与できます。チャンネルマネージャーも、自分の GitHub アカウントがリポジトリの管理者であれば、自分のチャンネルにリポジトリを追加できます。リポジトリへのアクセスを付与するを参照してください。
プライベートネットワークの git URL を書き直す
リポジトリ URL はコントロールプレーンから HTTPS として到達します。git ホストのホスト名を使用します。GitHub Enterprise の場合、claude.ai で GitHub Enterprise 統合用に設定したホスト名です。2 つの繰り返し可能なフラグはクローン前にこれらの URL を書き直します:--git-host-rewrite <from>=<to>:スプリットホライズン DNS の場合。Anthropic は外部ホスト名を通じて git ホストに到達しますが、ランナーは内部ホスト名を使用する必要があります--git-ssh-rewrite <host>:SSH のみを受け入れる git ホストの場合、または SSH キーしか持たないランナーホストの場合。例えば、github.com のリポジトリを SSH でクローンするには、ランナーのコマンドに--git-ssh-rewrite github.comを追加します。するとランナーはhttps://github.com/owner/repoをgit@github.com:owner/repoに書き直します。SSH はプロンプトなしで接続できる必要があります。
--git-ssh-rewrite に内部ホスト名をリストします。チェックアウトを完全に制御するには、checkout ライフサイクルフックを使用してください。
ランナーイメージをビルドする
Anthropic は事前にビルドされたランナーイメージを公開していません。claude バイナリの周りに独自のイメージをビルドし、リポジトリが必要とするツールチェーン(言語ランタイム、コンパイラ、パッケージマネージャー、MCP サイドカー)をレイヤーに追加してください。
以下のレシピは --capacity 4 を使用しているため、1 つのコンテナが同じロックされたオーナーからの最大 4 つの同時セッションを処理します。これはハードニングセクションのセッションごとのコンテナ分離を提供していません。環境を本番システムに接続する前に、レシピを --capacity 1 で実行してセッションごとに 1 つのコンテナを使用するか、オンデマンドランナーを使用してください。オンデマンドランナーは、セッション実行ホストから環境シークレットを保持します。これらのレシピのいずれかにAnthropic git プロキシを追加する場合は、--capacity も 1 に変更してください。
これは最小限の開始点となる Dockerfile です。
linux-x64 を linux-arm64 に置き換えるか、Alpine などの musl ベースのイメージの場合は linux-x64-musl または linux-arm64-musl に置き換えてください。Alpine Linux セットアップを参照して、musl イメージが必要とする追加パッケージを確認してください。URL は標準的な Claude Code リリースロケーションであるため、バイナリの整合性とコード署名で説明されているように、ダウンロードされたバイナリをリリースの署名されたマニフェストに対して検証できます。ランナーは Claude Code バージョン 2.1.224 以降が必要です。イメージをビルドしてから、レジストリにプッシュし、以下のレシピで参照してください。
stable リリース番号を検索し、ビルド引数として渡すため、新しい安定版リリース後に同じコマンドを実行すると、ダウンロードレイヤーが新しいバイナリで再ビルドされます。再現可能なビルドのために特定のリリースをピンするには、バージョン番号を CLAUDE_CODE_VERSION として直接渡してください。新しくリリースされたモデルが必要とするような安定版チャネルより新しいリリースが必要な場合は、ルックアップ URL の stable を latest に置き換えてください。
セッション用に CPU とメモリをサイズ設定する
ランナープロセス自体ではなく、ランナーが実行するセッション用にランナーのコンテナまたはホストをサイズ設定してください。ランナー自体は作業をポーリングし、各セッションのチェックアウトを準備し、ライフサイクルフックを実行し、セッションプロセスを開始および監視します。負荷はセッションから発生します。各セッションは Claude Code プロセスと、ビルド、テストスイート、パッケージインストール、MCP サーバーなど、それが開始するものです。 1 つのセッションについて、以下の値から開始してください。Kubernetes のリクエストと制限、またはプラットフォームの同等の値として記載されており、要件ではなく開始点として扱ってください。- メモリ: 各 4 GiB のリクエストと制限。これは Claude Code のシステム要件の 4 GB 最小値を満たします。2 つを等しく保つことで、スケジューラーはコンテナの全メモリを考慮に入れます。コンテナがメモリ制限に達すると、カーネルはその内部のプロセスを強制終了し、セッションをタスクの途中で終了させる可能性があります。
- CPU: 2 CPU のリクエストと 4 CPU の制限。セッションはビルド中にリクエストを超えてバースト可能です。カーネルはコンテナを CPU 制限でスロットルします。その制限でプロセスを強制終了するのではなく、セッションは制限で実行速度が低下しますが、実行を続けます。
resources ブロックを使用してこれらの開始値を設定します。
--capacity を使用して、一度に実行するセッション数をキャップします。CPU またはメモリをセッション間で分割しないため、ランナー上のセッションはコンテナの CPU とメモリを共有します。1 つのセッションのメモリ使用が他のセッションを終了させないようにするには、専用のメモリ制限を設けて、ランナーあたり 1 つのセッションを実行してください。
-
ランナーあたり 1 つのセッション: 各コンテナに 1 つのセッションの値を与えます。強化セクションが推奨する
--capacity 1でこのサイズ設定を使用し、オンデマンドランナーの場合、spawn-runnerフックが送信するワークロード(Kubernetes Job のポッドテンプレートなど)に値を設定します。 -
ランナーあたり複数のセッション:
--capacityが 1 より上の場合、1 つのセッションの値に容量を掛けます。その容量まで多くのセッションがコンテナ内で同時に実行できるためです。Kubernetes と Docker Compose レシピは CPU またはメモリ制限なしで--capacity 4を実行するため、実行する容量のサイズ設定された制限を追加してください。 -
1 つのホスト上の複数のランナーコンテナ: 各ランナーは自身のセッションのみを
--capacityに対してカウントするため、ランナーの容量の合計に合わせてホストをサイズ設定します。- メモリ: 1 つのセッションのメモリに合計を掛け、ホスト自身のプロセスが使用する分を加えます
- CPU: 1 つのセッションの CPU リクエストに合計を掛けます。すべてのセッションが同時にバーストできるようにするには、代わりに CPU 制限を掛けます。
--base-dirパスを、他のランナーのコンテナがマウントしないストレージ上で使用してください。
各セッションに専用のメモリ制限を与える
メモリが不足したときに 1 つのセッションが他のセッションを終了させないようにするには、各ランナーを--capacity 1 で、1 つのセッションのメモリに設定した専用のメモリ制限の下で実行してください。
- コンテナ内: コンテナあたり 1 つのランナーを実行し、コンテナのメモリ制限を設定します。例えば Kubernetes では
limits.memory、Docker では--memory、Compose ファイルではmem_limitです。コンテナの制限の合計はホストのメモリ未満に保ってください。ホスト自体のメモリが不足すると、カーネルはホスト上のどこにあるプロセスでも強制終了する可能性があるためです。 - コンテナなしの systemd 下: ランナーのユニットに
MemoryMaxを設定し、ホストあたり 1 つのランナーを実行します。1 つのファイルシステム上で同じ--base-dirを使用するランナーは、そこにクローンされたリポジトリを共有するためです。例えば、checkoutフックなしの--capacity 1では、1 つのリポジトリ上のそれらのセッションが同じチェックアウトで同時に作業する可能性があります。1 つのホストで複数のランナーを実行するには、それぞれにコンテナを与えてください。
--capacity を 1 より上に設定すると、セッションは 1 つの制限を共有します。制限に達したとき、カーネルは強制終了するプロセスをセッション単位で選択しないため、1 つのセッションのメモリ使用が他のセッションを終了させる可能性があります。
Kubernetes では、kubelet の singleProcessOOMKill 設定のどちらの値でもセッションを分離することはできません。また、ラッパースクリプト内のメモリ ulimit でセッションの合計メモリをキャップすることもできません。カーネルは ulimit -v などの値を各プロセスに個別に適用します。
プロセスとスレッドの制限に余裕を残す
プロセスとスレッドの制限をサイズ設定するには、1 つのセッションが必要とする量を測定し、その制限を共有するセッション数を掛けます。それらのセッションが制限に達すると、カーネルは新しいプロセスとスレッドを拒否するため、いずれのセッションでもコマンド、ビルド、テストが失敗する可能性があります。拒否された呼び出しはEAGAIN を返し、その標準メッセージは Resource temporarily unavailable です。
1 つのセッションのピークが 300 のプロセスとスレッドで、4 つのセッションが制限を共有するとします。合計で 1,200 が必要になり、制限を 2,400 にすれば、その 2 倍を必要とするビルドにも余裕を残せます。
各制限の設定場所
この表の各制限はプロセスだけでなくスレッドもカウントし、pids.max は cgroup の制限を保持するファイルです。
TasksMax を設定しない場合、systemd は DefaultTasksMax を適用します。そのデフォルトは、kernel.pid_max、kernel.threads-max、ルート cgroup の pids.max のうち最も低い値の 15% です。
1 つのセッションのピークを測定する
自分のランナーの数値を得るには、ホスト(Kubernetes ではノード)上で 1 つのセッションを測定します。1
1 つのランナーを単独で開始する
コンテナまたは systemd ユニット内に他に何もない状態で、1 つのランナーを
--capacity 1 で開始し、ホストと環境で単独にします。- ホスト: 他のランナーを実行していないホストを使用します。これにより、次のステップでそのプロセスを特定できます。
- 環境: 例えばテスト用に作成した環境で、そこにある唯一のランナーにします。セッションはランナーではなく環境にルーティングされます。
2
ランナーの cgroup ディレクトリを見つける
コンテナ内ではなくホスト上で、例えば
ps を使ってランナーのプロセス ID を見つけます。その ID の /proc/<pid>/cgroup を読み取ります。:pids:を含む行がある: ホストは cgroup v1 を使用しており、ディレクトリは/sys/fs/cgroup/pidsに:pids:の後のテキストを続けたものです- 唯一の行が
0::で始まる: ホストは cgroup v2 を使用しており、ディレクトリは/sys/fs/cgroupに0::の後のテキストを続けたものです
3
代表的なビルドを実行してピークを記録する
1 つのセッションで代表的なビルドを実行し、ランナーの cgroup ディレクトリからピークを取得します。
- ディレクトリに
pids.peakがある: ビルドが終了した後にファイルを読み取ります - ディレクトリに
pids.peakがない: ビルドの実行中にpids.currentを 1 秒ごとに読み取り、最大値を保持します。2 回の読み取りの間のピークは見逃されるため、その値は低めの見積もりとして扱ってください。
4
制限を共有するセッション数を掛ける
- 1 つのランナーの Pod、コンテナ、またはユニット: ピークにランナーの
--capacityを掛けます - 複数のランナーが共有する制限: ピークにそれらの容量の合計を掛けます
5
結果より上に制限を設定する
制限を高くすれば、より重いビルドに余裕を残せます。低くすれば、フォーク爆弾をより早く止められます。
pids.max 制限を確認する
pids.maxに達したかどうかを確認する: 例えばdmesgを使って、ホストのカーネルログでcgroup: fork rejected by pids controller inと cgroup のパスを含む行を検索します。カーネルはその cgroup で最初にプロセスまたはスレッドを拒否したときにのみログに記録するため、ログ全体を検索してください。- 適用中の制限を確認する: ランナーの cgroup ディレクトリとその上位の各ディレクトリで
pids.maxを読み取ります。最も低い値が適用中の制限で、maxはそのレベルで制限がないことを意味します。
Kubernetes
ランナーはデフォルトでポート 8080 でGET /healthz を提供し、--health-port で設定可能です。Kubernetes プローブは追加セットアップなしで動作します。エンドポイントはプロセスが生きている限り 200 を返すため、以下のプローブはデッドプロセスを検出し、スタックしたプロセスは検出しません。ランナーがポーリングを停止したことをキャッチするには、/metricsから last_poll_age_seconds シリーズでアラートを出してください。以下の Deployment は Kubernetes Secret から環境シークレットをマウントし、liveness および readiness プローブを /healthz に指します。90 秒の終了猶予期間を設定します。シャットダウンタイミングを参照して、猶予期間が重要な理由を確認してください。
マニフェストはランナーコンテナに CPU またはメモリ resources を設定しません。実行する容量のサイズ設定されたブロックを追加してください。セッションの CPU とメモリをサイズ設定するで説明されています。
claude-runners 名前空間に存在します。最初に名前空間を作成してください:
(umask 077 && cat > ./environment-secret) を実行し、シークレットを貼り付け、Enter キーを押してから Ctrl-D を押してください。次に Secret を作成してファイルを削除してください:
Docker Compose
以下の Compose サービスは、ランナーが終了するたびに再起動します。これはクラッシュと通常のドレイン後の終了の両方をカバーします。Docker 再起動ポリシーは、書き込み可能なレイヤーを保持して同じコンテナを再起動するため、ランナーは強化姿勢が推奨する新しいファイルシステムではなく、再利用されたファイルシステムで戻ります。このレシピを評価に使用し、本番環境ではコンテナを実行ごとに再作成するか、そうするオーケストレーターを使用してください。 Docker は、コンテナが終了し続ける前に、より長く待機してから再起動します。上限に達するまで、ランナーが起動できない場合、このレシピの下で厳しいループで再起動し続けることはありません。ランナーが終了するときは、その場合に確認する内容について説明しています。シャットダウンタイミング
SIGTERM の後、ランナーはオーケストレーターに強制終了される前に、セッションをクリーンにシャットダウンするための時間を必要とします。必要な時間は起動時にログに記録され、デフォルト設定では This runner needs up to 80s を含む行として出力されます。オーケストレーターの停止タイムアウトを少なくともその秒数に設定してください。Kubernetes では terminationGracePeriodSeconds、Docker Compose では stop_grace_period、またはプラットフォームの同等の設定です。Kubernetes のデフォルトは 30 秒であるため、この設定がないと、ランナーが終了する前にポッドが停止される可能性があります。
SIGTERM を受け取ると、ランナーは新しいセッションの受け付けを停止します。次に、--defer-shutdown-max-min を設定して遅延させない限り、ドレインと呼ばれるグレースフルシャットダウンを開始します。ドレインは 3 つのステップで構成されます:
- ランナーは、まだ実行中のターンが終了するのを最大
--drain-wait-sec秒(デフォルトは0)待機します。 - 各セッションのプロセスツリーを終了します。これには Claude がまだ実行していたコマンドも含まれますが、シェルコマンドの終了後も実行し続けているプロセスは含まれません。
post-sessionライフサイクルフックを実行します。
post-session フックがコミットされていない作業を保存している間に、別のランナーがそのセッションを引き継ぐことはありません。
ログに記録される時間は、次の値の合計です:
- ステップ 1 の
--drain-wait-sec(デフォルトは 0 秒) - ステップ 2 の
--session-stop-grace-sec(デフォルトは 5 秒) - ステップ 3 の
--post-session-hook-timeout-sec(デフォルトは 60 秒) - 固定の 15 秒の余裕
--push-outcome-on-releaseが設定されている場合はさらに 30 秒
--capacity を増やしてもこの時間は増えません。
次のいずれかのフラグを設定する場合は、より多くの時間を確保してください:
--retire-atを使用する場合:リタイア時刻とホストが停止する時刻の間に、典型的なターンが終了するのに十分な時間、ランナーのライフサイクルで説明されているバックグラウンドタスクの待機時間、およびログに記録された時間を確保してください。リタイア時刻は起動のたびに計算します。例えばdate +%sにランナーの想定稼働時間を加えます。--defer-shutdown-max-minを使用する場合:停止タイムアウトには、設定した分数と、ドレイン開始前のさらなる待機時間(デフォルト設定では 75 秒)も含める必要があります。両方については最初のシグナルを超えてドレインを遅延させるで説明しています。ランナーはこの長い時間も起動時にログに記録します。
再起動の前に実行中のターンを終了させる
ローリング再起動の前に実行中のターンを終了させるには、--drain-wait-sec を設定し、停止タイムアウトを少なくともその待機時間に 80 秒を加えた値に引き上げてください。デフォルトの待機時間 0 では、再起動によってまだ実行中のターンが中断され、セッションはプッシュされていない作業を失った状態で別のランナーで再開されます。
--drain-wait-sec:終了させたいターンとバックグラウンドタスクにかかる時間と同程度に設定します。これは最大値です:それらが先に終了した場合、待機は早めに終わります。- 停止タイムアウト:Kubernetes では
terminationGracePeriodSeconds、Docker Compose ではstop_grace_periodです。例えば--drain-wait-sec 120の場合、Kubernetes または Docker Compose のレシピの90を200に置き換えます。 - 他のシャットダウン設定を変更した場合:80 秒はデフォルト設定の場合の値です。使用するフラグで 1 つのランナーを起動し、起動時の行
This runner needs up toに示される数値(待機時間を含みます)以上を使用してください。--defer-shutdown-max-minを設定している場合は、次の起動時の行でSize the stop timeout to at leastの後に示される、より大きい数値を使用してください。これらの数値に加算される要素はシャットダウンタイミングに記載されています。
再起動の前にステータスメッセージを投稿する
セッションを中断する再起動の前に、Owner に Cloud environments 管理ページから環境にステータスメッセージを投稿してもらいます。claude.ai/code では、メンバーはその環境内の自分のセッションでメッセージを確認できます。投稿時に Owner に有効期限を設定してもらうか、ランナーが復帰したらメッセージを削除してもらってください。最初のシグナルを超えてドレインを遅延させる
再起動しているランナーが最初のシグナルでドレインするのではなく、最大n 分間保持するセッションを提供し続けるようにしたい場合は、--defer-shutdown-max-min <n>を設定してください。最初の SIGTERM または SIGINT では、ランナーは新しい作業を受け取るのを停止し、保持するセッションを提供し続けます。ポーリングを続けるため、コントロールプレーンはそれらのセッションを再キューイングしません。Claude Code v2.1.238 以降が必要です。
最初のシグナル後にランナーが保持するセッションに何が起こるか
最初のシグナルに続く最初の 2 つのステージでは、ランナーはセッションをリリースし、リリースされたセッションはユーザーが次のメッセージを送信するときに新しいランナーで再開されます。最初のシグナルからカウントして、ランナーは 3 つのステージを通じて移動します:- 最初の
n分間:ランナーは通常セッションを提供し、--startup-timeout-minと--kill-session-after-minを適用し続けます。--release-idle-session-minも設定した場合、ランナーはユーザーがその時間アイドル状態だったセッションをリリースします。それなしでは、アイドルセッションはランナーに留まります。 n分が経過したとき:ランナーは、アイドルかどうかにかかわらず、まだ保持しているすべてのセッションをリリースします。ランナーはターン途中のセッションのターンが終了するのを待ち、ターンのバックグラウンドタスクのためにさらに最大 60 秒待ってから、そのセッションをリリースします。- リリース後の猶予が経過したとき:ランナーはまだ保持しているセッションをドレインし、コントロールプレーンは各ドレインされたセッションを別のランナーにすぐに再キューイングします。リリース後の猶予は
n分が経過したときに開始され、デフォルトでは 75 秒です。--drain-wait-secを 60 秒より大きく設定した場合、リリース後の猶予は代わりに--drain-wait-sec+ 15 秒になります。
--defer-shutdown-max-min なしの最初のシグナルの場合と同様に、ランナーは直ちにドレインします。ドレインが進行中になると、次のシグナルはランナーを強制終了します。これは、ドレインを開始したのが 2 番目のシグナルであっても、リリース後の猶予の経過であっても同じです。
停止タイムアウトをサイズ設定する
ホストの停止タイムアウトに、少なくとも 3 つの部分の合計を与えてください:設定するn 分、リリース後の猶予、シャットダウンタイミングで説明されているドレインです。デフォルト設定ではリリース後の猶予は 75 秒、ドレインは最大 80 秒かかるため、n 分 + 155 秒を確保してください。--defer-shutdown-max-min が設定されている場合、ランナーはこの合計を起動時に出力します。
ランナーが終了する前に停止タイムアウトが切れると、まだ保持しているセッションでは post-session フックが実行されません。ランナーは登録解除されないため、コントロールプレーンがそれらのセッションを再キューイングするまでに数分、場合によってはそれ以上かかることがあります。停止タイムアウトにその合計を与えることができない場合は、--defer-shutdown-max-min を設定しないままにして、ランナーが最初のシグナルでドレインするようにしてください。
実行中の post-session フックに到達するもの
post-session フックと Claude セッション子は、それぞれ独自の POSIX プロセスグループで実行され、ランナーから分離されているため、停止メカニズムは異なる方法で到達します:
- ランナーが既にドレイン中の
SIGTERM:ランナーを直ちに強制終了し、ドレインの残りをスキップします。--defer-shutdown-max-minなしでは、ランナーが受け取る 2 番目のSIGTERMです。実行中のpost-sessionフックにはシグナルが送信されないため、init プロセスが孤児プロセスを引き取るベアホストでは、フックは独自に終了しますが、監視されていません:タイムアウト予算はもはや適用されず、閉じたログパイプへの書き込みによってSIGPIPEで強制終了される可能性があるため、そこで強制終了から生き残る必要があるフックは独自の出力をファイルにリダイレクトする必要があります。このページのコンテナレシピでは、ランナーはコンテナの PID 1 であり、その終了はコンテナを終了させます。また systemd のデフォルトKillMode=control-groupの下では、Cgroup 全体のキルの項目で説明するように、cgroup 全体のキルがフックにも到達します。どちらの場合も、強制終了をフックにとって致命的なものとして扱い、代わりに猶予期間に依存してください。 - プロセスグループ全体のシグナル(ラッパースクリプト内の
kill -- -<pid>、シェルのジョブ制御、グループ全体のウォッチドッグなど):ランナーと、checkoutフック実行中のサブプロセス(意図的にグループに接続されたままです)に到達しますが、実行中のpost-sessionフックやセッション子には到達しません。 - Cgroup 全体のキル(systemd のデフォルト
KillMode=control-groupや、terminationGracePeriodSecondsが期限切れになったときに Kubernetes がコンテナ全体に送信するSIGKILLなど):フックを含むすべてに到達します。プロセスグループの分離ではこれらから保護できないため、猶予期間はドレイン全体をカバーする必要があります。 - フック独自のタイムアウト:フックが
--post-session-hook-timeout-secを超えると、ランナーはフックの全体プロセスグループにSIGTERMを送信し、2 秒後にSIGKILLを送信します。フックがフォークしたワーカー(tar、rsync、git など)はラッパーシェルと一緒に終了し、孤児として生き残りません。ランナーの監視は、フックの stdio が閉じたときに終了します:独自の出力をファイルにリダイレクトし、SIGTERMステージを超えて生き残るワーカーはランナーの到達範囲を超えています。
post-session フックの数をログに記録するため、静かなドレインとスナップショット途中のドレインを区別できます。
ベースディレクトリと容量をランナー全体で同じに保つ
ランナーがセッション途中で死亡した場合、サーバーはセッションを再キューイングし、環境内の別のランナーがそれを取得します。そのランナーは、独自の--base-dir と --capacity からチェックアウトパスを導出します:--capacity 1 は --base-dir の直下にチェックアウトし、--capacity が 1 を超える場合は代わりにセッションごとの worktree を使用します。同じ環境内のランナーがこれらのフラグのいずれかに異なる値を使用する場合、再開されたセッションの作業ディレクトリが変更され、エージェントが以前に記録した絶対パス(編集、ツール呼び出し、独自のメモ)は、もはや存在しない場所を指します。
環境内のすべてのランナーで同じ --base-dir と --capacity を使用し、インスタンス ID やホスト名などのホストごとの値を使用しないでください。Kubernetes および Docker Compose のレシピと同様に両方のフラグを明示的に渡し、どちらの値もデフォルトに依存しないようにしてください。
ベースディレクトリのデフォルトは /workspace です。--base-dir リファレンス行が記録する例外を除きます。ランナーは書き込みアクセスが必要です。起動時に登録する前に、ランナーはディレクトリを作成し、書き込みできることを確認し、できない場合は cannot create or write to base directory で終了します。ルートとして開始されたランナーはデフォルト /workspace を自分で作成します。非ルートランナーの場合、ランナーを開始する前にディレクトリを作成してランナーのユーザーに所有権を与えるか、--base-dir をそのユーザーが既に所有しているディレクトリを指してください。
事前にウォームアップされたチェックアウトを再利用する
大規模なリポジトリの場合、クローンがセッション起動を支配することがあります。コールドクローンをスキップするには、ランナーが自身のクローンを保持するパスにクローンを自分で用意します。checkout フック がない場合、ランナーは <base-dir>/<repo-owner>/<repo> でリポジトリごとに 1 つの正規クローンを保持し、セッション全体で再利用します。
--capacity 1の場合: ランナーは要求された ref をフェッチし、HEADをデタッチして、それにハードリセットします。これは変更がほとんどない場合、ほぼ瞬時に完了します。--capacityが 1 より大きい場合: ランナーはそのクローンにフェッチし、セッションごとにそこから個別の worktree をチェックアウトします。事前にウォームアップされたクローンによってダウンロードは省略されますが、チェックアウトは省略されません。
- イメージ内にクローンを配置する: ランナーイメージをそのパスにビルドしてクローンを含めます。その後、新しいコンテナはすべてディスクを再利用せずにウォームクローンで起動します。
- 永続ボリューム上にクローンを配置する:
--lock-to-accountで 1 人のユーザーアカウントにプリロックされたランナーで、--base-dirを永続ボリュームに指定すると、ディスクはそのアカウントのみを提供します。プリロックされたランナーは Claude Tag チャネルセッションを取得しないため、このオプションはそれらを提供するランナーには適用されません。
-
クローンの深さ: クローンは
--depthなしでビルドしてください。--single-branchの有無は問いません。ランナーはoriginリモートを持つクローンにフェッチするとき、CLAUDE_RUNNER_FETCH_DEPTHを設定していても--depthを渡しません。完全なクローンでは、各セッションはクローンに欠けているコミットのみをダウンロードします。シャロークローンでは、クローンの最も古いコミットより前に分岐したブランチ上のセッションは、そのブランチの履歴全体をダウンロードします。 -
追跡された変更はリセットされ、追跡されていないファイルは保持される:
--capacity 1では、各セッションはハードリセットから開始され、前のセッションの追跡された変更を削除しますが、ランナーはgit cleanを実行しないため、ロックされたオーナーの以前のセッションからの追跡されていないファイルはツリーに残ります。 -
セッションごとのディレクトリも保持される: チェックアウトの横に、ランナーは実行するすべてのセッションに対して
<base-dir>/_sessions/の下にセッションごとのエントリを作成します。セッションの Claude 設定ディレクトリは、会話トランスクリプトのローカルコピーを保持します。その横には、セッションがある場合、セッションのアップロードされたファイルが配置されます。セッションディレクトリもそこに配置されます。セッションの実行中、セッションごとの worktrees とcheckoutフックチェックアウトを保持し、Claude がそこに書き込んだ他のすべてのものを保持します。 デフォルトでは、ランナーはセッションが終了したときにこれらをそのまま残すため、ランナープロセスより長く存続するディスク上に蓄積されます。すべてのセッションはランナー自身のユーザーとして実行されるため、そのディスクが提供する後続のセッションはそれらを読み取ることができます。永続的な--base-dirを保持する場合は、その成長に対応するようにボリュームのサイズを設定してください。同じことは、Docker Compose レシピ を含む、同じファイルシステム上でランナーを再起動するすべてのセットアップに適用されます。 -
--remove-session-stateを使用する場合、セッションごとのディレクトリは保持されない:--remove-session-stateでランナーを起動して、セッションが終了するときに各セッションのセッションごとのディレクトリを削除させます。削除はベストエフォートです。ランナーがクリーンアップ実行前に強制終了された場合、ディレクトリは残ります。正規クローンとセッションがホスト上の他の場所(一時ディレクトリなど)に書き込んだファイルは、いずれにせよ残ります。 -
git プロキシを使用する場合、リセットはチェックアウトになる:
--use-anthropic-git-proxyを使用すると、ランナーは各セッションの前にクローンの.git/をサニタイズします。オブジェクトストアとシャロー状態は保持し、インデックスは削除します。インデックスがないため、各セッションはほぼ瞬時のリセットではなく、完全なワーキングツリーチェックアウトから開始されます。それでもランナーは、リポジトリを再度クローンするのではなく、既存のクローンにフェッチします。プロキシの下ではサブモジュールプリウォームはサポートされていません。 -
git プロキシを使用する場合、
reftableのプリウォームは ref を失う: ランナーは各セッションの前に.git/をサニタイズする際、.git/refs/を保持し、.git/reftable/ディレクトリを削除します。git のreftableref 形式でプリウォームされたクローンはこの処理によって ref を失うため、代わりに git のfilesref 形式でクローンをプリウォームしてください。 - 長いクローンは回避策を必要としない: ランナーは各 git 操作を 120 秒の無進捗ウォッチドッグと 30 分のハードキャップで制限し、フラットタイムアウトではないため、進捗を報告し続けるスローコールドクローンは完了します。
ランナーがクローンを使用していることを確認する
ランナーがクローンを使用していることを確認するには、--log-level debug を指定してランナーを起動し、そのリポジトリでセッションを開始します。ランナーは Prefetched repo found at とクローンのパスをログに記録します。代わりに No prefetched repo, fresh init at をログに記録した場合、その行に示されたパスで使用可能なクローンが見つからなかったことを意味します。クローンがそのパスにあり、ランナーのユーザーが所有しており、origin という名前のリモートを持っていることを確認してください。
ランナーがクローンを見つけているにもかかわらずセッションの起動が遅い場合は、クローンがシャロークローンになっていないか確認してください。
バージョンをピンする
各セッションの子プロセスはデフォルトでランナー独自のバイナリを実行し、ランナーは自身が起動するセッション内でオートアップデートをオフにします。このデフォルトでは、すべてのセッションはホストにインストールされたか、イメージに組み込まれたバージョンを実行します。ホストレベルのアップデートはランナーが次に開始するときに有効になります。 セッションが実行するバージョンと、それを変更するタイミングを選択します。- バージョンをピンする前に:セッションが使用するすべてのモデルについて モデルが必要とする Claude Code バージョン を確認してください。モデルがセッションで実行されるバージョンより新しいバージョンを必要とする場合、サーバーはそのモデルのリクエストを Claude Code does not support this model で拒否します。
- フリートを 1 つのバージョンに保持するには:ピンされたバージョンでイメージをビルドするか、ベアホストで特定のバージョンをインストールし、オートアップデートを無効にしてください
- 固定フリートをアップグレードするには:現在のバージョンとインストールするバージョンの間の changelog のエントリを確認してから、新しいバージョンをインストールするか、イメージを再ビルドしてランナーを再起動してください
- オンデマンドランナーをアップグレードするには:現在のバージョンとインストールするバージョンの間の changelog のエントリを確認してから、
spawn-runnerフックが起動するイメージを変更してください。新しいランナーにはそれぞれ新しいバージョンが適用されます。すでに起動しているランナー(--min-idleによって起動されたスタンバイランナーを含む)は、終了するまでそのバージョンを維持します。その作業指示は一度しか使用できないため、再起動しないでください。 - セッションが別のバイナリを起動する場合:
--exec-pathまたはcommandフックを使用してランナー独自のもの以外の Claude Code バイナリを起動する場合、セッションはそのバイナリのバージョンを実行します。ランナーをアップデートするときは、そのバイナリもアップデートしてください。 - プラグイン:プラグインマーケットプレイスもオートアップデートしません。ランナーの環境で
FORCE_AUTOUPDATE_PLUGINS=1を設定して、バイナリがピンされたままの間、プラグインをオートアップデートさせます
フリートをスケーリングする
オーケストレーターは、ランナーを追加または削除するタイミングを決定します。ランナーのライフサイクルに関する 1 つのオーナーごとのロックのため、最小レプリカ数は、同時にアクティブになると予想されるユーザーと Claude Tag エージェントの数です。--capacity は、オーナー全体ではなく、1 つのオーナーのセッション内での並列処理を制御します。
2 つのスケーリングアプローチが利用可能です。
- 固定フリート: 静的なランナーレプリカセットを実行し、各ランナーが提供する Prometheus メトリクスに基づいてスケーリングします
- オンデマンドランナー:
claude self-hosted-runner orchestratorサブコマンドを実行します。このコマンドは、利用可能なランナーがないキューに入っているセッションについて Anthropic をポーリングし、spawn-runnerフックを呼び出して、セッションごとに 1 つ起動します。オンデマンドランナーを参照してください。
固定フリートでアイドル状態のセッションを解放する
固定フリートですべてのランナーがオンラインであるにもかかわらずセッションがキューに入ったままになる場合、アイドル状態のセッションが原因である可能性があります。デフォルトでは、セッションはターンが終了した後もスロットを保持し、そのランナーはそのセッションのオーナーにロックされたままになります。チームのクラウドスケジュールタスクが実行のたびに新しいセッションを開始する場合、そのアイドル状態のセッションがすべてのスロットを埋めてしまう可能性があります。 確認するには、各ランナーの Prometheus メトリクスでclaude_code_self_hosted_runner_session_idle_seconds を読み取ります。ランナーが保持する各セッションには独自の系列があり、セッションがビジー状態の間は 0、それ以外の場合はアイドル状態になってからの秒数を示します。許容するアイドル時間を選択してください。作業途中で人が取る休止よりも長く、かつスケジュールタスクの次の実行が始まる前に各実行が解放されるほど短い時間にします。系列をその時間と比較します。
- その時間を超える系列(30 分の場合の
1800など): アイドル状態のセッションがそれらのスロットを保持しているため、--release-idle-session-minを設定します - すべての系列がその時間未満: それほど長くアイドル状態のセッションはありません。ランナーを追加するか、アイドル状態にならないセッションのために
--kill-session-after-minを設定します。 - 系列がないランナー: そのランナーを保持しているセッションはありません。トラブルシューティングの Sessions stay queued を参照してください。
- メトリクスが応答しないランナー: プロセスが終了している可能性があります。ランナーが終了したときの An environment that looks healthy を参照してください。
--release-idle-session-min とその時間(分単位)を指定して起動します(例: --release-idle-session-min 30)。ランナーは、スケジュールタスクと人のどちらが開始したかにかかわらず、その時間アイドル状態が続いたセッションを解放します。
- プッシュされていない作業: 解放されたセッションは次のメッセージで再開されますが、プッシュしていなかった作業は失われます。コミットを保持するには、再開されたセッションはプッシュされていない作業を失うを参照してください。
- ランナーの終了: 最後のセッションを解放したランナーは通常の終了を開始します。デプロイを強化するで説明しているように、スーパーバイザーが新しいファイルシステム上でランナーを再起動するようにしてください。
- アイドル状態にならないセッション: 一部のセッションはアイドル状態としてカウントされないため、
--kill-session-after-minも設定します
既知の問題と制限事項
このリリースにおける制限事項と、回避策がある場合はその回避策を以下に示します。コネクタのトラフィックはネットワーク外に出る
Anthropic は、コネクタのツールをランナーからではなく、Anthropic 自身のインフラストラクチャから呼び出します。コネクタのツールとは、GitHub、Slack、Linear などの claude.ai のコネクタです。セルフホストセッションで Claude がコネクタを使用すると、そのトラフィックはネットワーク境界の内側から発信されるのではなく、api.anthropic.com を経由します。
コネクタをセルフホストセッションから除外するには、allowedMcpServers および deniedMcpServers ポリシー設定でフィルタリングします。Claude Code はこれらの設定を、ランナーホストからシードするサーバーやユーザーが追加するサーバーだけでなく、Anthropic が配信するコネクタにも適用します。そのため、他のサーバー向けに許可リストをデプロイすると、Claude Code は配信されたコネクタもブロックします。URL ベースの許可リストを使いながらコネクタを引き続き利用できるようにするには、配信されるコネクタ用の Anthropic プロキシのパスに一致するエントリを追加します。
https://api.anthropic.com/v2/ccr-sessions/*https://api.anthropic.com/v1/code/sessions/*https://api.anthropic.com/v1/code/mcp/*
一部のセッションはアイドルとみなされない
終了しないバックグラウンドタスクを保持しているセッションはアイドルとみなされないため、--release-idle-session-min はそのセッションのスロットを解放しません。実行中のツール呼び出しの内部から要求された承認を待っているセッションも、アイドルとみなされません。どのセッションもスロットを無期限に保持できないように、厳格な安全策として必ず --kill-session-after-min を併せて設定してください。
--kill-session-after-min は、暴走したセッションに対する安全策です。v2.1.260 以降のランナーでは、上限に達したセッションはただちに終了されません。ランナーはそのセッションに猶予期間(デフォルトは 15 分)を与えます。この期間は SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS で変更できます。
- セッションがユーザーを待っている場合、ランナーはそのセッションを解放します。ターンが終了していてバックグラウンドタスクのみを保持している場合、ランナーはそれらのタスクが完了するまで最大 60 秒待ってから、セッションを解放します。セッションは、ユーザーが次のメッセージを送信すると再開されます。
- ターンがまだ実行中の場合、ランナーはターンが完了するか、セッションが次にユーザーを待つ状態になるまで待ってから、セッションを解放します。
- 猶予期間が終了した時点でセッションがまだランナー上にある場合、ランナーはセッションを終了し、実行中のターンの作業は失われます。実行中のツール呼び出しの内部から要求された承認をターンが待っている場合は、セッションが猶予期間を超えて残る一例です。
--kill-session-after-min 480 とします。アイドル状態になった会話からスロットを解放するには、代わりに --release-idle-session-min を使用してください。
その他の制限事項
- 再開されたセッションではプッシュしていない作業が失われる: 新しいランナーはリポジトリを開始ブランチから再度クローンするため、セッションがプッシュしていなかった作業は失われます。
- コミット済みの作業を保持するには: 環境内のすべてのランナーで
--push-outcome-on-releaseを設定してください。このフラグのないランナーは、セッションを開始ブランチから再開するためです。このフラグを設定したランナーは、解放する前にセッションの成果ブランチのプッシュをベストエフォートで行い、再開されたセッションはそれらのコミットから開始されます。プッシュにはランナーホスト自身の git 認証情報が使用されます。これは Anthropic 管理の git を使用するランナーでも同様です。 checkoutフックを使用する場合:checkoutライフサイクルフックでチェックアウトされたリポジトリはプッシュされません。代わりにpost-sessionフックからそれらのスナップショットを取得してください。- フラグを有効にする前に: ソースリモート上の
claude/*ref にプッシュできるユーザーを制限してください。再開時、ランナーは以前にプッシュされたブランチを、誰がプッシュしたかを検証せずにフェッチします。 - コミットされていない変更は引き続き失われる: Claude が応答を終えたときにコミットとプッシュを行うよう促すには、セッションに作業のプッシュを促すを参照してください。
- コミット済みの作業を保持するには: 環境内のすべてのランナーで
- ランナーの喪失によって中断されたコマンドが再度実行されることがある: セッションが別のランナーで再開されると、中断されたツール呼び出しが、その成否が不明であることを示す結果とともに Claude に表示されます。
- セッションの途中で追加したリポジトリのクローンが失敗することがある: Claude は HTTPS 経由の
git cloneでリポジトリをクローンします。--use-anthropic-git-proxyを使用していないランナーでは、ホスト上にリポジトリを読み取れるものが何もない場合、クローンは git の認証エラーで失敗します。可能であれば、セッションの作成時に、セッションで必要なすべてのリポジトリを選択してください。 - 一部のコネクタがセルフホストセッションに表示されない: claude.ai の設定でまだ接続していないコネクタはセルフホストセッションに表示されず、セッションから接続を求められることもありません。まず設定で接続してから、新しいセッションを開始してください。また、すでに実行中のセッションにコネクタを追加しても、そのツールは Claude で使用できるようになりません。新しく追加したコネクタを反映するには、新しいセッションを開始してください。
- 誰かがセッションをアーカイブまたは削除した場合、またはセッションのメニューからランナーを解放した場合:
--push-outcome-on-releaseによるプッシュは当てにしないでください。このような場合にコミットを保存するには、post-sessionフックからHEADを退避用ブランチにプッシュしてください。そこにある例をもとにする場合は、コミットされていない変更が何もないときでもプッシュするように変更してください。この例はスナップショットのコミットを作成した後にのみプッシュするためです。
問題を報告する
セルフホスト環境に関する問題については、Anthropic のアカウントチームにお問い合わせください。トラブルシューティング
ガイド付きの診断を行うには、ランナーホストで doctor サブコマンドを実行します。doctor サブコマンドは、ランナーのログと状態を添付した対話型の Claude Code セッションを開始します。セッションが環境、そのランナー、キューに入っているセッションを照会できるように、先にそのホストでclaude auth login を使ってサインインしてください。このサインインがない場合(たとえばホストが API キーで認証する場合)、利用できるのはローカルのヘルスエンドポイント、メトリクス、ランナーのログに限られ、ログを読み取るのもランナーを --log-file 付きで起動した場合のみです。
-
ランナーが環境に表示されない: ホストが HTTPS 経由で
api.anthropic.comに到達できること、環境シークレットが最新であること、ホストの時計と実時間との差が 5 分以内であることを確認してください。それより大きなずれがあると認証が失敗します。認証に失敗すると、ランナーは拒否理由とともに[runner:fatal]をログに記録します。 -
ランナーが起動時に
cannot create or write to base directoryで終了する: ランナーが--base-dir(デフォルトは/workspace)を作成できないか、書き込めません。ランナー間でベースディレクトリと容量を同一に保つで説明しているとおり、ディレクトリの所有権を修正するか、--base-dirを書き込み可能なパスに向けてください。代わりにランナーがベースディレクトリのチェックがタイムアウトしたという[runner:fatal]をログに記録する場合、そのディレクトリはハングした NFS または CSI マウント上にあります。権限ではなくマウントの健全性を確認してください。ランナーはこれら 2 つの起動時の失敗を--log-fileを開く前に stderr に出力するため、ログファイルではなくターミナルまたはプラットフォームのコンテナログで探してください。v2.1.225 より前は、ランナーは起動時にベースディレクトリをチェックしておらず、この設定ミスがあると代わりにピックアップ後にセッションが失敗していました。 -
ランナーが起動時に
RegisterRunner failed:と TLS 証明書エラーで終了する: エラーはたとえばself signed certificate in certificate chainとなることがあります。TLS を検査するプロキシの背後にある場合のように、ランナーが受け取った証明書の背後にある認証局(CA)を信頼していません。ランナーの環境でNODE_EXTRA_CA_CERTSに、プロキシのルート CA を含む PEM ファイルを設定してください。 セッションはこれを継承するため、セッション用に再度設定する必要はありません。Git はこれを読み取りません。そのプロキシを経由したクローンには、GIT_SSL_CAINFOも設定してください。 -
開始スクリプトが
Resource temporarily unavailableを含む書き込みエラーを出力して終了する: スクリプトが、自身が起動するclaude self-hosted-runnerまたは orchestrator プロセスと stdout または stderr を共有しており、そのプロセスが共有のパイプまたはソケットをノンブロッキングモードに切り替えています。パイプがいっぱいになると、スクリプトからの書き込みは待機せずにこのオペレーティングシステムのエラーで失敗し、set -eの下ではスクリプトが終了します。 このエラーを止めるには、ランナーまたはオーケストレーターの出力を、スクリプトのユーザーが作成できるファイルに送ってください。それを起動するコマンドに、バックグラウンド化する&より前の位置で>> "$HOME/claude-runner.log" 2>&1を追加します:スクリプト自身の出力は引き続き以前と同じ場所に出力され、ランナーが stdout と stderr に書き込む内容(起動エラーを含む)はそのファイルに出力されます。--log-file単体ではなく、このシェルリダイレクトを使用してください。--log-fileはログをファイルにミラーリングしますが、ランナーは stdout と stderr への書き込みを続けます。すでに--log-fileを渡している場合は、それもそのまま残してください。リダイレクトはそのファイルが受け取る内容を変えないためです。 -
オーケストレーターが TLS 証明書エラーとともに
poll failed:をログに記録し、再試行を続ける: TLS を検査するプロキシの背後にある場合のように、オーケストレーターが受け取った証明書の背後にある CA を信頼していません。オーケストレーターの環境でNODE_EXTRA_CA_CERTSに、プロキシのルート CA を含む PEM ファイルを設定してください。spawn-runnerフックが起動するランナーにも設定してください。 たとえば、行がpoll failed: self signed certificate in certificate chain — retrying in 1sで終わることがあり、コロンとダッシュの間に TLS ライブラリの文言が入ります。修正を確認するには、オーケストレーターの/healthzのボディでconnectedがtrueであることを確認してください。 -
セッションがキューに入ったままになる: すべてのオンラインランナーがそれぞれ別の所有者にロックされている可能性があります。各ランナーの
claude_code_self_hosted_runner_locked_accountメトリクス、またはその[runner:health]ログ行のlocked_accountフィールドを確認して、誰がロックしているかを調べてください。どちらも、act.emailクレームを含むセッショントークンがランナーに発行された後にのみ所有者のメールアドレスを表示しますが、Claude Tag エージェントのセッションではこのクレームが含まれることはありません。クレームがない場合、ランナーはlocked_account系列を出力せず、locked_account=yesをログに記録します。これはランナーがロックされていることを示しますが、どの所有者にロックされているかは示しません。レプリカを追加するか、既存のランナーがドレインして再起動するのを待ってください。環境がオンデマンドランナーを使用している場合は、代わりにオーケストレーターを確認してください。オンデマンドランナーを参照してください。 -
ピックアップ直後にセッションが失敗する: claude.ai/code でセッションを開いてエラーを確認してください。git が認証できなかったことをエラーが示している場合は、ランナーの git 認証情報を確認してください。
--use-anthropic-git-proxy付きで起動したランナーでは、git プロキシを使用するランナーでセッションの開始に失敗した場合を参照してください。 書き込めないベースディレクトリは、セッションを失敗させるのではなく、起動時にランナーを停止させます。このリストの ランナーが起動時にcannot create or write to base directoryで終了する の項目を参照してください。 -
セッションはピックアップされたが、Claude が最初のメッセージに応答しない: ランナーがプロキシ経由で
api.anthropic.comに到達している場合は、セッションの/worker/events/streamレスポンスを到着したとおりに通過させるようにプロキシを設定してください。ランナーのタイムアウトを引き上げても解決しません。ランナーのログで原因を確認するには、セッションはピックアップされたが、Claude が最初のメッセージに応答しないを参照してください。 -
--use-anthropic-git-proxyを設定したランナーでセッションの開始に失敗する: ランナーのログでaccess denied by the git proxy、または/git_proxy/を含むapi.anthropic.comアドレスを示す git エラーを探してください。Anthropic がセッションを処理したかどうかを判断して原因を修正するには、git プロキシを使用するランナーでセッションの開始に失敗した場合を参照してください。 -
認証を行うエグレスプロキシ経由でセッションがネットワークに到達できない:
--proxy-authorization-commandまたは--proxy-authorization-fileで設定したソースが失敗する、30 秒後にタイムアウトする、または空の値を返す場合、ランナーはその接続に502 Bad Gatewayで応答し、理由をログに記録します。ランナーはそのログ内でコマンドの stderr を秘匿し、ヘッダー値をログに記録することはありません。--proxy-authorization-commandを使用している場合は、ホスト上でそのコマンドを自分で実行し、ヘッダー値全体が stdout に出力されることを確認してください。代わりにランナーが起動時にcould not start the proxy-authorization listenerで終了する場合、ランナーはループバックリスナーを開けませんでした。 -
ランナーが
rejecting the malformed poll responseを含むPoll failed行をログに記録する: ランナーが受け取ったワークポーリングのレスポンスのボディが、キューが想定する JSON ではありません。原因の 1 つは、インターセプトプロキシやキャプティブポータルが独自のページで応答したことです。ランナーがプロキシ経由で接続している場合は、api.anthropic.comからのレスポンスを変更せずに通過させるようにプロキシを設定してください。 ランナーはその不正なレスポンスを拒否し、claude_code_self_hosted_runner_poll_errors_totalメトリクスのtransport種別としてカウントし、セッションのライフサイクルで説明されているポーリング失敗時のスケジュールで再試行します。ランナーは稼働中のセッションの処理を続けます。v2.1.246 より前は、ランナーはこのようなレスポンスを空のワークキューとして読み取っていたため、稼働中のセッションが終了したり、ランナーが終了したりすることがありました。 -
セッションが
no longer exists on the remoteまたはcouldn't find remote refで失敗する: ランナーは git のcouldn't find remote refを、ブランチが削除されたものとして解釈します。ブランチはまだ存在している可能性があります。メッセージ内の名前そのままで git ホスト上のブランチを探し、当てはまる各原因を確認してください:- ブランチが存在しない: メッセージの求めに従ってブランチを復元してください。
- ブランチは存在し、自分はランナーを管理していない: ランナーの管理者にメッセージ全文を送り、ブランチが存在することを伝えてください。
- ブランチは存在し、ランナーに
checkoutフックがある: フック内の git コマンドが、フックが 0 以外で終了する前にcouldn't find remote refを stderr に出力することがあります。そのコマンドを見つけ、要求している ref またはフェッチ元のリモートを修正してください。ランナーは、セッションが要求したリビジョンをCLAUDE_RUNNER_REPO_REFとしてフックに渡します。 - ブランチは存在し、ランナーに
checkoutフックがない: ランナー自身がブランチをフェッチします。リポジトリに--git-host-rewriteが適用される場合は、書き換え先のホストに同じ名前のブランチがあることを確認し、ない場合はそこにブランチをプッシュしてください。 - ブランチは存在し、ランナーが v2.1.301 より古い: 別の失敗がそれ自体のエラーを表示するように、バージョンを固定するで説明しているとおりランナーをアップグレードしてください。v2.1.301 より前は、エラー出力に
couldn't find remote refを含むその他の失敗も、ブランチの削除として報告されていました。
-
セッションがリポジトリの 1 つを欠いたまま開始される:
checkoutフックのないランナーでは、セッションが読み取るだけのリポジトリについて、git ホストがランナーのアクセスチェックを拒否することがあります。その場合、ランナーはそのリポジトリをスキップし、拒否内容を示す[runner:warn] could not access context source行をログに記録して、残りのリポジトリでセッションを開始します。 ランナーがスキップするのは明確な拒否の場合のみです。つまり、ホストがリポジトリが見つからないと応答した場合、git がホストの認証情報を見つけられない場合、または認証に失敗した場合です。ネットワーク障害、タイムアウト、HTTP403の場合は、セッションが結果をプッシュするリポジトリに対する拒否と同様に、引き続きセッションの開始が失敗します。スキップするとリポジトリがまったくなくなるセッションは、引き続きランナーによって失敗とされます。--use-anthropic-git-proxyを使用する場合、ランナーは git プロキシ自体が拒否したリポジトリのみをスキップします。 アクセスチェックはセッションがランナー上で開始されるたびに再度実行されるため、ランナーの git ID に読み取りアクセス権が付与されると、次回の開始時にリポジトリがクローンされます。v2.1.274 より前は、これらの拒否のいずれでもセッションの開始が失敗していました。 -
セッションが
This runner couldn't readで開始に失敗する: ランナーが git 認証情報を使って git ホストにリポジトリを要求し、見つからないという応答を受け取りました。リポジトリが存在しないか、その認証情報ではリポジトリにアクセスできません。- ランナーを管理している場合: ランナーの git 認証情報にリポジトリへの読み取りアクセス権を付与してから、新しいセッションを開始してください。
- セッションを開始した場合: リポジトリが存在しない場合は、正しいリポジトリで新しいセッションを開始してください。ランナーがリポジトリにアクセスできない場合は、ランナーの管理者にアクセス権の付与を依頼してから、新しいセッションを開始してください。
-
セッションの開始または再開に数分かかる: 原因の 1 つは新規のクローンです。各ランナーを空のディスクで起動し、
checkoutフックがないフリートでは、ランナーは Claude Code を起動する前にセッションのリポジトリを新たにクローンします。空のディスク上で再開するセッションも、同じクローンを再び待つことになります。 新規のクローンを省略するには、事前にウォームアップしたチェックアウトを用意してください。すでに用意している場合は、ランナーがそれを使用していることを確認してください。ランナー自身がクローンを作成し、1 つのセッションの後に終了する場合は、CLAUDE_RUNNER_FETCH_DEPTHをデフォルトの 50 コミットから下げて、フェッチする履歴を減らしてください。 フックを使用している場合、フックはランナーのクローンの代わりに実行されるため、代わりにフックの処理内容を確認してください。開始にかかる時間を確認するには、claude_code_self_hosted_runner_session_init_duration_secondsメトリクスを監視してください。 -
ターンが 401 で失敗する: ターンが Anthropic API からの 401 または 403 で終了すると、ランナーは Anthropic から新しい
CLAUDE_CODE_OAUTH_TOKENを取得してセッションに渡します。失敗したターンは再試行されません。このトークンは有効期間が短く、ランナーはセッションの stdin を介してこれをローテーションします。 取得に失敗すると、ランナーはいつ再試行するかを示すinference_token refresh failed行をログに記録し、セッションが実行されている間は再試行を続けます。 セッション開始から約 30 分後にすべての呼び出しが失敗し始める場合は、ラッパースクリプトがセッションの stdin を切断しているため、トークンのローテーションが届いていない可能性があります。stdin とファイル記述子 3 を接続したままにするを参照してください。 v2.1.274 より前は、ランナーは失敗した取得の再試行を数回で停止し、次の予定された取得を待っていました。失敗したターンでは取得がトリガーされなかったため、次の予定された取得まですべてのターンが 401 で失敗していました。 -
claude.ai/code でターンが
This model needs a newer version of Claude Codeで失敗する: ランナーがセッションの開始に使用する Claude Code のバージョンが、セッションのモデルが必要とするバージョンより古いため、API がリクエストを拒否します。バージョンを固定するで説明しているとおり、メッセージが求めるバージョン以降にランナーをアップグレードしてください。それまでは、セッション内で別のモデルを選択できます。 -
ドレイン中に Pod が強制終了される:
terminationGracePeriodSecondsを、ランナーが起動時にログに記録する値以上に引き上げてください。シャットダウンのタイミングを参照してください。
[runner:fatal] 行を含むライフサイクルログを stdout に、デバッグ出力を stderr に、いずれも JSON ではなくプレーンテキストの行として書き込みます。上記のトラブルシューティング項目で説明したベースディレクトリの失敗は、その時点より前に stderr に出力されます。両方のストリームを --log-file(これにより self-hosted-runner doctor がそれらを tail できるようにもなります)またはプラットフォームのログ収集でキャプチャしてください。
各セッションの子プロセスは個別のデバッグログを書き込みます。失敗時には、ランナーは claude.ai/code でセッションとともにそのログの末尾を表示します。--remove-session-state 付きでランナーを起動していない限り、ランナーは失敗したセッションのログもディスク上に保持し、そのパスをランナーログに出力します。
ランナーが終了したとき
オンデマンドランナーは、作業指示が 1 回限りのものであるため、再起動しないでください。起動直後に終了するランナーは、それ以外の理由で終了するランナーとは異なる対処が必要です。- 正常な終了: ランナーがセッションを終えてドレインした、リタイア時刻に達した、または停止を指示された場合です。環境が再び処理能力を持てるように、ランナーを再起動してください。これらの終了についてはランナーのライフサイクルで説明しています。
- 起動の失敗: ランナーは与えられた設定またはホストでは起動できないため、起動から数秒で終了し、再起動するたびに同じように終了します。より早く再起動しても解決しません。誰かが出力を読み、原因を修正する必要があります。
- 接続の喪失: たとえばホストがスリープしている間など、リースより長く Anthropic に到達できないランナーは、環境から削除されることがあります。削除されたランナーは再接続すると終了します。そのログには、
runner record gone server-sideを含む[runner:fatal]行、またはより長い停止の後にはpoll auth failedが表示されることがあります。ランナーは自動的に再登録されないため、再起動してください。
起動の失敗を見分ける
ランナーは起動できない場合、その理由を示す行を出力してから終了します。ほとんどの原因では、その行に[runner:fatal] が含まれます。一部の原因では、代わりに行が error: で始まります。これには、ランナーがフラグを解析できない場合、環境シークレットを読み取れない場合、ベースディレクトリを作成できないか書き込めない場合が含まれます。その場合、次の行で --help が案内されます。
ほとんどのログ行はタイムスタンプと [self-hosted-runner] で始まりますが、以下のサンプルでは省略しています。たとえば、Anthropic git プロキシと 1 を超える容量で起動したランナーは、次のような行を出力します:
--log-file で設定したファイルで探してください。ランナーはログファイルを開く前に error: 行を出力するため、トラブルシューティングで説明しているとおり、ターミナルまたはコンテナログで探してください。
起動の失敗を読み解く際には、次の点も役立ちます:
- 行がまったくない: ホストによって強制終了されたランナーは、どちらの行も出力しません。出力が
[runner:fatal]行もerror:行もなく終わっている場合は、たとえばメモリ制限を超えたためにホストまたはオーケストレーターがプロセスを停止したかどうかを確認してください。 - 終了コード: ランナーは、起動のたびに繰り返されるエラー専用の終了コードを用意していません。サポートされていないフラグの組み合わせなどの設定エラーでも、ランナー自身の再試行を通じて API に到達できない状態が続くなど自然に解消する可能性のある失敗でも、同じコードで終了します。待機時間を長くするかどうかは、ランナーがどれだけ早く終了したかに基づいて判断し、理由を知るにはランナーの出力を読んでください。
- 正常に見える環境:
--configure-gitや Anthropic git プロキシの認証情報のセットアップなど、一部の起動ステップはランナーが環境に登録された後に実行されます。これらのステップのいずれかが失敗すると、プロセスが終了した後も数分間、環境がそのランナーを一覧に表示し続けることがあり、どのランナーも作業をピックアップしていないのに Cloud environments ページに Healthy と表示されることがあります。正常に見える環境でセッションがキューに入ったままになる場合は、スーパーバイザーがランナーを再起動し続けていないか確認してください。
待機時間を延ばしながら再起動する
待機時間を延ばしていく方法は、スーパーバイザーによって異なります。-
Kubernetes: このページの Deployment は変更不要です。コンテナが終了した後、kubelet はデフォルトでコンテナを再起動する前に待機し、その待機時間は再起動のたびに上限まで延びます。コンテナが終了せずにしばらく実行されると、待機時間は最初からやり直しになります。
kubelet は、コンテナの実行時間が短かった場合は正常終了の後にも同じ待機を適用します。そのため、頻繁にドレインするランナーも
CrashLoopBackOffステータスを表示することがあるので、ランナーが起動できないと結論づける前に出力を読んでください。以下のコマンドは、Deployment の 1 つの Pod から前回の実行の出力を読み取ります:前回の実行が起動の失敗であった場合、[runner:fatal]またはerror:行は出力の最後のほうの行にあります。別の Pod の前回の実行を読むには、deploy/claude-runnerの代わりにその Pod の名前を指定してください。 -
Docker と Docker Compose: このページの Compose レシピは変更不要です。
restart: alwaysを指定すると、Docker は終了し続けるコンテナの再起動のたびに、上限まで待機時間を長くします。以下のコマンドの<container>をコンテナ名に置き換えてください。このコマンドは、Docker がコンテナを再起動した回数を読み取ります:コマンドは数値を出力します。数値が増え続けている場合は、Docker がランナーを再起動し続けていることを意味します。 -
systemd ユニット: デフォルトでは、systemd は再起動のたびに同じ
RestartSecだけ待機し、それを延ばさないため、Restart=alwaysのユニットは、起動できないランナーを毎回同じ間隔で再起動します。起動がユニットの起動レート制限(デフォルトでは 10 秒間に 5 回の起動)に達するほど速く行われると、systemd はユニットの再起動を停止します。ユニットは誰かが再び起動するまで停止したままになります。systemd がそれを許可するのは、レート制限の間隔が経過した後、またはsystemctl reset-failedの後です。RestartSecはすべての再起動に適用されるため、値を長くすると正常終了後の再起動も遅れます。この 2 つのバランスを取る値を選び、ユニットの再起動回数に対してアラートを設定してください。 - シェルループまたは独自のスーパーバイザー: 同じルールを自分で適用してください。5 秒の待機から始めます。1 分以内に終了した実行の後は、次の再起動までの待機時間を最大 5 分まで 2 倍にします。1 分以上続いた実行の後は、5 秒に戻します。
ランナーが終了し続ける理由を確認する
ランナーが起動直後に終了することを何度も続けて繰り返した場合は、再び再起動する前にいったん止めて、次の点を確認してください。- 最後の
[runner:fatal]またはerror:行: ランナーが停止した理由が示されています。一般的な原因はトラブルシューティングに記載しています。 - フラグの組み合わせ: Anthropic git プロキシには
--capacity 1が必要です。このページのレシピではより大きな容量を使用しているため、いずれかのレシピにプロキシを追加する場合は容量を下げてください。 - サービスの環境から到達できるもの: ランナーを手動で起動すると成功するのに、スーパーバイザーの下では失敗する場合は、ユーザー、ホームディレクトリ、
PATH、メモリ制限を比較してください。--configure-gitと Anthropic git プロキシには、PATH上の git と書き込み可能な~/.gitconfigが必要です。 - 環境シークレット: シークレットを取り消したか、入力を誤った場合、ランナーは
RegisterRunner auth failedを含む行を出力します。 - 環境の Activity タブ: 環境を開き、Activity を選択します。そこに新しいランナーが次々と表示され、どれも作業をピックアップしていない場合は、スーパーバイザーがランナーを再起動しています。
セッションはピックアップされたが、Claude が最初のメッセージに応答しない
ランナーがセッションをピックアップしたのに Claude が最初のメッセージに応答せず、ランナーがプロキシ経由でapi.anthropic.com に到達している場合は、プロキシが原因である可能性があります。Anthropic は、開いたままになる 1 つのストリーミングレスポンスを通じてセッションにメッセージを送信します。プロキシがこのレスポンスをバッファリングしたり、何も渡さないうちに終了させたりすると、最初のメッセージは届きません。セッションからの他のリクエストは引き続き成功します。
修正するには、プロキシがこのリクエストを処理する方法を変更してください:
- レスポンスをバッファリングしない: 到着したとおりに通過させてください。コンテンツタイプは
text/event-streamです。 - レスポンスを開いたままにする: レスポンスは最長 1 時間開いたままになることがあります。プロキシにアイドルタイムアウトがある場合は、15 秒よりも十分に長くしてください。Anthropic はデフォルトで少なくともその頻度でキープアライブを送信するためです。
ランナーのログで原因を確認する
以下の手順は、デフォルトの--log-level info で動作する Claude Code v2.1.287 以降のランナーを対象としています。それより古いランナーでは、これらの行はより遅れて記録されるか、まったく記録されません。
--startup-timeout-min(デフォルトは 15 分)が経過するのを待ちます。するとランナーはセッションを停止し、no child output forを含み— releasingで終わる行をログに記録します。- ランナーのログで
SDKStartup: SSEを検索します。これらの行は、手順 1 の行から数行後にあるfinished: interrupted行に続きます。ほとんどの行にはタイムスタンプがないため、ログコレクターでは別の場所に表示されることがあります。 - 次の表で該当する行を見つけます:
ログにこれらの行がいずれもない場合、またはプロキシのログに問題が見当たらない場合は、問題を報告してください。
セッションの再試行を止める
セッションはメッセージを保留したままにし、セッションの所有者に対応できるランナーがセッションを再びピックアップします。プロキシを変更するまで、セッションは毎回同じように待機します。これを止めるには、claude.ai/code でセッションをアーカイブしてください。次のステップ
- セッションをカスタマイズする:ラッパースクリプト、ライフサイクルフック、オンデマンドランナー、MCP サーバー、権限
- エンドツーエンドをテストする:本番環境に昇格させる前に新しいランナーイメージを検証する
- リファレンス:すべての CLI フラグ、環境変数、メトリクス