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/ と打つと、以下の順番で通信が起きる。
- DNS 解決:
niki-nakamura.github.ioという名前を IP アドレスに変換する。OS の resolver → ISP の DNS キャッシュ → 権威 DNS サーバの順に問い合わせが進む - TCP 接続: 解決した IP に対して 3-way handshake(SYN / SYN-ACK / ACK)で TCP コネクションを張る
- TLS handshake: HTTPS なので証明書交換と鍵共有を行う。TLS 1.3 では 1-RTT、再接続なら 0-RTT で済む
- HTTP request:
GET /til/ HTTP/2のようなリクエストを送る - HTTP response: サーバが status code(
200 OKなど)と HTML を返す - 追加リソース: 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 つ。
- A レコード: 名前を IPv4 アドレスに紐付ける(
nikinakamura.com → 185.199.108.153など) - CNAME レコード: 名前を別の名前に紐付ける(
www.nikinakamura.com → niki-nakamura.github.io.)。ルートドメイン(apex)に CNAME を置くのは RFC 上禁止で、代替として A レコードか ANAME / ALIAS と呼ばれる擬似レコードを使う - NS(nameserver)レコード: そのドメインの権威 DNS サーバを指定する。
nikinakamura.comを Cloudflare に乗せるとは、registrar 側の NS レコードを Cloudflare の NS(例:ns1.cloudflare.com)に書き換えることを指す
他に MX(メール)、TXT(SPF / DKIM / 所有権確認)、CAA(証明書発行許可)などがあり、nameserver 移行時には MX を必ず引き継ぐ必要がある(詳細は §5.8)。
1.3 「ホスティング」のレイヤー
「Web ホスティング」と一括りに呼ぶが、実態は何層かに分かれる。
- 静的サイトホスティング: HTML / CSS / JS / 画像をそのまま返すだけ。GitHub Pages、Cloudflare Pages、Netlify、Vercel(の static 部分)、S3 + CloudFront などが該当
- サーバ実行型ホスティング: PHP / Node.js / Python など、リクエストごとにサーバでコードを走らせる。Heroku、Render、AWS Elastic Beanstalk、自前 VPS など
- オブジェクトストレージ: ファイルを置くだけのストア。Amazon S3、Cloudflare R2、Google Cloud Storage。単体では HTTP 配信もできるが、CDN を被せて使うのが普通
- エッジホスティング: コードを世界中のエッジロケーションで走らせる。Cloudflare Workers、AWS Lambda@Edge、Vercel Edge Functions、Deno Deploy
静的サイトはエッジホスティングと相性がよく、最近の 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 点に集約される。
- 物理距離の短縮: 東京のユーザに対して US East のオリジンから返すと往復で 100ms 以上かかるが、東京の PoP にキャッシュがあれば数 ms で返る
- オリジン負荷の軽減: 同じファイルを複数ユーザに返す場合、キャッシュヒットすればオリジンに問い合わせない
- 接続効率: PoP はバックボーンを使ってオリジンと張りっぱなしの接続を持ち、TCP / TLS のセットアップコストを償却できる
「オリジン」は本物のファイルが置いてある場所、「エッジ」は世界中の PoP。エッジで cache miss が起きたときだけオリジンに取りに行く。静的サイトの場合、ビルド成果物そのものを全 PoP にあらかじめ配っておく(pre-distribute)方式が主流。
2. GitHub Pages の仕組み
2.1 push から配信までに何が起きているか
main ブランチに push したあと、内部では次の流れが走る。
- GitHub Actions が自動でトリガされる(明示的に workflow を書かなくても、Pages 設定をオンにすると裏で
pages-build-deploymentという Action が走る) - リポジトリ root の
_config.ymlを読み、Jekyll がbundle exec jekyll build相当のビルドを実行して_site/に成果物を出す - その成果物を GitHub の静的配信基盤に転送し、Fastly ベースの CDN に乗せる
<user>.github.io/<repo>/の URL で配信開始
GitHub Pages の CDN が Fastly であることは、niki-nakamura.github.io を curl -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 )。
- User / Organization site:
<user>.github.io(1 アカウントにつき 1 サイト) - Project site:
<user>.github.io/<repo>(1 リポジトリにつき 1 サイト)
このリポジトリは project site なので niki-nakamura.github.io/til/ の subpath になり、Jekyll の _config.yml で baseurl: /til を指定して内部リンクを補正している。ルートドメイン(nikinakamura.com)にデプロイするときはこの baseurl を空文字列に変更しないと、CSS のパスが /til/assets/... のままになって 404 になる。
2.3 なぜ無料なのか
GitHub Pages はストレージ・帯域・ビルドすべて無料で、商用利用も認められている。これが成立する事業的背景は次のように整理できる(ここは推測を含む)。
- GitHub は Microsoft 傘下で、開発者を GitHub プラットフォームに囲い込むためのロスリーダー的な位置付け
- Pages 単体での収益化ではなく、Actions の有料分・Copilot・Enterprise 契約で回収する設計
- ハード制限を緩く敷くことで、「個人サイト + ドキュメント」用途に絞り、商用大規模配信は事実上できなくしている
2.4 ハード制限(公式値)
GitHub の公式 limits ページ(https://docs.github.com/en/pages/getting-started-with-github-pages/github-pages-limits )に書かれている上限はおおむね次のとおり。
- 公開サイトの最大サイズ: 1 GB
- 帯域: ソフトリミット 100 GB / month
- ビルド頻度: ソフトリミット 10 builds / hour(カスタム GitHub Actions workflow でビルドする場合は対象外)
- ビルドタイムアウト: 10 分でデプロイ失敗
- 配信: 静的のみ。サーバサイドコード実行は不可
加えて、Jekyll の plugin allowlist がある。_config.yml で plugins: に書ける 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 )。
- リポジトリの Pages 設定で Custom domain に
nikinakamura.comを入力 → リポジトリにCNAMEファイルが自動で commit される - registrar(または DNS プロバイダ)側で次のレコードを設定:
- apex: GitHub の 4 つの IP に A レコード(
185.199.108.153 / .109.153 / .110.153 / .111.153) www:niki-nakamura.github.io.への CNAME
- apex: GitHub の 4 つの IP に A レコード(
- GitHub 側で DNS check が通れば Enforce HTTPS をオンにする。Let's Encrypt 証明書が自動発行される
3. Cloudflare Pages の仕組み
3.1 push から配信までに何が起きているか
Cloudflare Pages は GitHub の Pages とは別物で、Cloudflare 自前のビルド基盤と CDN を使う(https://pages.cloudflare.com )。
- Git 連携で push を検知
- Cloudflare の build environment(コンテナ)で任意の SSG / framework を実行。Jekyll、Hugo、Astro、Next.js、Remix、SvelteKit、Nuxt など主要 framework は preset 済み
- 成果物を Cloudflare の グローバル CDN に push。Cloudflare の network は 337 都市、100+ 国に展開(https://www.cloudflare.com/network/ )
- 全 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 が権威サーバになる。
- HTTPS 証明書(Universal SSL)は自動発行・自動更新。Let's Encrypt と Google Trust Services をバックエンドに持つ
- HTTP/3、TLS 1.3、IPv6 はデフォルト on
- DNS 設定画面で各レコードに「Proxied」(オレンジ雲)か「DNS only」(グレー雲)を選べる。Proxied にすると Cloudflare の CDN / WAF / DDoS 防御を通る
3.3 なぜ無料なのか(重要)
Cloudflare Pages の無料プランには 帯域無制限・リクエスト無制限・サイト数無制限 が含まれる(https://pages.cloudflare.com )。これがなぜ事業として成立しているかは、彼ら自身が複数の blog で説明している。要点は次の 4 つ。
- コスト構造: Cloudflare は自前の世界規模 CDN(337 都市、世界人口の 95% から 50ms 以内)を持ち、固定費中心の事業モデル。1 ユーザー追加の限界費用がほぼゼロ
- 規模の経済: 無料ユーザーは Cloudflare のトラフィック量を底上げする。Cloudflare の営業資料で「世界 X% のトラフィックを処理」と言えるほど、商用顧客への価格交渉力が増す
- アップセル: Pages 自体は無料維持しつつ、Workers(サーバレス実行)、R2(オブジェクトストレージ)、D1(SQLite)、KV、Durable Objects、Images、Stream、Zero Trust などの周辺で課金する。Pages を入口として開発者を取り込む設計
- 対競合(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/ )。
- ビルド回数: 500 / month
- 同時ビルド: 1
- 1 ビルドあたりの最大時間: 20 分
- 1 サイトあたりのファイル数: 20,000
- 1 ファイルの最大サイズ: 25 MiB
- プロジェクトあたりカスタムドメイン: 100
- 帯域: 無制限
- リクエスト数: 無制限
別途、Workers を併用する場合のみ Workers 側の制限(free で 100,000 requests / day)がかかる。純粋な静的配信だけなら Workers 制限は無関係。
3.5 カスタムドメイン手順
- registrar で nameserver を Cloudflare のものに切り替え(DNS propagation で数分〜24 時間)
- Cloudflare Dashboard → Workers & Pages → 対象プロジェクト → Custom Domains →
nikinakamura.comとwww.nikinakamura.comを追加 - 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 を寄せる
- Cloudflare アカウントを作成 → Add a Site で
nikinakamura.comを追加 - Cloudflare が既存の DNS レコードを scan して候補を表示するので、レコードが正しいか確認(特に MX、TXT、CAA)
- registrar 側で nameserver を Cloudflare のもの(指示された 2 つの NS)に変更
- propagation を待つ(数分〜24 時間)。
dig NS nikinakamura.comで確認できる
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)を自動発行する。ここで動作確認する。注意点:
_config.ymlのbaseurl: /tilをルートドメイン公開時は 空文字列""に変える必要がある。さもないと CSS / リンクが全部 404 になるurl:もhttps://nikinakamura.comに書き換える- GitHub Pages と並行運用する間は、
baseurlを環境変数で切り替えるか、ブランチを分ける運用が安全
5.4 カスタムドメイン
Pages プロジェクト → Custom Domains → nikinakamura.com と www.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 つ。
jekyll-redirect-fromプラグイン(Pages allowlist 入り)で各ページに redirect ページを生成。生成される HTML は<meta http-equiv="refresh">とwindow.location.replace()を併用。SEO 的には 301 と同等に扱われる、というのが Google John Mueller の公式回答だが、強度は本物の 301 より弱い- トップ
index.htmlだけ手書きで meta refresh + canonical link rel + JS リダイレクトを入れる
実装は 1 で済ませるのが現実的。
5.6 SEO 引き継ぎ
- Google Search Console で新プロパティ
https://nikinakamura.com/を追加し、所有権確認(Cloudflare DNS なら TXT レコードで一発) - 新サイトの sitemap.xml を送信
- 旧プロパティ
niki-nakamura.github.io/til/は 残しておく。リダイレクトの認識状況やリンクの引き継ぎを確認するのに必要 - Change of Address ツールは使えない。これは「ドメイン全体の移行」用で、
example.github.io/til/のような subpath からの移行はカバーしない(https://support.google.com/webmasters/answer/9370220 ) - 結局は meta refresh / JS リダイレクト + 新サイト送信 + 旧サイトを残す、3〜6 ヶ月で自然に置き換わるのを待つ
5.7 GA4 / 計測
GA4 は計測 ID(G-XXXXXXXXXX)で動くので、タグ自体はそのまま動く。やることは:
- GA4 プロパティのウェブストリーム URL を
nikinakamura.comに書き換える - 旧 URL からのトラフィックも同じプロパティに流れ続けるので、移行期間中の比較がしやすい
- Referrer exclusion list に
nikinakamura.github.ioを入れて、自己リダイレクト経由のセッションを切らないようにする
5.8 DNS の落とし穴(重要)
nameserver を Cloudflare に切り替える瞬間、既存の DNS レコードは Cloudflare 側に登録したものに 完全に置き換わる。具体的には:
- MX レコード(メール)を引き継ぎ忘れると
*@nikinakamura.comが即死する - TXT(SPF / DKIM / DMARC)、CAA も同様に消える可能性
- Cloudflare の add site 時に scan される候補は完全ではなく、
digで各レコードを確認したほうがいい
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 の中で困っていない。
推奨は ハイブリッド構成:
- ドメインだけ先に Cloudflare DNS に乗せる: nameserver を Cloudflare に切り替え、DNS / WAF / DDoS 防御の恩恵だけ受ける
- ホスティングは GitHub Pages のまま:
nikinakamura.comを GitHub Pages のカスタムドメインとして設定する(apex は GitHub の 4 つの A レコード、wwwは CNAME) - Cloudflare 側は DNS only(グレー雲)か Proxied(オレンジ雲)かを選ぶ: Proxied にすると Cloudflare の CDN を経由するので、GitHub Pages のオリジン帯域を消費しにくくなる副次効果がある
これで「nikinakamura.com で自分のサイトが見える」を最小コストで達成できる。
本格的な Cloudflare Pages 移行は、次のいずれかが発生したときに考える。
- コンテンツが商業的に重要になり、エッジ最適化や A/B テストが必要になった
- Workers でメール capture、redirect logic、auth、edge-side rendering が必要になった
- GitHub Pages の plugin allowlist や 10 分ビルド上限に当たって、ローカルビルドや Actions に逃げているのが煩わしくなった
「無料の罠」は、無料同士の差別化要素(無制限帯域、Workers との統合)を 必要ないのに先取りして移行コストを払う こと。13 エントリの個人 TIL で「Cloudflare の方が速い」は計測上の差より移行 / 学習コストのほうが大きい。
参考・引用元
- GitHub Pages documentation — 公式ドキュメント, GitHub
- Cloudflare Pages documentation — 公式ドキュメント, Cloudflare
- Dependency versions for GitHub Pages — 公式ドキュメント, GitHub (Jekyll allowlist)
- RFC 9110: HTTP Semantics — 仕様書, IETF
- RFC 9112: HTTP/1.1 — 仕様書, IETF
- RFC 9113: HTTP/2 — 仕様書, IETF
- RFC 9114: HTTP/3 — 仕様書, IETF
- jekyll-redirect-from — OSS, Jekyll team
- Google Search Central: Change of Address — 公式ドキュメント, Google
- John Mueller on meta-refresh as 301 — サイト, Search Engine Roundtable
2026-05-18