niki-til

GitHub Pages と Cloudflare Pages — 仕組みの違いと nikinakamura.com への移行プラン

この TIL は現在 niki-nakamura.github.io/til/ で公開しているこのサイトを、すでに保有している nikinakamura.com(auto-renew 2027-04-21)に乗せ替えるべきか検討した記録。前提として、まず Web ホスティングと CDN の基礎を押さえ、GitHub Pages と Cloudflare Pages がそれぞれ何をしていてなぜ無料なのかを腑分けし、そのうえで具体的な移行手順と落とし穴を書く。最後に「今の自分には何が最適か」を結論として置く。

1. HTTP と Web ホスティングの基礎

1.1 HTTP / HTTPS が裏でやっていること

ブラウザに https://niki-nakamura.github.io/til/ と打つと、以下の順番で通信が起きる。

  1. DNS 解決: niki-nakamura.github.io という名前を IP アドレスに変換する。OS の resolver → ISP の DNS キャッシュ → 権威 DNS サーバの順に問い合わせが進む
  2. TCP 接続: 解決した IP に対して 3-way handshake(SYN / SYN-ACK / ACK)で TCP コネクションを張る
  3. TLS handshake: HTTPS なので証明書交換と鍵共有を行う。TLS 1.3 では 1-RTT、再接続なら 0-RTT で済む
  4. HTTP request: GET /til/ HTTP/2 のようなリクエストを送る
  5. HTTP response: サーバが status code(200 OK など)と HTML を返す
  6. 追加リソース: HTML 内の <link> <script> <img> を解析して同じことを繰り返す

HTTP の正式仕様は RFC 9110(HTTP Semantics)と RFC 9112(HTTP/1.1)にまとまっている(https://www.rfc-editor.org/rfc/rfc9110.html )。HTTP/2 は RFC 9113、HTTP/3 は RFC 9114 で、HTTP/3 は TCP ではなく QUIC(UDP 上で TLS とフロー制御を統合したもの)を使う。実用面では HTTP/2 でヘッダ圧縮と多重化(同一コネクションで複数 request を並行送信)、HTTP/3 で head-of-line blocking の解消が効く。

1.2 DNS の役割

DNS は「名前 → IP」を引くだけでなく、用途ごとに複数のレコードタイプを持つ。Web ホスティングで触るのは主に次の 3 つ。

他に MX(メール)、TXT(SPF / DKIM / 所有権確認)、CAA(証明書発行許可)などがあり、nameserver 移行時には MX を必ず引き継ぐ必要がある(詳細は §5.8)。

1.3 「ホスティング」のレイヤー

「Web ホスティング」と一括りに呼ぶが、実態は何層かに分かれる。

静的サイトはエッジホスティングと相性がよく、最近の Pages 系サービス(Cloudflare Pages、Vercel、Netlify)は「静的サイトホスティング + エッジ実行」のハイブリッドになっている。

1.4 CDN とエッジキャッシュ

CDN(Content Delivery Network)は、世界中の PoP(Point of Presence) にコンテンツを複製しておき、ユーザに最も近い PoP から返す仕組み。Cloudflare の説明(https://www.cloudflare.com/learning/cdn/what-is-a-cdn/ )によれば、CDN がサイトを速くする理由は次の 3 点に集約される。

  1. 物理距離の短縮: 東京のユーザに対して US East のオリジンから返すと往復で 100ms 以上かかるが、東京の PoP にキャッシュがあれば数 ms で返る
  2. オリジン負荷の軽減: 同じファイルを複数ユーザに返す場合、キャッシュヒットすればオリジンに問い合わせない
  3. 接続効率: PoP はバックボーンを使ってオリジンと張りっぱなしの接続を持ち、TCP / TLS のセットアップコストを償却できる

「オリジン」は本物のファイルが置いてある場所、「エッジ」は世界中の PoP。エッジで cache miss が起きたときだけオリジンに取りに行く。静的サイトの場合、ビルド成果物そのものを全 PoP にあらかじめ配っておく(pre-distribute)方式が主流。

2. GitHub Pages の仕組み

2.1 push から配信までに何が起きているか

main ブランチに push したあと、内部では次の流れが走る。

  1. GitHub Actions が自動でトリガされる(明示的に workflow を書かなくても、Pages 設定をオンにすると裏で pages-build-deployment という Action が走る)
  2. リポジトリ root の _config.yml を読み、Jekyll が bundle exec jekyll build 相当のビルドを実行して _site/ に成果物を出す
  3. その成果物を GitHub の静的配信基盤に転送し、Fastly ベースの CDN に乗せる
  4. <user>.github.io/<repo>/ の URL で配信開始

GitHub Pages の CDN が Fastly であることは、niki-nakamura.github.iocurl -I した時に返る server: GitHub.com ヘッダや過去のインシデントレポート(status.github.com)で繰り返し確認されている、というのが定説。ただし GitHub 公式ドキュメントは「CDN を使っている」と書いているだけで Fastly と明言している箇所は見つからなかったので、ここは公式確認できなかった事実として記録しておく。

2.2 URL 構造と baseurl

GitHub Pages の URL 構造は 2 通り(https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages )。

このリポジトリは project site なので niki-nakamura.github.io/til/ の subpath になり、Jekyll の _config.ymlbaseurl: /til を指定して内部リンクを補正している。ルートドメイン(nikinakamura.com)にデプロイするときはこの baseurl を空文字列に変更しないと、CSS のパスが /til/assets/... のままになって 404 になる。

2.3 なぜ無料なのか

GitHub Pages はストレージ・帯域・ビルドすべて無料で、商用利用も認められている。これが成立する事業的背景は次のように整理できる(ここは推測を含む)。

2.4 ハード制限(公式値)

GitHub の公式 limits ページ(https://docs.github.com/en/pages/getting-started-with-github-pages/github-pages-limits )に書かれている上限はおおむね次のとおり。

加えて、Jekyll の plugin allowlist がある。_config.ymlplugins: に書ける gem は GitHub が許可したものに限られ、pages-gem の dependency manifest(https://pages.github.com/versions/ )に列挙された 9 個ほどのデフォルト + 追加許可 plugin だけが使える。未承認の plugin を入れると Pages 側のビルドは通らず、ローカルで jekyll build した成果物を push するか、GitHub Actions で任意のビルドを走らせて成果物をデプロイする迂回が必要になる。

2.5 カスタムドメインを向ける標準手順

公式の手順は次のとおり(https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site )。

  1. リポジトリの Pages 設定で Custom domain に nikinakamura.com を入力 → リポジトリに CNAME ファイルが自動で commit される
  2. registrar(または DNS プロバイダ)側で次のレコードを設定:
    • apex: GitHub の 4 つの IP に A レコード(185.199.108.153 / .109.153 / .110.153 / .111.153
    • www: niki-nakamura.github.io. への CNAME
  3. GitHub 側で DNS check が通れば Enforce HTTPS をオンにする。Let's Encrypt 証明書が自動発行される

3. Cloudflare Pages の仕組み

3.1 push から配信までに何が起きているか

Cloudflare Pages は GitHub の Pages とは別物で、Cloudflare 自前のビルド基盤と CDN を使う(https://pages.cloudflare.com )。

  1. Git 連携で push を検知
  2. Cloudflare の build environment(コンテナ)で任意の SSG / framework を実行。Jekyll、Hugo、Astro、Next.js、Remix、SvelteKit、Nuxt など主要 framework は preset 済み
  3. 成果物を Cloudflare の グローバル CDN に push。Cloudflare の network は 337 都市、100+ 国に展開(https://www.cloudflare.com/network/ )
  4. 全 PoP からエッジ配信

GitHub Pages との最大の構造的違いは、ビルド成果物が CDN の origin として配信される のではなく、CDN そのものに pre-distribute される こと。エッジが本体になっている。

3.2 DNS と SSL

nikinakamura.com を Cloudflare で運用するには、registrar 側の nameserver を Cloudflare のもの(例: bob.ns.cloudflare.com / lara.ns.cloudflare.com)に切り替える。これにより Cloudflare の DNS が権威サーバになる。

3.3 なぜ無料なのか(重要)

Cloudflare Pages の無料プランには 帯域無制限・リクエスト無制限・サイト数無制限 が含まれる(https://pages.cloudflare.com )。これがなぜ事業として成立しているかは、彼ら自身が複数の blog で説明している。要点は次の 4 つ。

  1. コスト構造: Cloudflare は自前の世界規模 CDN(337 都市、世界人口の 95% から 50ms 以内)を持ち、固定費中心の事業モデル。1 ユーザー追加の限界費用がほぼゼロ
  2. 規模の経済: 無料ユーザーは Cloudflare のトラフィック量を底上げする。Cloudflare の営業資料で「世界 X% のトラフィックを処理」と言えるほど、商用顧客への価格交渉力が増す
  3. アップセル: Pages 自体は無料維持しつつ、Workers(サーバレス実行)、R2(オブジェクトストレージ)、D1(SQLite)、KV、Durable Objects、Images、Stream、Zero Trust などの周辺で課金する。Pages を入口として開発者を取り込む設計
  4. 対競合(Vercel / Netlify)の差別化: Vercel と Netlify の無料プランは帯域 100 GB / month が上限で、超えると即停止または課金。Cloudflare はここを「無制限帯域」で差別化し、開発者の流入を奪っている

確認できなかった事実: Cloudflare 側が「Pages を Workers のロスリーダーとして位置付けている」と明示的に書いた blog 投稿は今回の WebFetch では特定できなかった(blog.cloudflare.com/cloudflare-pages-goes-full-stack/ は別の話題だった)。アップセル戦略の解釈は推測。

3.4 ハード制限(公式値)

Free プランの制限(https://developers.cloudflare.com/pages/platform/limits/ )。

別途、Workers を併用する場合のみ Workers 側の制限(free で 100,000 requests / day)がかかる。純粋な静的配信だけなら Workers 制限は無関係。

3.5 カスタムドメイン手順

  1. registrar で nameserver を Cloudflare のものに切り替え(DNS propagation で数分〜24 時間)
  2. Cloudflare Dashboard → Workers & Pages → 対象プロジェクト → Custom Domains → nikinakamura.comwww.nikinakamura.com を追加
  3. DNS レコードと SSL 証明書は Cloudflare が自動で設定

4. 直接比較表

| 項目 | GitHub Pages | Cloudflare Pages | |---|---|---| | ホスティング基盤 | GitHub の静的配信 + 第三者 CDN | Cloudflare 自前のグローバル CDN | | エッジ PoP 数 | 非公開 | 337 都市 / 100+ 国 | | 無料帯域 | ソフトリミット 100 GB / month | 無制限 | | ビルド時間制限 | 10 分 | 20 分 | | ビルド回数 | 10 / hour(ソフト) | 500 / month | | 同時ビルド | 1 | 1 | | 公開サイトの最大サイズ | 1 GB | 20,000 ファイル / 各 25 MiB | | フレームワーク自由度 | Jekyll が一級。他は Actions で迂回 | Jekyll / Hugo / Astro / Next.js 等 preset 多数 | | カスタムドメイン | 1 / repo(1 site) | 100 / project | | SSL | Let's Encrypt 自動 | Universal SSL 自動 | | エッジ実行(サーバレス) | なし(純粋静的のみ) | Pages Functions / Workers と統合 | | 画像最適化 | なし | Cloudflare Images(有料) | | 設定の慣性 | 既に動いている / 移行コスト 0 | 新規設定が必要 | | プラットフォーム lock-in | 低(Jekyll は CMS 非依存) | 中(Workers / D1 / R2 を使うと依存度↑) |

5. nikinakamura.com への移行プラン

ドメインは既に保有済み、ホスティング先として Cloudflare Pages 無料を検討中、というのが前提。手順を時系列で書く。

5.1 準備: Cloudflare に DNS を寄せる

5.2 Pages プロジェクト作成

Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect to Git → niki-nakamura/til を選択。

ビルド設定:

Framework preset:    Jekyll
Build command:       bundle exec jekyll build
Build output dir:    _site
Root directory:      /
Environment:         RUBY_VERSION = 3.x(_config.yml と整合)

5.3 ビルド検証

Cloudflare は preview URL(<branch>.<project>.pages.dev)を自動発行する。ここで動作確認する。注意点:

5.4 カスタムドメイン

Pages プロジェクト → Custom Domains → nikinakamura.comwww.nikinakamura.com を両方追加。Cloudflare は自動で必要な CNAME を DNS に挿入し、Universal SSL の証明書を発行する。

5.5 GitHub Pages からのリダイレクト

推奨は 30 日以上の並行運用niki-nakamura.github.io/til/ から nikinakamura.com への 301 リダイレクトを GitHub Pages 側に仕込む。

ただし、GitHub Pages は真の 301 ステータスを返せない(純粋な静的配信のため、HTTP ヘッダを動的に出せない)。代替は次の 2 つ。

  1. jekyll-redirect-from プラグイン(Pages allowlist 入り)で各ページに redirect ページを生成。生成される HTML は <meta http-equiv="refresh">window.location.replace() を併用。SEO 的には 301 と同等に扱われる、というのが Google John Mueller の公式回答だが、強度は本物の 301 より弱い
  2. トップ index.html だけ手書きで meta refresh + canonical link rel + JS リダイレクトを入れる

実装は 1 で済ませるのが現実的。

5.6 SEO 引き継ぎ

5.7 GA4 / 計測

GA4 は計測 ID(G-XXXXXXXXXX)で動くので、タグ自体はそのまま動く。やることは:

5.8 DNS の落とし穴(重要)

nameserver を Cloudflare に切り替える瞬間、既存の DNS レコードは Cloudflare 側に登録したものに 完全に置き換わる。具体的には:

nikinakamura.com で運用中のメールがあるなら、切り替え前に以下を確認:

dig MX nikinakamura.com +short
dig TXT nikinakamura.com +short
dig CAA nikinakamura.com +short

これらを Cloudflare DNS に手で先に入れてから nameserver を切り替える。

6. 結論 — 今移行すべきか

正直に書くと、現時点(エントリ 13 本、月間 PV おそらく 3 桁)では Cloudflare Pages のメリットは過剰。GitHub Pages の 100 GB / month と 1 GB サイズ上限には当分当たらないし、Jekyll の plugin allowlist の中で困っていない。

推奨は ハイブリッド構成:

  1. ドメインだけ先に Cloudflare DNS に乗せる: nameserver を Cloudflare に切り替え、DNS / WAF / DDoS 防御の恩恵だけ受ける
  2. ホスティングは GitHub Pages のまま: nikinakamura.com を GitHub Pages のカスタムドメインとして設定する(apex は GitHub の 4 つの A レコード、www は CNAME)
  3. Cloudflare 側は DNS only(グレー雲)か Proxied(オレンジ雲)かを選ぶ: Proxied にすると Cloudflare の CDN を経由するので、GitHub Pages のオリジン帯域を消費しにくくなる副次効果がある

これで「nikinakamura.com で自分のサイトが見える」を最小コストで達成できる。

本格的な Cloudflare Pages 移行は、次のいずれかが発生したときに考える。

  1. コンテンツが商業的に重要になり、エッジ最適化や A/B テストが必要になった
  2. Workers でメール capture、redirect logic、auth、edge-side rendering が必要になった
  3. GitHub Pages の plugin allowlist や 10 分ビルド上限に当たって、ローカルビルドや Actions に逃げているのが煩わしくなった

「無料の罠」は、無料同士の差別化要素(無制限帯域、Workers との統合)を 必要ないのに先取りして移行コストを払う こと。13 エントリの個人 TIL で「Cloudflare の方が速い」は計測上の差より移行 / 学習コストのほうが大きい。

参考・引用元

2026-05-18