Raspberry Pi 5 の GitHub Actions runner で Hugo を自動ビルドする

Hugo GitHub Actions RaspberryPi 自宅サーバ 覚書

Hugo へ移行したこのサイトを、GitHub Pages ではなく Raspberry Pi 5 上でビルドするようにした。

GitHub Pages 用の workflow は使わないので削除し、代わりに GitHub Actions の self-hosted runner を Raspberry Pi 5 に登録して、main ブランチへ push したタイミングで Rpi5 上の hugo コマンドを実行する構成にした。

やりたいこと

今回の目的は次の通り。

  • GitHub Pages への deploy workflow をやめる
  • Raspberry Pi 5 上で Hugo をビルドする
  • GitHub から Raspberry Pi へ SSH ログインしなくても自動実行できるようにする
  • Rpi5 を systemd サービスとして待機させ、push のたびにビルドさせる

self-hosted runner とは

GitHub Actions の self-hosted runner は、自分で用意したマシン上で Actions の job を実行する仕組み。

今回の場合は Raspberry Pi 5 が runner になる。

重要なのは、GitHub から Raspberry Pi へ SSH ログインするわけではない、という点。

Raspberry Pi 側で runner を起動しておくと、runner が GitHub に接続しに行き、GitHub Actions の job が来るのを待つ。

通信の向きは大まかに次のようになる。

Raspberry Pi 5  --->  GitHub

そのため、自宅ルーターで SSH ポートを公開したり、GitHub から Raspberry Pi にログインできるようにしたりする必要はない。

GitHub Pages workflow を削除する

もともとは .github/workflows/gh-pages.yml で GitHub Pages へ deploy していた。

このサイトでは GitHub Pages を使わないので、この workflow は削除した。

代わりに .github/workflows/rpi5-hugo-build.yml を追加した。

name: Build Hugo on Raspberry Pi 5

on:
  push:
    branches:
      - main
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: [self-hosted, Linux, ARM64, rpi5]
    env:
      HUGO_DESTINATION: ${{ vars.HUGO_DESTINATION || 'public' }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0

      - name: Check Hugo
        run: hugo version

      - name: Build
        run: hugo --minify --cleanDestinationDir --destination "$HUGO_DESTINATION"

main に push されたとき、または GitHub Actions 画面から手動実行したときに動く。

on:
  push:
    branches:
      - main
  workflow_dispatch:

実行先は次のラベルを持つ runner。

runs-on: [self-hosted, Linux, ARM64, rpi5]

self-hostedLinuxARM64 は自動で付くラベルで、rpi5 は自分で追加したラベル。

Raspberry Pi 5 に runner を登録する

GitHub の対象リポジトリで次の画面を開く。

Settings
  -> Actions
  -> Runners
  -> New self-hosted runner

画面では次のように選ぶ。

Runner image: Linux
Architecture: ARM64

すると、Raspberry Pi で実行するコマンドが表示される。

Rpi5 に SSH して、表示されたコマンドを実行する。

mkdir actions-runner
cd actions-runner

# GitHub の画面に表示された curl / tar コマンドを実行する

./config.sh --url https://github.com/<owner>/<repo> --token <表示されたtoken>

./config.sh の token は期限があるので、GitHub の runner 追加画面を開いてから作業する。

runner group と label を間違えない

登録中に次のように聞かれる。

Enter the name of the runner group to add this runner to: [press Enter for Default]

ここで rpi5 と入力すると、次のようなエラーになる。

Could not find any self-hosted runner group named "rpi5".

rpi5 は runner group ではなく label として使う。

そのため runner group は空のまま Enter でよい。

runner group: Default のまま
runner name : rpi5 など好きな名前
runner label: rpi5

追加ラベルを聞かれたら、そこで rpi5 を入力する。

Enter any additional labels (ex. label-1,label-2): [press Enter to skip]
rpi5

手動起動で確認する

登録できたら、一度手動で runner を起動する。

./run.sh

今回の環境では、次のように表示された。

√ Connected to GitHub

Current runner version: '2.335.1'
2026-07-09 14:01:47Z: Listening for Jobs

Connected to GitHubListening for Jobs が表示されれば、GitHub との接続はできている。

GitHub Actions 画面から workflow を手動実行すると、Raspberry Pi 側で job が走った。

2026-07-09 14:05:58Z: Running job: build
2026-07-09 14:06:23Z: Job build completed with result: Succeeded

これで Rpi5 上で Hugo build 用の job が成功した。

systemd サービスとして起動する

手動起動の ./run.sh は、端末を閉じると止まってしまう。

常時待機させるため、systemd サービスとして登録する。

まず手動起動している runner を Ctrl+C で止める。

^CExiting...
Runner listener exit with 0 return code, stop the service, no retry needed.
Exiting runner...

次にサービスをインストールして起動する。

sudo ./svc.sh install
sudo ./svc.sh start
sudo ./svc.sh status

今回の環境では、次のサービスが作成された。

/etc/systemd/system/actions.runner.usurageha-nosubject-hugo.rpi5.service

status では次のように active (running) になった。

● actions.runner.usurageha-nosubject-hugo.rpi5.service - GitHub Actions Runner (usurageha-nosubject-hugo.rpi5)
     Loaded: loaded (/etc/systemd/system/actions.runner.usurageha-nosubject-hugo.rpi5.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-07-09 23:07:31 JST

これで、Raspberry Pi 5 が起動していてネットワークにつながっていれば、GitHub Actions の job を受け取れる。

Hugo の出力先

workflow では HUGO_DESTINATION を使っている。

env:
  HUGO_DESTINATION: ${{ vars.HUGO_DESTINATION || 'public' }}

Repository variables に HUGO_DESTINATION を設定しておくと、そのパスへ Hugo の出力を置ける。

未設定なら public に出力する。

たとえば公開用ディレクトリへ直接出力するなら、GitHub のリポジトリ設定で variable を追加する。

Settings
  -> Secrets and variables
  -> Actions
  -> Variables

例:

HUGO_DESTINATION=/home/usura/nosubject-docker/hugo-public

ただし、workflow では --cleanDestinationDir を使っている。

hugo --minify --cleanDestinationDir --destination "$HUGO_DESTINATION"

出力先ディレクトリの中身を消してから生成するので、HUGO_DESTINATION には Hugo の公開先専用ディレクトリだけを指定する。

ホームディレクトリや作業ディレクトリ全体のような広すぎるパスは指定しない。

まとめ

GitHub Pages を使わず、Raspberry Pi 5 上で Hugo をビルドする流れは次のようになった。

  • GitHub Pages 用の workflow を削除する
  • Rpi5 用の GitHub Actions workflow を追加する
  • Rpi5 に self-hosted runner を登録する
  • runner に rpi5 ラベルを付ける
  • ./run.sh で接続確認する
  • GitHub Actions から手動実行して job 成功を確認する
  • svc.sh で systemd サービス化する

これで、main に push すると Raspberry Pi 5 上で Hugo が自動ビルドされるようになった。