ブラウザキャッシュとCloudflareキャッシュは別物:Cache-Control、Edge TTL、公開後の更新

ブラウザキャッシュとCloudflareエッジキャッシュの違いから、Cache-Control、max-age、s-maxage、Edge TTL、Browser TTL、purge allの関係、静的ブログでのキャッシュ設定を整理する。

Cloudflareのキャッシュを設定するとき、最も混同しやすいのは次の2つです。

  • Cloudflareのエッジノードがどれだけ長くキャッシュするか。
  • ユーザーのブラウザがローカルでどれだけ長くキャッシュするか。

どちらもキャッシュですが、制御している層が違い、リスクも違います。

静的ブログでは、Cloudflareのエッジキャッシュは少し攻めてもよく、ブラウザキャッシュは控えめにするのが安定します。Cloudflareのキャッシュは管理画面やAPIで削除できますが、ユーザーのローカルブラウザキャッシュはサイト管理者が直接消せないからです。

まず三層を分ける

1回のアクセスは、おおよそ次の三層を通ります。

1
2
3
4
5
ブラウザ
Cloudflare エッジノード
VPS / Nginx / Hugo 静的ファイル

重要なキャッシュは主に2種類あります。

  • Browser cache:ユーザーの端末上に保存されるブラウザキャッシュ。
  • Edge cache:Cloudflareのエッジノード上に保存されるキャッシュ。

オリジンのNginxが返すCache-Controlはブラウザに影響し、CDNにも影響する場合があります。CloudflareのCache RulesではEdge TTLとBrowser TTLを別々に設定できます。さらにResponse Header Transform Rulesを使えば、最終的にブラウザへ返すレスポンスヘッダーも書き換えられます。層を分けて考えないと、「キャッシュを設定した」と思っても、実際には一部しか制御できていないことがあります。

Cache-Controlは誰を制御するのか

Cloudflareの学習センターでは、Cache-Controlをブラウザや中間キャッシュにリソースの扱い方を伝えるHTTPレスポンスヘッダーとして説明しています。

よくある例です。

1
Cache-Control: public, max-age=300

このレスポンスはキャッシュ可能で、ブラウザは最大300秒間新鮮なものとして扱えます。

1
Cache-Control: private

これはブラウザのようなプライベートキャッシュにだけ適しており、CDNのような共有キャッシュには保存すべきではない、という意味です。

1
Cache-Control: no-store

どこにもキャッシュしない、という意味です。非常に機密性の高いデータに向いています。

1
Cache-Control: no-cache

名前は少し紛らわしいです。完全にキャッシュしないという意味ではなく、キャッシュを使う前にサーバーへ更新確認が必要という意味です。通常はETagLast-Modifiedと組み合わせます。

1
Cache-Control: s-maxage=86400

s-maxageはCDNなどの共有キャッシュ向けです。ブラウザはmax-ageなどに従いつつ、CDNだけをより長くキャッシュさせることができます。

つまり、Cache-Controlはブラウザ専用でもCDN専用でもありません。キャッシュに関する指示の集合であり、どの層が採用し、どの層が上書きするかは中間設定次第です。

Cloudflare Edge TTLとBrowser TTLの違い

Cloudflareの2つのTTLは分けて見ます。

Edge TTLは、Cloudflareエッジノードがどれだけ長くキャッシュするかを決めます。

たとえば:

1
Cloudflare Edge TTL = 1 day

これは、Cloudflareがページ、画像、CSS、JSなどをエッジノードに1日保存できるという意味です。訪問者が同じURLを再度リクエストしたとき、キャッシュが命中すればCloudflareが直接返し、VPSへ戻りません。

Browser TTLは、ブラウザがどれだけ長くキャッシュするかを決めます。

たとえば:

1
Browser TTL = 5 minutes

これは、ブラウザがリソースを受け取ったあと、最大5分間ローカルで新鮮なものとして扱えるという意味です。5分以内ならローカルキャッシュを直接使うことがあります。5分を過ぎると、再検証または再リクエストが必要になります。

最大の違いは次の点です。

  • Edge cacheはサイト管理者がpurgeできる。
  • Browser cacheはユーザーのPC内にあり、サイト管理者は直接消せない。

そのため、HTMLページに長いブラウザTTLを付けるのはおすすめしません。記事を更新してCloudflareをpurgeしても、ユーザーのブラウザがローカルの古いページを表示し続ける可能性があります。

静的ブログでHTMLをキャッシュできる理由

動的サイトではHTMLを安易にキャッシュできません。ページにログイン状態、ユーザープロフィール、カート、推薦内容、権限情報などが含まれる可能性があるからです。

静的ブログは違います。Hugoが生成するページは通常、純粋な静的ファイルです。

  • ホームページ。
  • 記事ページ。
  • カテゴリページ。
  • タグページ。
  • 多言語ページ。
  • RSS。
  • sitemap。

これらは基本的にすべての訪問者に同じ内容を返すため、CloudflareでHTMLをキャッシュできます。これによりオリジンへのリクエストを減らし、海外からのアクセスも速くできます。

重要なのは次の考え方です。

1
2
Cloudflare Edge は長めでもよい
ブラウザ Browser は短めにする

例:

1
2
Cloudflare Edge TTL = 1 day
Browser TTL = 5 minutes

Cloudflareは1日キャッシュできますが、ユーザーのブラウザは5分だけキャッシュします。

毎回purge allするならEdge TTLは長めにできる

デプロイスクリプトが毎回Cloudflareのpurge everythingを呼ぶなら、Edge TTLは長めにできます。

流れはこうです。

1
2
3
通常時:Cloudflareが1日キャッシュして回源を減らす
公開時:新しいpublicをアップロードしてpurge all
公開後:Cloudflareがオリジンから新しい内容を取得する

この方式は静的ブログに向いています。サイト内容はリアルタイムに変わらず、更新もデプロイ時に集中するからです。

Edge TTLは1日でも1か月でも構いません。違いは主にリスク許容度です。

  • 1 day:purgeに失敗しても、古い内容は最大1日で自然に切れる。
  • 1 month:キャッシュヒット率は高いが、purge失敗時に古い内容が長く残る可能性がある。

個人ブログなら、まず1 dayから始めるほうが無難です。

ブラウザも長期キャッシュにしない理由

ブラウザキャッシュが長いほど再訪問は速くなりますが、更新制御は難しくなります。

たとえばHTMLに次を設定するとします。

1
Cache-Control: public, max-age=31536000

ユーザーが記事ページを一度訪問すると、ブラウザはそのページを1年間新鮮と見なす可能性があります。その後に誤字修正、リンク更新、本文修正をしてCloudflareをpurgeしても、そのユーザーのローカルキャッシュには効かない場合があります。

静的アセットを長期キャッシュできるのは、多くの場合フィンガープリント付きファイル名だからです。

1
2
/scss/style.min.5e5f1f8f7ce389becd0a48fe3eff3e1c79b2750a903584200a3a6fc54ae1e664.css
/ts/main.9acdcb7a78e911f2c617b8cd4af2eab573c04169dddc51c052977dde63210ced.js

内容が変わればファイル名も変わるため、古いキャッシュは新しいページが参照する新ファイルに影響しません。

しかしHTMLのURLは通常変わりません。

1
/2026/06/13/browser-cache-vs-cloudflare-edge-cache/

そのため、HTMLには短いブラウザTTLが向いています。

シンプルな設定例

ファイル種別ごとに細かく分けたくないなら、統一ポリシーで始められます。

1
2
3
Cloudflare Edge TTL = 1 day
Browser TTL = 5 minutes
毎回公開時に purge everything

Cloudflare Cache Ruleがエッジキャッシュを担当します。

1
(http.host in {"knightli.com" "www.knightli.com"} and not starts_with(http.request.uri.path, "/cdn-cgi/"))

動作:

1
2
3
4
Eligible for cache
Edge TTL: 1 day
Browser TTL: 5 minutes
Query string: ignore

オリジンのNginxがCSS、JS、画像に長いCache-Controlを設定していて、ブラウザへ返すすべてのリソースを5分に統一したい場合は、CloudflareにResponse Header Transform Ruleを追加します。

1
2
3
4
5
Set:
Cache-Control: public, max-age=300

Remove:
Expires

これで次の形になります。

  • EdgeキャッシュはCloudflare Cache Ruleで制御する。
  • BrowserキャッシュはCloudflareのレスポンスヘッダールールで統一する。
  • NginxはブラウザTTL統一のために変更しなくてよい。

分層キャッシュが必要になる場合

より高い性能を狙うなら、リソース種別ごとに分けられます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
HTML:
  Edge TTL: 1 day
  Browser TTL: 5 minutes

CSS / JS / 画像 / フォント:
  Edge TTL: 1 month
  Browser TTL: 1 month または 1 year

RSS / sitemap:
  Edge TTL: 1 hour
  Browser TTL: 5 minutes

この構成はより効率的ですが、維持コストも上がります。個人ブログなら最初からここまで複雑にする必要はありません。

すべての静的アセットにhash付きファイル名があることを確認してから、CSS、JS、画像のBrowser TTLを長くすると安定します。

有効かどうかを確認する

curl -Iで同じURLを連続してリクエストします。

1
2
curl.exe -I https://knightli.com/
curl.exe -I https://knightli.com/

見るべきヘッダーは2つです。

1
2
cf-cache-status: HIT
cache-control: public, max-age=300

cf-cache-status: HITはCloudflareエッジキャッシュに命中したことを示します。

cache-control: public, max-age=300は、ブラウザ側のキャッシュTTLが最大300秒であることを示します。

もし次が出た場合:

1
cf-cache-status: MISS

初回アクセス、purge直後、ルール未反映、またはキャッシュ条件に合っていない可能性があります。再度リクエストするとHITになることがよくあります。

CSSやJSでまだ次が見える場合:

1
cache-control: public, max-age=31536000, immutable

ブラウザキャッシュヘッダーがまだオリジン、またはより優先度の高いルールから来ています。静的アセットの長期キャッシュを受け入れるか、Cloudflare Response Header Transform Ruleで上書きします。

まとめ

ブラウザキャッシュとCloudflareキャッシュは同じものではありません。

実用的な判断は次の通りです。

  • Cloudflare Edgeキャッシュは攻めてもよい。サイト管理者がpurgeできるから。
  • ブラウザキャッシュは慎重にする。ユーザーのローカルキャッシュは消せないから。
  • HTMLページには短いBrowser TTLが向いている。
  • hash付き静的アセットには長いBrowser TTLを使える。
  • 毎回公開時にpurge allする静的ブログでは、Edge TTL 1日は安定した出発点になる。

Hugoの静的ブログなら、まず次の設定で十分です。

1
2
3
Cloudflare Edge TTL = 1 day
Browser TTL = 5 minutes
毎回公開時に purge everything

これだけでCDNによる高速化の大部分を得られ、記事更新後に古いHTMLがユーザーのブラウザに長く残る問題も避けやすくなります。

参考リンク

记录并分享
Hugo で構築されています。
テーマ StackJimmy によって設計されています。