「リンクを1本置く」だけだったはずなのに
やりたかったことは、かなり小さかった。
アフィリエイトサービスの審査を進めるため、サイトの記事に外付けHDDの商品リンクを1本置く。リンクの前には「このページにはアフィリエイトリンクが含まれ、購入時に運営者が報酬を受け取る場合がある」と明示する。商品リンクを作り、記事へ差し込み、GitHubへコミットする。
ここまでは終わった。
ところが、GitHubにコードが入った瞬間に一つの勘違いが露出した。
GitHubにあることと、インターネットで公開されていることは別である。
通常使っていたGitHub Actionsは使えない。ではCloudflare Workerでその1ページだけ横取りして返せばいいのでは、という案も出た。しかし、その経路も今回の利用条件では使えない。
リンク1本を置きたいだけなのに、気づけば「CIは? Workerは? PagesはGit連携? Direct Upload?」という配備会議が始まった。
アフィリエイト・サグラダ・ファミリア2号館の着工である。
ただし、ここで仕組みを分けて考えると話は急に簡単になる。
1. そもそも、なぜ公開ページが必要だったのか
Sovrn Commerceのコンテンツ/ブログ向けオンボーディングでは、申請したサイトにCommerceのリンクを実装し、クリックを発生させた後に審査へ進む流れが案内されている。[3]
つまり「審査に通ったらリンクを置く」ではなく、審査側が実装例を見られる状態を先に作る。
さらにSovrnは、アフィリエイトリンクがあるページごとに、報酬関係があることを読者へ分かりやすく開示するよう案内している。リンクや宣伝より前に見える位置へ置く考え方も示されている。[4]
今回必要なのは、豪華な商品比較サイトではない。
必要条件はかなり素朴だ。
- 実際のサイト上に記事がある
- その記事にアフィリエイトリンクがある
- リンクより前に開示文がある
- 公開URLから普通に閲覧できる
- 実装後に少数の確認クリックを発生させられる
ここで重要なのは最後から2番目だ。
「GitHubにHTMLが存在する」は「公開URLから見える」と同義ではない。
2. GitHub Actionsが止まっても、Cloudflare Pagesまで止まるとは限らない
GitHub Actionsは、GitHub上でビルドやテスト、デプロイを動かすCI/CDの仕組みである。
一方、Cloudflare PagesにはGitHubやGitLabを直接つなぐGit integrationがある。これを使うと、接続したリポジトリへ変更がpushされたとき、Cloudflare側がビルドとデプロイを実行する。[1]
つまり構造はこうなる。
GitHubへpush → Cloudflare Pagesが変更を検知 → Cloudflareがbuild → Cloudflareがdeploy
この経路なら、GitHub Actionsのworkflowを経由する必要がない。
ここはかなり重要だ。
「GitHub Actionsが使えない」からといって、すぐに「GitHubからCloudflareへ自動公開できない」とは限らない。ActionsとCloudflare PagesのGit連携は別物である。
工場で例えるなら、GitHub Actionsは社内の搬送ロボット。CloudflareのGit integrationは、外部倉庫が自分で集荷に来る契約だ。
搬送ロボットが止まっていても、集荷便まで止まるとは限らない。
3. 最初に確認するのは「このPagesプロジェクトは何方式か」
Cloudflare Pagesでは、ここを曖昧にしたまま作業すると一気に迷路になる。
大きく分けると、公開経路は二つある。
| 方式 | 何が起点か | ビルド/配備 | 向いているケース |
|---|---|---|---|
| Git integration | GitHub / GitLabへのpush | Cloudflare側 | リポジトリを正本にして自動公開したい |
| Direct Upload | 事前に作ったbuild成果物 | Wranglerまたはダッシュボード | ローカルや独自CIでbuildした成果物を直接出したい |
Cloudflareの公式ドキュメントでは、Git integrationで作ったPagesプロジェクトを後から通常のDirect Uploadプロジェクトへ切り替えることはできない。一方、Git連携済みプロジェクトにWranglerから手動デプロイすることは可能だが、既存Git連携プロジェクトへダッシュボードのdrag-and-dropを使う方式は使えない。[1][2]
逆に、Direct Uploadとして始めたプロジェクトへ、後から同じプロジェクトのままGit integrationを追加することもできない。自動Git連携へ移したいなら新しいPagesプロジェクトが必要になる。[2]
したがって、最初の質問は「どうデプロイする?」ではない。
「今あるPagesプロジェクトは、Git integration型かDirect Upload型か?」
ここが分かれば、選択肢の半分は消える。
4. Git integration型なら、GitHub Actionsを復活させる必要はない
すでにGitHubリポジトリとCloudflare Pagesが正しく接続されているなら、最短経路はWorkerでも新しいCIでもない。
Cloudflare Pages側で次を確認する。
- 対象プロジェクトが正しいGitHubリポジトリに接続されている
- production branchが、実際に公開したいbranchになっている
- production branchの自動buildが停止されていない
- build commandと出力directoryが現在のプロジェクトに合っている
- push後、Cloudflare PagesのDeployments画面で新しいdeploymentが作られている
pages.dev側で新しい本文を確認する- 最後にcustom domain側でも同じ本文を確認する
CloudflareのGit integrationは、接続したbranchへのcommitをもとにbuildとdeployを行う。[1]
したがって、GitHub Actionsが一時的に使えなくても、Cloudflare native buildが生きていれば公開ラインは維持できる。
ここでやるべきことは「別の複雑な仕組みを増築する」ではなく、元々あるCloudflareの集荷口が開いているか確認することである。
5. Direct Upload型なら「1ページだけ投げる」ではなく、build成果物を出す
Direct Uploadは、完成済みの静的ファイル一式をCloudflare Pagesへ渡す方式である。公式ドキュメントでは、事前にbuildしたassetsをWranglerまたはダッシュボードからアップロードする流れが案内されている。[2]
ここで危ない発想がある。
「今回追加したHTMLだけCloudflareへ投げればよくない?」
静的サイト全体をbuildしている構成では、これは基本的に避けたい。
デプロイ単位は「Git差分の1ファイル」ではなく、その時点のサイトを構成するbuild出力だからだ。ページ一覧、CSS、JavaScript、検索index、asset、routingなどが一緒に生成される構成なら、1枚だけ手作業で差し込むと本番とリポジトリの状態が分離する。
Direct Uploadを使うなら、原則はこうなる。
最新版を取得 → projectのbuild commandを実行 → 出力directoryを確認 → 出力一式をdeploy → 本番URLを確認
たとえばNode系の静的サイトなら pnpm build のようなproject固有のbuild commandを実行し、生成された dist などのdirectoryをアップロードする。
重要なのは、本番を「1ファイルだけ手で直した謎の別世界」にしないことである。
6. Workerという逃げ道が使えないなら、素直に消す
1ページだけ緊急公開したい場合、特定pathだけWorker routeで横取りする発想自体は成立する。
しかし、今回のようにWorker経路も利用条件上使えないなら、それを中心設計にしても意味がない。
使えない経路を「もしかしたら」で設計図に残すほど、運用は複雑になる。
- GitHub Actionsは使えない
- Workerも使えない
- なら、Cloudflare PagesのGit integrationかDirect Uploadのどちらかに絞る
これでいい。
非常口を10個作るより、今開いている正面玄関を1個特定した方が速い。
アフィリエイトリンク1本のために配備基盤をもう一棟建てない。
これが今回いちばん大きな教訓だった。
7. 公開完了は「commit SHA」ではなく、実ページで判定する
Web運用で危険なのは、工程の途中を完成と呼ぶことだ。
- コードを書いた
- GitHubへcommitした
- buildが通った
- Cloudflareにdeploymentができた
どれも重要だが、読者が見るのは最終URLだけである。
今回のようなアフィリエイト審査ページなら、最後に確認するのは次の状態だ。
- 公開URLをシークレットウィンドウ等で開ける
- 最新の記事本文が表示される
- アフィリエイト開示文がリンクより前に見える
- 商品リンクが期待した遷移先へ動く
- モバイルでも表示が壊れていない
- 必要なら数回の確認クリックを発生させる
- Sovrn側でクリック計測や審査状態を確認する
Sovrnは、Content/Blog campaignについてリンクを実装してクリックを発生させた後に審査する流れを説明している。[3]
したがって、「GitHubへ入れたので審査待ち」ではなく、本番URLで実装を見せられる状態まで行って初めてスタートラインである。
8. その後は、アフィリエイトURLを記事本文へ焼き込まない方がいい
今回の1本は手動でもいい。
しかし、記事が数百、数千と増えるなら、毎回「この記事には広告を入れる? どこ? どの商品? どの国?」を人間が手で決めると、記事工場の横に広告工場が生えてしまう。
次の段階では、本文と収益化情報を分離した方が扱いやすい。
たとえば記事側には、次のような小さなmonetization manifestだけを持つ。
article_id: example-123
affiliate: true
placement: after_solution
max_products: 3
market_mode: auto
product_theme: external-storage
そして公開時に、
記事 → 収益化ゲート → 商品候補 → affiliate link生成 → rendererが挿入 → 実績計測
と流す。
本文は長期資産として残し、商品URLや在庫、merchant、国別routingは交換可能な部品にする。
これならリンク切れや商品変更のたびに12言語の本文を掘り返さなくて済む。
アフィリエイトは記事そのものではない。
記事に後から接続できる営業配管くらいにしておく方が、長期運用では強い。
9. 結論:CIが死んだら、別の城を建てる前にCloudflareの入口を確認する
今回の流れは、かなり象徴的だった。
「審査用にHDDの商品リンクを1本置こう」
から始まった。
リンクは作れた。開示文も書けた。GitHubにも入った。
しかし本番へ出す段階で、GitHub Actionsが使えない。Workerで逃げようとしても、その経路も使えない。
ここでさらに新しい仕組みを足すと、目的が「リンクを公開する」から「配備システムを増築する」にすり替わる。
整理すると、必要なのは次の判断だけだ。
- 既存PagesがGit integration型なら、Cloudflare native buildを使う
- Direct Upload型なら、サイト全体をbuildして正規の成果物をdeployする
- Workerが使えないなら候補から消す
- GitHub commitを公開完了と呼ばない
- 最終URLで開示文・リンク・表示・クリックを確認する
技術的に一番危ないのは、選択肢が少ないことではない。
使えない選択肢まで設計図に残り続けることである。
リンク1本から始まった配備迷路の答えは、意外と地味だった。
まず、自分のCloudflare Pagesがどの方式なのかを見る。
そこからで十分だった。
