自宅Proxmox上のUbuntu ServerをGitHub ActionsのSelf-hosted Runnerにする【Dockerビルド・E2Eテストまで】
はじめに
自宅のProxmox VEで動かしているUbuntu Serverを、GitHub Actionsの**Self-hosted Runner(セルフホステッドランナー)**にしてみます。
この記事では、Runnerの登録・常駐化から、GitHub Actionsでの動作確認、Dockerイメージのビルド、PlaywrightによるE2Eテストまでを紹介します。
AIAgentの登場により、コードをみないで開発することが増えました。それによりE2Eテストをする重要性はましており、GithubActionsでは課金が高額になる。そういった場合に余っているPC端末が使えるかもしれません。
対象: 自分で管理しているプライベートリポジトリで、信頼できるコードのみを実行する開発・検証用途。実行されるWorkflowはUbuntuサーバー上でコマンドを動かせるため、セキュリティには注意してください。
※ この記事は2026年10月28日時点の公式ドキュメントに基づきます。Runnerのバージョンや画面表示は更新されるため、ダウンロード・登録コマンドはGitHubが表示する最新版を使用してください。
Self-hosted Runnerとは?
GitHub Actionsのジョブを、GitHubが用意したVM(GitHub-hosted Runner)ではなく、自分で管理するマシンで実行する仕組みです。
GitHub Repository
└─ Push / 手動実行
└─ GitHub Actions
└─ HTTPS(Ubuntu → GitHub、外向き443)
└─ 自宅 Proxmox VE
└─ Ubuntu Server VM
└─ Self-hosted Runner
├─ Docker Build
├─ Unit Test
└─ Playwright E2E Test
Runner側からGitHubに接続するため、通常、Runnerのためにルーターのポート開放は不要です。ただしUbuntuからGitHub関連サービスへ、外向きTCP 443番で通信できる必要があります。
自宅Runnerを使うメリット
- 既存の計算資源を活用できる: Proxmoxで常時稼働しているVMをCIに使える。
- 環境をカスタマイズできる: CPU・メモリ・ストレージやDocker、テストツールを自由に用意できる。
- ローカルキャッシュを活用できる: 永続型RunnerならDockerイメージ・ビルドキャッシュを保持でき、条件次第で高速化できる。
- 宅内の検証環境と連携できる: 必要な範囲だけネットワーク接続を許可すれば、検証用DBやサービスとのテストも可能。
- GitHub ActionsのSelf-hosted Runner実行時間自体は無料: ただし電気代、ストレージ、保守などは自己負担。
デメリット・注意点
GitHub-hosted Runnerと違い、OS更新・ディスク容量・ジョブの隔離・Runnerの稼働管理は自分の責任です。またRunnerがオフラインの場合はジョブが待機します。必ずしもGitHub-hostedより高速・安価になるわけではありません。
想定環境
| 項目 | 内容 |
|---|---|
| 仮想化基盤 | Proxmox VE |
| ゲストOS | Ubuntu Server 24.04 LTS(22.04 LTSでも概ね同様) |
| CPU / メモリ | 例:2〜4 vCPU / 4〜8GB(推奨の目安であり必須条件ではない) |
| GitHub | 管理権限のあるプライベートリポジトリ |
| Runner | Linux x64、リポジトリ単位で登録 |
| Ubuntuへのアクセス |
sudo可能な管理ユーザーでSSH接続できる |
今回は既存のUbuntu VMを使用します。重要な本番サービスやNAS・Proxmox管理系へアクセスできるVMなら、Runner専用VMを別に作ることを推奨します。
1. Ubuntuの事前準備
まずUbuntuにSSH接続し、OSとアーキテクチャを確認します。
cat /etc/os-release
uname -m
uname -m が x86_64 の場合、GitHubでは Linux / x64 を選びます。aarch64 の場合は ARM64 を選んでください。
必要な基本ツールを導入します。
sudo apt update
sudo apt install -y curl ca-certificates git tar gzip
Runnerをrootで動かさないため、専用ユーザーを作成します。
sudo adduser --disabled-password --gecos "" gha-runner
sudo -iu gha-runner
mkdir -p ~/actions-runner
cd ~/actions-runner
以降、Runnerのダウンロード・登録までは gha-runner ユーザーで作業します。
2. GitHubからRunnerを登録する
対象のGitHubリポジトリを開き、次の順番で進みます。
- Settings を開く
- 左メニューの Actions → Runners を選択
- New self-hosted runner を押す
- Linux / x64 を選ぶ
画面に「Download」「Configure」などのコマンドが表示されます。
Runnerアプリをダウンロードする
Ubuntuの ~/actions-runner ディレクトリで、GitHub画面に表示されるダウンロード・SHA-256検証・展開のコマンドをそのまま実行します。
# ここでGitHubの「Download」に表示されるコマンドを実行
# 1. curl でRunnerアーカイブをダウンロード
# 2. sha256sum で検証
# 3. tar で展開
Runnerのリリース番号・ダウンロードURL・SHA-256値は変わるため、この記事では固定しません。
GitHubにRunnerを登録する
続いて、GitHub画面の「Configure」に表示される ./config.sh コマンドを実行します。
# 以下は書式の例。OWNER / REPO / TOKEN は自分の値に置き換える
./config.sh \
--url https://github.com/OWNER/REPO \
--token YOUR_REGISTRATION_TOKEN \
--name home-ubuntu-runner \
--labels homelab
-
--name:GitHubに表示するRunner名 -
--labels homelab:WorkflowからこのRunnerを指定するためのカスタムラベル -
--token:登録用の期限付きトークン(1時間で失効)。GitHubが表示するものを使う
登録トークンはQiitaの記事・スクリーンショット・実行ログに掲載しないでください。 コマンド履歴への記録も避けたい場合は、./config.sh の対話入力を利用してください。
接続を確認する
一度フォアグラウンドで起動します。
./run.sh
Connected to GitHub や Listening for Jobs が表示されれば接続成功です。GitHubの Settings → Actions → Runners にもRunnerが表示されます。
常駐化するため、Ctrl+C で停止してから exit で管理ユーザーに戻ります。
# Ctrl+C で ./run.sh を停止してから実行
exit
3. systemdで自動起動する
以下はsudo権限のある元の管理ユーザーで実行します。
cd /home/gha-runner/actions-runner
sudo ./svc.sh install gha-runner
sudo ./svc.sh start
sudo ./svc.sh status
これでUbuntu起動時にRunnerサービスも起動するようになります。
トラブル時にログを確認するには、インストールディレクトリにある .service ファイルでサービス名を調べます。
cat /home/gha-runner/actions-runner/.service
sudo journalctl -u "$(cat /home/gha-runner/actions-runner/.service)" -n 100 --no-pager
4. GitHub Actionsから動作確認する
リポジトリに .github/workflows/home-runner-test.yml を作成します。
name: Home Runner Test
on:
workflow_dispatch:
permissions:
contents: read
jobs:
test:
runs-on: [self-hosted, linux, x64, homelab]
timeout-minutes: 10
steps:
- name: Show Ubuntu server information
run: |
echo "Hello from my Proxmox VM!"
hostname
uname -a
free -h
df -h .
GitHubの Actions → Home Runner Test → Run workflow から手動実行します。実行ログに自宅Ubuntuのホスト名やメモリ情報が表示されれば成功です。
runs-on の各ラベルはすべて一致する必要があります。ジョブが Queued のままなら、Runnerが Idle か、指定したラベルが正しいかを確認してください。
5. Dockerビルドを動かす
Dockerビルドを行うには、Ubuntu側にDocker EngineとBuildx、Docker Composeプラグインが必要です。既にDockerを利用しているVMでは、既存環境を壊さないよう、まずインストール状況を確認してください。
docker --version
docker compose version
sudo systemctl status docker --no-pager
未導入の場合は、Docker公式のUbuntu向けインストール手順に従い、公式APTリポジトリから docker-ce、docker-ce-cli、containerd.io、docker-buildx-plugin、docker-compose-plugin を導入します。
RunnerユーザーにDockerの操作権限を与える例は次のとおりです。
sudo usermod -aG docker gha-runner
cd /home/gha-runner/actions-runner
sudo ./svc.sh stop
sudo ./svc.sh start
sudo -u gha-runner -H docker version
セキュリティ上の重要事項: Docker公式によると、
dockerグループへの所属は実質的にroot相当の権限を与えます。既存の重要なサービスとDockerデーモンを共有する構成は避け、Runner専用VMで利用することを強く推奨します。
リポジトリのルートに Dockerfile があるなら、次のWorkflowでビルドできます。
.github/workflows/docker-build.yml
name: Docker Build
on:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: [self-hosted, linux, x64, homelab]
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- name: Build image
run: docker build -t "my-app:ci-${GITHUB_RUN_ID}" .
- name: Remove test image
if: always()
run: docker image rm "my-app:ci-${GITHUB_RUN_ID}" || true
actions/checkout でリポジトリを取得し、自宅Ubuntu上のDockerでビルドします。キャッシュが残ることはありますが、毎回必ず高速になるわけではありません。
6. PlaywrightでE2Eテストを動かす(応用)
次は、Docker Composeで検証用Webアプリを起動し、Playwright公式DockerイメージからE2Eテストを実行する例です。UbuntuホストにブラウザやNode.jsを直接インストールしなくても構成できます。
前提: リポジトリにアプリ用Dockerfile、package.json、package-lock.json、Playwrightのテストがあり、アプリはコンテナ内の 0.0.0.0:3000 で待ち受けるものとします。実際のアプリに合わせてポートやヘルスチェックURLを変更してください。
CI専用のComposeファイル
compose.ci.yml
services:
app:
build: .
ports:
- "127.0.0.1:3000:3000"
ホスト側を 127.0.0.1 に限定しているため、アプリをLAN全体に公開せずにテストできます。既存の本番用Composeファイルをそのまま使用しないようにしましょう。
Playwrightのテスト例(tests/home.spec.ts):
import { test, expect } from '@playwright/test';
test('トップページが表示される', async ({ page }) => {
const response = await page.goto('http://127.0.0.1:3000/');
expect(response?.ok()).toBeTruthy();
});
ここでは例としてPlaywright v1.64.1 の公式Dockerイメージを使用します。プロジェクトの@playwright/testのバージョンとDockerイメージのバージョンを必ず合わせてください。
.github/workflows/e2e.yml
name: Playwright E2E
on:
workflow_dispatch:
permissions:
contents: read
jobs:
e2e:
runs-on: [self-hosted, linux, x64, homelab]
timeout-minutes: 45
env:
COMPOSE_PROJECT_NAME: ci-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- uses: actions/checkout@v7
- name: Start test application
run: docker compose -f compose.ci.yml up -d --build
- name: Wait for application
run: |
curl --fail --silent --show-error \
--retry 30 --retry-connrefused --retry-delay 2 \
http://127.0.0.1:3000/
- name: Run Playwright E2E in Docker
run: |
docker run --rm --init --shm-size=1g \
--network host \
-e CI=1 \
-v "$GITHUB_WORKSPACE:/src:ro" \
-w /work \
mcr.microsoft.com/playwright:v1.64.1-noble \
bash -lc 'cp -a /src/. /work/ && npm ci && npx playwright test'
- name: Cleanup
if: always()
run: docker compose -f compose.ci.yml down -v --remove-orphans
-
docker compose up -d --build:アプリのビルドと起動 -
curl --retry:アプリがHTTP応答できるまで確認 -
docker run ... --network host:Linuxホスト上の127.0.0.1:3000にPlaywrightからアクセス -
-v "$GITHUB_WORKSPACE:/src:ro":ソースを読み取り専用で渡し、コンテナ内でコピーしてテストすることで、ホスト側にroot所有ファイルを残しにくくする -
if: always():テスト失敗時もComposeを停止・削除
この例は信頼できるテストコード・アプリのみを対象にします。また同じUbuntu上で他のサービスが3000番ポートを使っている場合は衝突するため、ポートを変更してください。
7. よくあるトラブル
| 現象 | 確認すること |
|---|---|
GitHubでRunnerがOffline
|
VMの起動状態、sudo ./svc.sh status、外向きHTTPS 443、Runnerログ |
Queuedから進まない |
runs-onのラベル、RunnerがIdleか、対象リポジトリへの登録状況 |
config.shで登録できない |
登録トークンの有効期限、リポジトリURL、管理権限 |
docker.sock: permission denied |
gha-runnerのDocker権限、サービス再起動 |
| Playwrightでブラウザが起動しない | プロジェクトと公式DockerイメージのPlaywrightバージョン一致、メモリ不足 |
| E2Eの接続エラー | アプリの待受アドレス、ポート、起動完了、compose.ci.yml
|
| ディスク不足 | Dockerイメージ、ビルドキャッシュ、_workの蓄積 |
Dockerの使用量は docker system df、Runnerのログは /home/gha-runner/actions-runner/_diag/ で確認できます。既存Ubuntuが他のコンテナも動かしている場合、安易な docker system prune -a --volumes は避けてください。
8. セキュリティと運用で守りたいこと
- 信頼できるプライベートリポジトリだけにRunnerを登録する。 パブリックリポジトリのFork PRで任意コードが実行される構成は避ける。
- Runner専用ユーザー・可能ならRunner専用VMを使う。 Dockerを使うRunnerは強い権限を持つので、NASやProxmox管理ネットワークから分離する。
-
GITHUB_TOKENは最小権限にする。 Workflowにpermissions: contents: readを設定し、不要なSecretやSSH鍵をRunner上に置かない。 - ジョブ後のデータ残存に注意する。 永続型Runnerでは作業ディレクトリやキャッシュが残る。信頼境界が異なるジョブを混在させない。
- 更新と稼働状況を管理する。 Runnerアプリは通常自動更新されるが、Ubuntu・Docker・その他のツールは別途更新する。自宅停電や回線断でジョブが止まることも想定する。
複数人で共有する場合や外部コードを処理する場合は、ジョブごとに破棄するEphemeral Runner や専用VMの自動作成も検討した方が安全です。
9. Runnerを削除したい場合
一時停止だけなら、Ubuntu側で次を実行します。
cd /home/gha-runner/actions-runner
sudo ./svc.sh stop
完全に削除する場合は、GitHubの Settings → Actions → Runners → 対象Runner → Remove を開き、表示される削除手順に従ってください。必要なトークンはその画面から取得します。
まとめ
自宅Proxmox上のUbuntu ServerをSelf-hosted Runnerにすると、普段使っているVMをGitHub Actionsの実行基盤として活用できます。DockerビルドやPlaywrightのE2Eテストも実行でき、既存の計算資源・キャッシュを使えるのが魅力です。
一方、自宅サーバー上でWorkflowのコマンドが本当に実行されることが最大のリスクでもあります。まずは自分だけが管理するプライベートリポジトリで小さく試し、Dockerを使う場合や共有する場合はVM分離を検討するとよいでしょう。