🚀 はじめに:この記事でできること
GitHub Actions ホストランナー(GitHub管理ランナー) 上でジョブを実行しながら、自前のWireGuard VPNサーバー(国内)を出口としてインターネットへ接続する方法を解説します。
root権限・一時実行環境・Secrets制約といったActions特有の前提を踏まえ、操作 → 目的 → 結果 → 注意/補足 の流れで安全に構築します。
想定ユースケース
- 国内IPからのみアクセス可能なAPI/サイトの検証
- クローリング・E2Eテストでの地域制約回避(合法・規約順守前提)
- CIからの外部通信を自前ネットワークに集約
🧭 前提:構成上の制約と選択肢
ホストランナーは短命・共有・一時的という前提があります。ここを理解することが成功の鍵です。
操作
- ランナーの権限制約と接続方式を確認する
目的
- 「できること/できないこと」を把握し、ハマりどころを回避する
前提
- GitHub Actions ホストランナー(ubuntu-latest 等)
- 既に 国内に設置したWireGuard VPNサーバー が稼働している
sudoが使える(GitHubホストランナーでは可)- 外向き UDP 51820 がランナーから到達可能(通常は可)
結果(この時点でできること)
- ホストランナーでも ユーザースペースでVPNを張れる ことを理解できる
注意(重要)
- ホストランナーは systemd常駐や自動起動は不可。
- VPNは ジョブ内で起動→終了 する設計が必須。
- 複数ジョブ/マトリクスでは同時起動不可(競合防止)。
🧩 準備:Secrets と VPN クライアント設計
この章では、ホストランナーに状態を残さない ための安全な設計を行います。
1-1. GitHub Actions Secrets の準備
操作
- VPN接続に必要な情報を Secrets に登録する
目的
- 設定値・鍵をリポジトリに残さず、安全に参照する
前提
- リポジトリ管理者権限
登録するSecrets例
WG_CLIENT_PRIVATEKEY:ランナー用秘密鍵WG_SERVER_PUBLICKEY:VPNサーバー公開鍵WG_ENDPOINT:vpn.example.jp:51820WG_CLIENT_ADDRESS:例10.8.0.20/32
結果(この時点でできること)
- ワークフロー内でVPN設定を動的生成できる
注意
Secretsの内容は ログ出力厳禁。set -xは使用しない。
⚙️ Step 1:ホストランナー上でWireGuardを起動
GitHubが用意したランナー上に 一時的なWireGuardクライアント を構成します。
1-1. WireGuard のインストール
操作
- ジョブ内で WireGuard をインストールする
目的
- VPNクライアントを使用可能にする
前提
sudoが利用可能
sudo apt update
sudo apt install -y wireguard wireguard-tools
結果(この時点でできること)
wg/wg-quickが利用可能
補足
ホストランナーは毎回新品のVM。インストールは都度必要です。
1-2. クライアント設定ファイルを生成
操作
- Secretsから
wg0.confを生成する
目的
- 秘密情報を残さず、安全にVPN設定を作る
前提
- Secretsが登録済み
sudo mkdir -p /etc/wireguard
sudo bash -c 'cat > /etc/wireguard/wg0.conf' <<EOF
[Interface]
Address = ${{ secrets.WG_CLIENT_ADDRESS }}
PrivateKey = ${{ secrets.WG_CLIENT_PRIVATEKEY }}
DNS = 1.1.1.1
[Peer]
PublicKey = ${{ secrets.WG_SERVER_PUBLICKEY }}
Endpoint = ${{ secrets.WG_ENDPOINT }}
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
sudo chmod 600 /etc/wireguard/wg0.conf
結果(この時点でできること)
- ランナー上に一時的なVPN設定が完成
注意
YAMLのインデント崩れや変数展開ミスが 最頻出エラー。
1-3. VPNを起動
操作
wg-quick upでVPNを開始
目的
- 外向き通信の出口を国内VPNに切り替える
前提
- サーバー側に該当Peerが登録済み
sudo wg-quick up wg0
sudo wg show
結果(この時点でできること)
- このジョブ内のネットワーク通信が国内経由になる
注意
VPN起動後は SSH/HTTP等すべてVPN側にルーティング されます。
🧪 Step 2:国内出口の確認
操作
- 外部IPを確認する
目的
- 実際に国内IPで通信できているか検証
前提
- VPN接続が確立している
curl -s https://ipinfo.io/json
結果(この時点でできること)
country: JP等が確認でき、国内出口であることを証明
🔁 Step 3:VPNを安全に終了
操作
- ジョブ終了時にVPNを停止する
目的
- 不要なトンネルを残さず、後続ステップへの影響を防ぐ
前提
- VPNが起動している
sudo wg-quick down wg0 || true
結果(この時点でできること)
- ランナーが初期状態に戻る
注意
if: always()を使い、失敗時も必ず実行。
✅ 完成形のワークフロー例
name: vpn-outbound-japan
on:
workflow_dispatch:
jobs:
run-via-japan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install WireGuard
run: |
sudo apt update
sudo apt install -y wireguard
- name: Setup VPN
run: |
sudo mkdir -p /etc/wireguard
sudo bash -c 'cat > /etc/wireguard/wg0.conf' <<EOF
[Interface]
Address = ${{ secrets.WG_CLIENT_ADDRESS }}
PrivateKey = ${{ secrets.WG_CLIENT_PRIVATEKEY }}
DNS = 1.1.1.1
[Peer]
PublicKey = ${{ secrets.WG_SERVER_PUBLICKEY }}
Endpoint = ${{ secrets.WG_ENDPOINT }}
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
sudo chmod 600 /etc/wireguard/wg0.conf
sudo wg-quick up wg0
- name: Access via Japan outbound
run: |
curl -s https://ipinfo.io/json
- name: Teardown VPN
if: always()
run: |
sudo wg-quick down wg0 || true
⚠️ よくあるつまずき(チェックリスト)
- Secretsが正しく登録されている
- YAMLのインデントが崩れていない
- Peerがサーバー側に登録済み
- UDP 51820 が到達可能
-
AllowedIPsが意図通り(全トラフィック) - VPN停止を
always()で実行している - Secretsをログに出していない
🔧 拡張案(次にやると良いこと)
- スプリットトンネル化:特定APIのみVPN経由にする
- IPチェック自動化:国内IPでなければジョブ失敗
- 出口冗長化:VPNサーバーを2台構成に
- Secretsローテーション:定期的な鍵更新
🎯 まとめ
- GitHub Actions ホストランナーでもWireGuard VPNは利用可能
- ポイントは「ジョブ内で起動・終了」「Secrets徹底管理」
- 国内IP要件のあるCIを、安全かつ再現性高く実現できる
