GitHub Actionsのセルフホストランナー(セルフホステッドランナー、self-hosted runner)は、自分で用意したマシンにランナーアプリケーションを入れ、そこでワークフローのジョブを動かす仕組みです。GitHubが用意する仮想マシン(GitHub-hosted runner)と違い、OS・CPU・メモリ・社内ネットワークへの到達性を自分で決められます。その代わり、OSの更新・ランナーの更新・ジョブ間の後片付けはすべて利用者の責任になります。
この記事では、2026年10月時点のランナー最新版 v2.338.0(2026-10-06公開)を前提に、hosted版との違い、料金の現状、Linuxでの導入コマンド、runs-on の書き方、運用で踏みやすい期限と上限、常駐ランナーの後片付け、セキュリティ、オートスケールまでを公式ドキュメントとランナーのソースコードで確認した内容で整理します。
まとめ:セルフホストランナー導入の要点
- 料金:GitHub Actions側の利用料は2026年10月時点で無料です。2026年3月1日から1分0.002ドルを課金する計画は発表直後に延期され、再開日は示されていません。マシン代・電気代・運用工数は自己負担です。
- hosted版との最大の差:ジョブごとにまっさらな環境が用意されない点です。前のジョブのファイルや認証情報が残るので、既定の常駐ランナーはプライベートリポジトリ専用と考えてください。
- 導入:Settings → Actions → Runners → New self-hosted runner で表示されるコマンドを実行し、
config.shで登録します。登録トークンの有効期限は1時間です。 - 指定方法:ワークフローでは
runs-on: [self-hosted, linux, x64]のようにラベルを並べます。並べたラベルをすべて持つランナーにだけジョブが割り当てられます。 - 期限:新版公開から30日以内に更新しないとジョブが来なくなります。GitHub Enterprise Cloudでは2026年9月29日から、このルールと登録時の最低版(v2.329.0)が全面施行されています。14日間接続が無いランナーは登録ごと消えます。
- 常駐運用:1台のランナーが同時に実行するジョブは1つです。
_workにリポジトリやビルド成果物が残り続けるので、ジョブ前後のスクリプトで掃除します。 - 台数を増やすなら:Kubernetesがあれば Actions Runner Controller(ARC)、無ければ Scale Set Client か
workflow_jobwebhook で、使い捨て(ephemeral)ランナーを自動で出し入れします。マシンを持ちたくなければ AWS CodeBuild や Cloud Run のワーカープールにランナーを任せる方法もあります。
GitHub Actionsのランナーの役割とセルフホスト型の位置づけ
ランナーは、ワークフローのジョブを受け取って実行するマシンです。GitHub Actionsのサービスはジョブをキューに積むだけで、実際に git checkout やビルドを行うのはランナー上で動くランナーアプリケーションです。このアプリケーションは actions/runner としてオープンソースで公開されており、GitHub-hosted runner の中でも同じものが動いています。
ランナーの提供形態は2つあります。GitHubが仮想マシンを用意して課金するのが GitHub-hosted runner、利用者が自分のマシンにランナーアプリケーションを入れるのがセルフホストランナーです。「セルフホストランナー」「セルフホステッドランナー」「self-hosted runner」は同じものを指す表記ゆれで、GitHubの日本語ドキュメントは「セルフホステッド ランナー」と書いています。
セルフホストランナーは物理マシン・仮想マシン・コンテナのどれでもよく、オンプレミスでもクラウドでも構いません。登録先はリポジトリ・Organization・Enterpriseの3階層から選べ、リポジトリ単位なら1リポジトリ専用、Organization単位なら組織内の複数リポジトリで共有できます。GitHub Actions全体の仕組みはGitHub Actionsのできることと使い方の解説にまとめています。
GitHub-hosted runnerとの違い:スペック・料金・上限の比較
違いは「誰が環境を管理するか」に尽きますが、判断に効くのは下の数値です。hosted版の値は公式ドキュメントの標準ランナー(2026年10月時点)です。
| 項目 | GitHub-hosted runner | セルフホストランナー |
|---|---|---|
| Linux x64のスペック | パブリック 4コア/16GB、プライベート 2コア/8GB(SSD 14GB) | 自由(GPU・大容量メモリも可) |
| Actionsの利用料 | パブリック無料、プライベートは無料枠超過分が従量 | 無料(マシン代は自己負担) |
| Linux 2コアの単価 | 0.006ドル/分 | なし |
| ジョブの実行時間上限 | 6時間 | 5日 |
| ジョブごとの環境 | 通常は新規VM(ubuntu-slimはコンテナ) | 常駐型は状態が残る |
| OS・ツールの更新 | GitHubが実施 | 利用者が実施 |
| 社内ネットワークへの到達 | 不可(別途プライベート接続が必要) | そのまま可能 |
プライベートリポジトリの無料枠は、Free 2,000分・Pro 3,000分・Team 3,000分・Enterprise Cloud 50,000分(いずれも月あたり)です。無料枠を超えて hosted 版を使うと Linux 2コアで1分0.006ドル、macOS は1分0.062ドルかかります。分単価の全体と無料枠の数え方はGitHub Actionsの料金と2026年改定後の分単価で扱っています。
セルフホストを選ぶべき条件と選ぶべきでない条件
セルフホストを候補にするのは、次のいずれかに当てはまり、必要な機能と保守費用を含む総コストを確認できた場合です。月の実行時間が長く hosted 版の従量課金が積み上がっている、GPUや64GB超のメモリなど標準ランナーに無いハードウェアが要る、社内のデータベースや検証環境など外部から到達できない資源にジョブから触る必要がある、6時間を超えるジョブがある。最後の条件では、ジョブの timeout-minutes が既定で360分なので、明示的に延ばさないとセルフホストでも6時間で打ち切られます。24時間を超えるジョブでは、ジョブ内の GITHUB_TOKEN の有効期限が先に切れる点も公式が注意しています。hosted版とセルフホストの使い分けを含めたCI基盤の設計は、DevOps・CI/CD導入支援でも相談を受けています。
逆に、パブリックリポジトリのCI、月の実行時間が無料枠に収まる小規模チーム、ランナーのOS更新を担当する人がいない組織では採用しません。必要なハードウェアや社内接続をhosted版で満たせるなら、無料枠内の処理を移しても料金面の利点はありません。OS更新の担当者を確保できない場合は、保守責任を果たせないため採用を見送ります。軽い処理だけなら1コアの ubuntu-slim(1分0.002ドル)という選択肢もあり、条件はubuntu-slimの仕様と使えない条件で解説しています。
セルフホストランナーの料金:無料の現状と延期された0.002ドル課金
GitHubの課金ドキュメントは、2026年10月時点で「GitHub Actionsの利用は self-hosted runner では無料」と明記しています。ランナーを動かすサーバー代、クラウドのインスタンス代、ストレージ代は当然ながら利用者持ちです。
ただし、無料が恒久的に保証されているわけではありません。GitHubは2025年12月16日のChangelogで、プライベートリポジトリのジョブに1分0.002ドルの「GitHub Actions cloud platform charge」を導入し、セルフホストランナーには2026年3月1日から適用すると発表しました。同時に hosted 版の単価をマシン種別に応じて最大39%下げる内容でした。
この課金は利用者の反発を受けて発表直後に延期され、GitHubの告知ページは冒頭で「We’re postponing the announced billing change for self-hosted GitHub Actions to take time to re-evaluate our approach」と延期を明記しています。hosted版の値下げ(Linux 2コア 0.006ドル/分)は2026年1月から実施済みで、セルフホスト側の課金だけが保留された状態です。
コスト試算では、この課金が将来復活した場合も想定しておくのが安全です。無料枠を考慮せず、10万分すべてに0.002ドル/分が適用されると仮定した場合、追加額は200ドルです。セルフホストに移す理由が料金だけなら、この上乗せ分を差し引いても hosted 版より安いかを確認してから判断してください。
動作要件:対応OS・CPUアーキテクチャと通信先
対応OSとアーキテクチャ(公式サポート一覧)
| OS | サポート対象 | アーキテクチャ |
|---|---|---|
| Linux | Ubuntu 20.04以降、Debian 10以降、RHEL 8以降など | x64 / ARM64(ARM32はサポート終了) |
| Windows | Windows 10・11(64bit)、Windows Server 2016〜2022 | x64(ARM64はプレビュー) |
| macOS | macOS(13.4以前はサポート終了) | x64 / ARM64 |
公式の対応一覧には macOS 11.0以降と ARM32 が残っていますが、2026年9月23日のChangelogで、Node 20の提供終了に伴い macOS 13.4以前と ARM32 のセルフホストランナーはサポート対象外と告知されました。古いMacやRaspberry Piの32bit OSを再利用する計画は、この時点で選択肢から外れます。続く v2.338.0(2026-10-06)では、ランナー自身が内部で使うNode(hashFiles()・run.sh --check・サービスのラッパー runsvc.sh)もNode 24に切り替わりました。ランナーの .env に ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION=node20 を書くと一時的に戻せますが、リリースノートによると戻るのは hashFiles() と --check だけです。
ランナーアプリケーション自体の消費リソースはわずかで、CPUやメモリは実行するジョブに合わせて決めます。制約として効くのはコンテナです。Dockerコンテナアクションやサービスコンテナ(services:)を使うワークフローは Linux のランナーでしか動かず、Dockerのインストールも必要です。WindowsやmacOSのランナーで container: を指定しても実行できません。
通信要件:アウトバウンド443番ポートと許可するドメイン
ランナーはGitHubへ自分から接続してジョブを取りに行く方式(ロングポーリング)なので、受信ポートを開ける必要はありません。必要なのは、443番ポートへのアウトバウンドHTTPS通信と、上り下りとも70kbps以上の回線です。ファイアウォールで宛先を絞る場合、公式ドキュメントが用途別に挙げるドメインのうち、最低限次を許可します。
# 基本動作(ジョブの受信・APIアクセス)
github.com
api.github.com
*.actions.githubusercontent.com
# アクションのダウンロード
codeload.github.com
# ログ・アーティファクト・キャッシュの送受信
results-receiver.actions.githubusercontent.com
*.blob.core.windows.net
# ランナー自身の自動更新
objects.githubusercontent.com
objects-origin.githubusercontent.com
github-releases.githubusercontent.com
github-registry-files.githubusercontent.com
# リリースアセットのダウンロード
release-assets.githubusercontent.com
GitHub Packages・ghcr.io・Git LFS・Dependabotのジョブを使う場合は、それぞれ追加のドメインが要ります。Organizationで IP許可リストを有効にしているなら、ランナーの送信元IPもそこへ登録しないと接続できません。プロキシ環境では https_proxy と no_proxy 環境変数をランナーの .env ファイルに書いておくと、サービス起動時にも読み込まれます。
Linuxでの導入手順:ダウンロードから登録・サービス化まで
登録画面の開き方と登録トークンの有効期限
リポジトリ単位で登録する場合は、リポジトリの Settings → Actions → Runners → New self-hosted runner を開きます。Organization単位なら組織の Settings から同じ画面へ進みます。個人所有リポジトリへの登録には所有者権限が必要です。組織所有リポジトリでは組織オーナーまたはリポジトリ管理者が登録できます。Enterprise Cloudでは「Manage organization runners and runner groups」権限でも登録でき、Organizationへの登録も組織オーナーまたはこの権限の保有者が行えます。
画面でOSとアーキテクチャを選ぶと、ダウンロードから登録までのコマンドがトークン入りで表示されます。このトークンは1時間で失効するので、画面を開いたまま翌日に作業すると登録で失敗します。その場合は画面を開き直して新しいトークンを取得してください。
runner v2.338.0 のダウンロードとconfig.shによる登録
Linux x64 で v2.338.0 を入れる場合のコマンドは次のとおりです。ランナーは段階的に配布されるため、作業時には登録画面に表示される対象版も確認してください。ハッシュ値はリリースノートに掲載された SHA-256 で、ダウンロードしたファイルの改ざんを確認します。OWNER/REPO と登録トークンは自分の値に置き換えます。
mkdir actions-runner && cd actions-runner
curl -O -L https://github.com/actions/runner/releases/download/v2.338.0/actions-runner-linux-x64-2.338.0.tar.gz
echo "af4b794c1bc41d73d40535e3fe092a39f9679cd8d965954c2aca25a05ca41d32 actions-runner-linux-x64-2.338.0.tar.gz" | shasum -a 256 -c || exit 1
tar xzf ./actions-runner-linux-x64-2.338.0.tar.gz
./config.sh --url https://github.com/OWNER/REPO --token 登録トークン
./run.sh
config.sh は対話式でランナー名・ラベル・作業ディレクトリを聞いてきます。run.sh を実行して「Listening for Jobs」と表示され、GitHubの Runners 一覧でステータスが Idle になれば登録完了です。自動化するときは対話を止めるオプションを付けます。v2.338.0 のヘルプ文で確認できる主なオプションは次のとおりです。
| オプション | 用途 |
|---|---|
--unattended |
対話プロンプトを出さず既定値で進める |
--name |
ランナー名(既定はホスト名) |
--labels |
カスタムラベルをカンマ区切りで追加 |
--no-default-labels |
self-hosted・OS・アーキテクチャの既定ラベルを付けない |
--runnergroup |
登録先のランナーグループ |
--work |
作業ディレクトリ(既定は _work) |
--replace |
同名の既存ランナーを置き換える |
--ephemeral |
1ジョブ実行後に登録を自動解除 |
--disableupdate |
ランナーの自動更新を止める |
ランナーを rootで動かすと、ジョブのスクリプトもroot権限で走ります。専用の一般ユーザーを作り、その権限で config.sh を実行してください(root で実行するとスクリプトが停止する仕様です)。
svc.shでのサービス化と自動起動
run.sh はターミナルを閉じると止まるので、常用するならサービスとして登録します。systemd のLinuxでは、登録後にランナーのディレクトリに生成される svc.sh を使います。
sudo ./svc.sh install # 引数でサービスの実行ユーザーを指定できる
sudo ./svc.sh start
sudo ./svc.sh status
journalctl -u actions.runner.OWNER-REPO.ランナー名.service -f
サービス名は actions.runner.<組織>-<リポジトリ>.<ランナー名>.service の形式で、80文字を超えると切り詰められます。正確な名前はランナーのディレクトリにある .service ファイルで確認できます。
WindowsとmacOSでの手順の違い
Windowsでは、サービスとして動かすかどうかを config.cmd の対話中に聞かれます。後からサービス化する手段は無く、一度登録を外して設定し直す必要があります。サービス化するなら管理者権限のPowerShellで作業し、配置先は C:\actions-runner のようにドライブ直下にします。サービスアカウントからのアクセス権と、長いパスの制限による失敗を避けるためで、リリースノートも同じ場所を推奨しています。
macOSはLinuxとほぼ同じ手順ですが、svc.sh install を sudo なしで実行し、LaunchAgentとして登録されます。Apple Silicon なら osx-arm64 のパッケージを選びます。
runs-onでセルフホストランナーを指定する書き方
ワークフロー側では runs-on にラベルを配列で書きます。ランナーには登録時に self-hosted、OSを表す linux・windows・macOS、アーキテクチャを表す x64・ARM・ARM64 の3種類が自動で付きます。
jobs:
build:
runs-on: [self-hosted, linux, x64]
steps:
- uses: actions/checkout@v7
- run: make build
train:
runs-on: [self-hosted, linux, x64, gpu] # gpuは登録時に付けたカスタムラベル
steps:
- uses: actions/checkout@v7
- run: python train.py
配列のラベルはAND条件です。すべてを持つランナーだけが候補になり、1つでも欠けると該当ランナーが無い扱いになります。公式ドキュメントは配列の先頭を self-hosted にするよう求めています。GitHub-hosted runner と取り違えないための目印でもあります。
Organizationでランナーを共有しているなら、ラベルの代わりにランナーグループ名で指定することもできます。
jobs:
deploy:
runs-on:
group: build-runners
labels: [self-hosted, linux]
steps:
- run: echo "Runner selection succeeded"
ランナーグループは、どのリポジトリ・ワークフローにどのランナーを使わせるかを決める境界で、OrganizationとEnterpriseで作成します。1グループに登録できるランナーは最大10,000台です。ARCで作ったランナーには self-hosted ラベルが付かないので、runs-on には、この導入例ではHelmのインストール名を書きます(後述)。ARC 0.14.0以降はスケールセットに設定した複数ラベルによる指定も可能です。
運用で踏みやすい期限と上限:30日更新ルールと14日自動削除
ランナーの更新や停止期間には、ジョブの受付停止や登録削除につながる期限があります。放置すると「ある日突然ジョブが流れなくなる」形で表に出ます。公式ドキュメントの値を一覧にしました。
| 項目 | 値 | 超えたときの挙動 |
|---|---|---|
| 登録に必要な最低版 | v2.329.0以上 | 登録・再登録できない |
| ランナーの更新期限 | 新版公開から30日 | ジョブが割り当てられなくなる |
| 未接続による自動削除 | 14日(ephemeralは1日) | GitHubから登録が消える |
| ジョブのキュー待ち | 24時間 | ジョブが失敗する |
| ジョブの実行時間 | 最大5日(既定タイムアウトは360分) | 有効な制限時間で終了 |
| 割り当て後の受け取り待ち | 60秒 | 別のランナーへ再キュー |
| ランナー登録の頻度(登録先単位) | 5分あたり1,500台 | 登録が拒否される |
自動更新を止めた場合の30日ルール
ランナーは既定で自動更新されます。新版が出ると、ジョブが割り当てられたタイミングで、またはジョブが無くても公開から1週間以内に自分を更新します。問題になるのは --disableupdate を付けた場合と、更新用ドメインをファイアウォールで塞いでいる場合です。
公式の警告は、メジャー・マイナー・パッチを問わず新版が出てから30日以内に更新しなければ、そのランナーにジョブをキューしないと定めています。重大なセキュリティ更新の場合は30日を待たずに止まります。コンテナイメージにランナーを焼き込んで自動更新を切る構成では、actions/runner のリリースを通知登録し、新版公開から30日以内にイメージの再作成と稼働ランナーへの反映を完了し、重大なセキュリティ更新には直ちに対応してください。
この30日ルールは以前から存在しましたが、徹底されていない場合がありました。GitHubは2026年6月12日のChangelogで施行の再開を告知しました。GitHub Enterprise Cloudの全面施行は当初9月25日とされていましたが、2026年9月28日のChangelogで9月29日に移り、その日から始まっています(データレジデンシー版は7月31日から施行済み、GitHub Enterprise Serverは対象外)。施行後は、v2.329.0未満のランナーが登録・再登録できず、v2.329.0以上でも更新が30日遅れたランナーはジョブを受け取れません。v2.329.0はあくまで登録の最低版で、ジョブ実行に必要な版は新版が出るたびに上がっていきます。
手元の版がいつまで使えるかは、2026年9月に追加されたREST API GET /actions/runners/deprecations/{version} で確認できます。リポジトリ・Organization・Enterpriseの各階層で呼べ、応答の registration_deprecates_at が登録できなくなる日、runtime_deprecates_at がジョブを実行できなくなる日です。自動更新を止めている環境では、この日付を監視してイメージの作り直しを予定に組み込みます。
14日で登録が消える仕様と再登録の手間
14日以上GitHubに接続していないランナーは、GitHub側の登録が自動で削除されます。ephemeralランナーは1日です。長期休暇中にマシンを止めていた、検証用に一時停止していた、といった理由で登録が消えると、マシンを起動してもOfflineのまま戻りません。その場合はランナーのディレクトリにある .runner ファイルを消すと、再ダウンロードせずに config.sh からやり直せます。
常駐ランナーの後片付け:同時1ジョブ・_workの肥大化・ジョブ前後スクリプト
ランナーアプリケーション単位の同時実行数と並列化
公式ドキュメントは「各ランナーが同時に実行できるジョブは1つ」としています。マシンのCPUが16コアあっても、登録したランナーが1台なら、ジョブは1本ずつ順番に処理されます。同じマシンで並列に流したいときは、ランナーごとに別のディレクトリへパッケージを展開し、重複しない名前で config.sh を実行して台数を増やします。登録情報はディレクトリ内の .runner ファイルに入るので、1ディレクトリが1台に対応します。並列数を増やすほどメモリとディスクの取り合いになるため、ジョブ1本あたりの消費量を見てから台数を決めます。
セルフホスト環境の事前インストールと不足ツールへの対応
GitHub-hosted runner のイメージには言語ランタイムやビルドツールが最初から入っていますが、セルフホストランナーに入っているのはランナーアプリケーションだけです。hosted版で動いていたワークフローを runs-on だけ書き換えて移すと、git・Docker・Node.js などが無くて失敗します。言語ランタイムは actions/setup-node などのセットアップ用アクションで入れるか、マシンに事前に入れておきます。actions/checkout は、PATHにGit 2.18以上が無いとREST APIでファイルだけを取得するため(入力と既定値はactions/checkoutの解説を参照)、.git の無い作業ディレクトリになります。gitコマンドを使うワークフローでは、先にgitを入れておきます。Dockerを使うためにランナーのユーザーを docker グループに入れる場合、Dockerのドキュメントが書くとおり、このグループはroot相当の権限を与えます。
ジョブ前後スクリプトによる作業ディレクトリの清掃
常駐ランナーでは、チェックアウトしたリポジトリやビルド成果物が作業ディレクトリ(既定は _work)にジョブ終了後も残ります。毎回まっさらな環境で始まる hosted 版と違い、放置するとディスクを使い切ってジョブが失敗します。ランナーには、ジョブの直前と直後に任意のスクリプトを実行する仕組みがあり、環境変数にスクリプトの絶対パスを入れると動きます。
# actions-runner/.env(変更後はランナーの再起動が必要)
ACTIONS_RUNNER_HOOK_JOB_STARTED=/opt/runner-hooks/cleanup.sh
ACTIONS_RUNNER_HOOK_JOB_COMPLETED=/opt/runner-hooks/cleanup.sh
#!/bin/bash
# /opt/runner-hooks/cleanup.sh(chmod +x で実行権限を付ける)
# 前のジョブが残したワークスペースの中身を消す(GITHUB_WORKSPACE が空なら :? で止まり、/ 以下を消さない)
rm -rf "${GITHUB_WORKSPACE:?}"/* "${GITHUB_WORKSPACE:?}"/.[!.]* "${GITHUB_WORKSPACE:?}"/..?* || exit 1
# 専用Dockerデーモンでのみ実行する。共有環境ではこのコマンドを省く
# このジョブに限らず、デーモン全体の未使用資源(ネットワークも含む)が削除対象になる
docker system prune -af --filter "until=168h" >/dev/null 2>&1 || true
公式ドキュメントが定める動きは次のとおりです。ACTIONS_RUNNER_HOOK_JOB_STARTED はジョブが割り当てられてから実行前に、ACTIONS_RUNNER_HOOK_JOB_COMPLETED は全ステップの実行後に走ります。スクリプトは actions-runner のディレクトリの外に置き、ランナーのサービスアカウントの権限で実行されます。開始前スクリプトが0以外で終わるとジョブは実行されず失敗扱いになり、continue-on-error は効きません。スクリプトにはタイムアウトが無く、終わるまでジョブを止めるので、時間がかかる処理には自分で上限を付けます。実行結果はジョブログの「Set up runner」「Complete runner」に出ます。終了時スクリプトはジョブ完了の前に実行されるため、オートスケールでマシン自体を消す処理には使えません。
セキュリティ:パブリックリポジトリで使わない理由とephemeral運用
フォークからのプルリクエストで任意のコードが走る危険
公式ドキュメントは「self-hosted runner はプライベートリポジトリでのみ使うことを推奨する」と明記しています。理由は、パブリックリポジトリをフォークした第三者が、ワークフローでコードを実行するプルリクエストを出すだけで、そのコードがあなたのランナー上で動きうるからです。
hosted版なら実行後に仮想マシンごと捨てられますが、常駐型のセルフホストランナーは次のジョブまで状態が残ります。仕込まれたプロセスが常駐し、後続ジョブのシークレットやソースを盗む足場になりえます。ランナーが社内ネットワークにあれば、被害はランナーの外に広がります。この危険があるため、ランナーグループに入れたランナーは既定でパブリックリポジトリから使えない設定になっています。パブリックリポジトリでどうしてもセルフホストが必要なら、次のephemeral構成を前提にしてください。
ephemeral・JITランナーの単一ジョブ実行と環境破棄
config.sh に --ephemeral を付けて登録したランナーは、1ジョブを処理すると GitHub側で自動的に登録解除されます。GitHubが保証するのは、登録したephemeralランナーへのジョブ割り当てが1回だけであることです。登録解除だけではファイルやプロセスは消えないので、同じマシンを使い回すなら、登録解除後にマシンやコンテナを消去・再作成する処理を自分で自動化します。
./config.sh --url https://github.com/OWNER --token 登録トークン --ephemeral --unattended
REST API の generate-jitconfig エンドポイントで発行した設定を run.sh --jitconfig に渡すと、config.sh を通さずに just-in-time(JIT)ランナーを起動できます。JITランナーも1ジョブしか実行せず、ジョブを受け取らなかった場合は自動で削除されます。ephemeral運用ではランナーごとにログが消えるので、公式は本番導入の前に _diag のログを外部のログ基盤へ転送しておくよう警告しています。
オートスケール構成:ARC・Scale Set Client・webhookの選び分け
ランナーを常駐で数台並べる構成は、ピーク時に足りず閑散時に余ります。公式が挙げるオートスケールの方式は3つで、いずれも ephemeral ランナーの利用を前提としています。常駐ランナーを増減させる方式は、停止中のランナーにジョブが割り当てられる可能性を排除できないため非推奨です。
ARC(Actions Runner Controller)によるKubernetes上のランナー自動増減
Kubernetesクラスタを運用しているなら、GitHubの推奨は ARC です。ジョブが来るとリスナーPodが検知してランナーPodを作り、ジョブが終わると消します。最新のHelmチャートは gha-runner-scale-set 0.15.0(2026-10-01)で、パッチ版のアップグレードではリソースを作り直さずその場で更新するようになりました。導入はコントローラーとランナースケールセットの2回の helm install で済みます。
helm install arc \
--namespace arc-systems --create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
helm install arc-runner-set \
--namespace arc-runners --create-namespace \
--set githubConfigUrl="https://github.com/OWNER/REPO" \
--set githubConfigSecret.github_token="PAT" \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
ワークフローでは runs-on: arc-runner-set のように、2つ目のインストール名をそのまま書きます。ARCからGitHub APIへの認証は、PAT(classic)のほかOrganization所有のGitHub Appでも行えます。ただしEnterprise単位のランナーはGitHub Appで認証できず、PATに限られます。
Kubernetesが無い場合のScale Set Clientとwebhook
VMやオンプレミスのマシンで自動化したい場合は、GitHubが公開しているGo製のモジュール actions/scaleset(Runner Scale Set Client)を使います。ARCと同じスケールセットAPIを話し、マシンの作成と破棄だけを自分で実装する形で、Windows・Linux・macOSに対応します。
もう1つは workflow_job webhook の queued・completed を受けて自前でランナーを増減させる方式です。仕組みは単純ですが、webhookの配信遅延がそのままスケールの遅れになるため、公式は大量のジョブを捌く場合にARCかScale Set Clientを勧めています。
AWS CodeBuild・Cloud Runにランナーを任せる構成
自前のマシンもKubernetesも持ちたくない場合は、クラウドのビルド基盤にランナーの起動を任せる方法があります。GitHubから見ればセルフホストランナーなので、GitHub Actions側の利用料はかからず、計算資源の料金はクラウド側に発生します。
AWS CodeBuild は、プロジェクトの種類で「Runner project」を選ぶとGitHubにwebhookを作り、WORKFLOW_JOB_QUEUED イベントを受けるたびにephemeralランナーを1つ起動して、ジョブが終わると即座に破棄します。ワークフローでは runs-on にプロジェクト名と実行IDを含むラベルを書きます。
jobs:
build:
runs-on:
- codebuild-myProject-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- run: echo "Hello World!"
ラベルのプロジェクト名がCodeBuildのプロジェクト名と一致しないとwebhookが処理されず、ジョブは待ち続けます。image: や instance-size: を続けて書けば、ジョブごとにイメージやインスタンスサイズを上書きできます。Google Cloudでは、Cloud Run ワーカープールのチュートリアルが、Cloud Run上にデプロイしたCREMA(Cloud Run External Metrics Autoscaling)で、ジョブの状態に応じてワーカープールのインスタンス数を増減させる構成を公開しています。どちらもランナーのイメージやクラウドの権限設定は利用者側で管理します。
トラブルシューティング:Offline・Queuedのまま進まない時の確認順
ランナーのステータスは Runners 一覧で Idle(待機中)・Active(ジョブ実行中)・Offline(未接続)の3つで表示されます。症状ごとに確認する順番は次のとおりです。
- Offlineのまま:まずランナーのプロセスかサービスが動いているかを
svc.sh statusで見ます。動いているのにOfflineなら、次に通信状態を切り分けるため、./run.sh --check --url https://github.com/OWNER/REPO --pat トークンを実行します。必要な接続先を1つずつ試して PASS・FAIL を表示します。 - ジョブがQueuedのまま:
runs-onのラベルをすべて持つランナーが存在するかを確認します。ラベルの綴り間違いやカスタムラベルの付け忘れを確認します。ラベルは大文字小文字を区別しません。該当ランナーが無くても即座には失敗せず、24時間キューに残ってから失敗します。 - 以前は動いていたのに急に来なくなった:自動更新を止めていないか、未適用の新版が公開されてから30日を過ぎていないかを確認します。手元の版の期限は前述の
deprecationsAPIで分かります。14日以上止めていたなら登録自体が消えています。ディスクの空きが無くなってジョブが失敗している場合もあるので、_workの容量も見ます。 - 登録で失敗する:トークンの1時間の期限切れ、同名ランナーの重複、v2.329.0未満の古いパッケージを使っていないかを確認します。同名ランナーを意図的に置き換える場合は
--replaceを指定できます。
詳しい原因はランナーのディレクトリの _diag フォルダにあります。Runner_ で始まるファイルがランナーアプリケーション本体の起動ごとのログ、Worker_ で始まるファイルがジョブごとの実行ログです。社内の証明書でTLS検査を挟んでいる環境では、証明書エラーがここに出ます。
よくある質問
セルフホストランナーとセルフホステッドランナーは違うものですか?
同じものです。英語の self-hosted runner をどう訳すかの違いで、GitHubの日本語ドキュメントは「セルフホステッド ランナー」と表記しています。対になるのが、GitHubが仮想マシンを用意する GitHub-hosted runner(GitHubホステッドランナー)です。検索や社内資料で表記が混在していても、指しているのは自分のマシンでジョブを動かす同じ仕組みです。
セルフホストランナーに料金はかかりますか?
2026年10月時点では、GitHub Actions側の利用料はかかりません。GitHubは2026年3月1日からプライベートリポジトリで1分0.002ドルを課金すると発表しましたが、2025年12月に延期しており、再開日は発表されていません。ランナーを動かすサーバーやクラウドの費用は利用者の負担です。GitHub Enterprise Server 上のセルフホストランナーは、発表時点から課金対象外とされていました。
WindowsやmacOSでもセルフホストランナーは使えますか?
使えます。Windows 10・11(64bit)とWindows Server 2016〜2022が公式のサポート対象です。macOSはApple Silicon(ARM64)にも対応していますが、2026年9月23日にランナーのJavaScript実行環境がNode 24へ切り替わり、Node 24が動かないmacOS 13.4以前はサポート対象外になりました。ただし、Dockerコンテナアクションとサービスコンテナが動くのはLinuxのランナーだけです。Windowsでサービスとして動かすかどうかは登録時に決める必要があり、後から変える場合は登録し直します。
パブリックリポジトリでセルフホストランナーを使っても大丈夫ですか?
常駐型のランナーでは使わないでください。公式ドキュメントはプライベートリポジトリでの利用のみを推奨しています。フォークからのプルリクエスト経由で第三者のコードがランナー上で実行され、次のジョブや社内ネットワークに影響しうるためです。例外的に使う場合は、1ジョブごとに環境を破棄するephemeralランナーと実行承認を組み合わせ、実行中のコードが社内ネットワークや不要な認証情報へ到達できないよう隔離します。
ジョブが「Waiting for a runner to pick up this job」のまま進まないのはなぜですか?
runs-on に書いたラベルやグループ条件を満たすランナーが、まだジョブを受け取れていない状態です。オンラインでも他のジョブを実行中なら待機が発生します。ラベルの綴り、ランナーがOfflineになっていないか、ランナーグループの利用許可にそのリポジトリが含まれているかを順に確認します。一致するランナーが現れないままだと、ジョブは24時間キューに残った後に失敗します。