ブログへ戻る

別リポジトリの変更でCloudflare Pagesを再デプロイする

Cloudflare PagesのGit連携は1つのリポジトリしか監視しない。コンテンツや設定が別リポジトリにある場合、Deploy HookとGitHub Actionsを組み合わせることで自動デプロイを実現できる。

Cloudflare PagesのGit連携は、接続した1つのリポジトリを監視する。そのリポジトリへのpushがビルドのトリガーになる。それ以外の仕組みはない。

コンテンツリポジトリとフロントエンドリポジトリを分けている場合、コンテンツ側へpushしてもPagesは何も知らない。Cloudflareから見て、2つのリポジトリは無関係だ。

解決策はDeploy Hookだ。CloudflareがPagesプロジェクトに対して発行するURLで、POSTリクエストを受け取るとビルドをキューに入れる。コンテンツリポジトリのGitHub Actionsからこれを呼ぶことで、連携が成立する。

なぜGit連携だけでは解決しないか

PagesをGitHubまたはGitLabに接続すると、Cloudflareは対象リポジトリにWebhookを設置し、設定したブランチへのpushを監視する。2つ目のリポジトリを監視する手段は、この仕組みには存在しない。

コンテンツがリポジトリA、PagesのフロントエンドがリポジトリBにある構成では、Aへのpushに対してPagesは何も反応しない。

実際にこの状況に遭遇した。コンテンツリポジトリとPagesのフロントエンドリポジトリを別々に管理していたところ、コンテンツ側へのpushがPagesに届かない状態が続いた。エラーも通知も出ない。Pagesは単純に何も知らないまま再ビルドしない。Deploy Hookで接続するまで、この問題に気づく手がかりすらなかった。

Cloudflare PagesでDeploy Hookを作る

Cloudflareダッシュボードで Workers & Pages → 対象プロジェクト → SettingsBuilds & deployments を開く。Deploy Hooks のセクションまでスクロールし、Add Deploy Hook をクリックする。

何がトリガーするかが分かる名前(例:content-repo-main)を入力し、ビルド対象のブランチを選ぶ。Save をクリックするとURLが生成されるので、コピーしておく。

hookはブランチ単位で作成する。main向けのhookは本番ビルドを起動し、preview向けに別のhookを作ればプレビュー環境をトリガーできる。

このURLを持っている人は誰でもビルドを起動できる。シークレットトークンと同等の扱いが必要だ。

URLをGitHub Secretへ登録する

トリガー元リポジトリ(PagesリポジトリではなくAの方)で Settings → Secrets and variables → Actions → New repository secret を開く。

  • Name: CLOUDFLARE_DEPLOY_HOOK
  • Value: コピーしたURL

ワークフローファイルにURLを直接書いてはいけない。リポジトリ履歴に残り、読み取り権限を持つ全員にURLが露出する。GitHub ActionsはSecretsの値をログで自動的にマスクするが、プレーンテキストのURLはマスクされない。

トリガー元リポジトリにワークフローを追加する

トリガー元リポジトリに .github/workflows/deploy-pages.yml を作成する。

name: Trigger Cloudflare Pages Deploy

on:
  push:
    branches:
      - main

jobs:
  trigger:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Cloudflare Pages build
        run: |
          curl --silent --fail -X POST "${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}"

--fail オプションをつけると、CloudflareがHTTPエラーを返したときにcurlが非ゼロで終了し、ステップが失敗としてマークされる。つけなければ、POSTが失敗していてもステップは成功に見える。

mainへのpushのたびにこのワークフローが実行され、Cloudflareはhookに設定されたブランチのビルドをキューに入れる。

pushの条件を絞る

トリガー元リポジトリにPagesのビルドに無関係なファイルが含まれる場合、パスフィルターで条件を絞れる。

on:
  push:
    branches:
      - main
    paths:
      - 'content/**'
      - 'data/**'

この設定では content/data/ 以下のファイルが変更されたpushだけがビルドを起動する。CI設定やドキュメントだけの変更では起動しない。

POSTのレスポンスが示すもの

成功すると、Cloudflareは次のJSONを返す。

{"id":"abc123def456"}

これはビルドがキューに入ったことを示す。完了成功を意味しない。ワークフローのステップはこのレスポンスを受け取った時点で終了する。

ビルドの実際の結果を確認するには、Cloudflareダッシュボードの Workers & Pages → 対象プロジェクト → Deployments を開く。hookでトリガーされたデプロイがそこに表示される。

ビルド結果をワークフローで受け取りたい場合

GitHubActionsのジョブ自体にビルドの成否を反映させたい場合——たとえばビルド失敗時に後続ステップをブロックしたい場合——はDeploy Hookだけでは対応できない。Cloudflare Pages REST API とAPIトークンを使ってビルド完了をポーリングする実装が必要になる。

GitHub Marketplaceにはこれを処理するサードパーティのアクションも存在するが、本番環境に追加する前にメンテナンス状況と要求するパーミッションを確認すること。

通常のユースケースではDeploy Hookで十分だ。ビルドの失敗はCloudflareダッシュボードで確認でき、Cloudflareの通知設定でアラートを受け取ることもできる。

月間ビルド数の上限に注意する

CloudflareのFreeプランは月500ビルドが上限だ(Cloudflare Pages Limits)。コミットが多いリポジトリでは、パスフィルターなしだと想定より早く上限に達する可能性がある。

パスフィルターで不要なビルドを減らすのが最初の対策だ。それでも足りない場合は、pushトリガーからスケジュール実行に切り替える方法もある。

on:
  schedule:
    - cron: '0 */6 * * *'  # 6時間ごと

コンテンツの更新タイミングにある程度の余裕が許容されるなら、1日数回の定期ビルドの方がビルド数の管理がしやすい。

注意点として、トリガー元リポジトリとPagesが接続しているリポジトリが同一の場合、pushで2つのビルドが走る——Git連携によるものとhookによるものだ。2つのリポジトリを使う今回の構成ではこの問題は起きないが、同一リポジトリにhookを設定する場合は二重実行を意識しておくこと。


2026年7月時点の情報。Cloudflare Pagesのプラン制限とUIは変更される可能性がある。最新情報はCloudflare Pagesドキュメントで確認すること。