【AWS】CloudFrontのキャッシュ設定完全ガイド|TTL・invalidation・キャッシュポリシーの使い分け
はじめに
CloudFrontは高速なコンテンツ配信が魅力ですが、キャッシュの設定を誤るとコンテンツが更新されない、あるいはキャッシュが効かずオリジンへのリクエストが増えるという問題が起きます。
私自身、このブログをS3 + CloudFront構成で運用しており、記事を更新してもブラウザに古いページが表示される問題や、Invalidationのコストを気にしながら設定を調整した経験があります。
この記事では、CloudFrontのキャッシュの仕組みからTTL設定、キャッシュポリシー、Invalidationの使い方まで、実務で役立つ知識を整理します。
CloudFrontのキャッシュの仕組み
CloudFrontはエッジロケーションにコンテンツをキャッシュし、ユーザーへ近いロケーションから配信します。
リクエストが来たとき、CloudFrontは次の順序で処理します。
- エッジキャッシュにコンテンツが存在するか確認(キャッシュヒット)
- キャッシュがなければオリジン(S3やEC2など)へ取得しに行く(キャッシュミス)
- オリジンから取得したコンテンツをエッジにキャッシュして返す
キャッシュヒット率(Cache Hit Ratio)が高いほどオリジンへの負荷が下がり、レスポンスも速くなります。
キャッシュキーとは
CloudFrontはデフォルトでURLのパス部分をキャッシュキーとして使います。同じURLへのリクエストはキャッシュから返されます。
クエリ文字列・ヘッダー・Cookieをキャッシュキーに含めることもできますが、含めるほどキャッシュヒット率が下がるため注意が必要です。
TTL設定の種類
TTL(Time To Live)はキャッシュの有効期間です。CloudFrontでは3種類のTTLを設定できます。
| 設定 | 意味 | デフォルト値 |
|---|---|---|
| Minimum TTL | キャッシュの最短保持時間 | 0秒 |
| Maximum TTL | キャッシュの最長保持時間 | 31536000秒(1年) |
| Default TTL | オリジンがCache-Controlを返さない場合のTTL | 86400秒(1日) |
オリジンのCache-Controlヘッダーとの関係
オリジン(S3など)が Cache-Control: max-age=3600 を返している場合、CloudFrontはその値を尊重しますが、TTLの範囲内に丸められます。
オリジンのmax-age=3600(1時間)
→ Minimum TTL=0, Maximum TTL=86400 の場合
→ CloudFrontは3600秒キャッシュする(オリジンの指定を尊重)
オリジンのmax-age=0(キャッシュなし)
→ Minimum TTL=0 の場合
→ CloudFrontはキャッシュしない
オリジンがCache-Controlを返さない場合
→ Default TTL(86400秒)が使われる
S3静的サイトでの推奨設定
S3で静的サイトをホストしている場合、ファイルの種類によってTTLを使い分けるのがベストプラクティスです。
| ファイル種別 | Cache-Control設定 | 理由 |
|---|---|---|
| HTML | max-age=0, must-revalidate | 記事更新がすぐ反映されるように |
| CSS / JS(ハッシュ付き) | max-age=31536000, immutable | ファイル名が変わるので長期キャッシュOK |
| 画像 | max-age=2592000(30日) | 頻繁に変わらないが長すぎも避ける |
| sitemap.xml | max-age=3600(1時間) | クロール頻度に合わせて短めに |
S3にオブジェクトをアップロードする際、メタデータで Cache-Control を指定できます。AWS CLIでは次のように設定できます。
aws s3 cp index.html s3://your-bucket/ \\
--cache-control "max-age=0, must-revalidate" \\
--content-type "text/html"
キャッシュポリシーの設定方法
CloudFrontのビヘイビア(Behavior)にはキャッシュポリシーを関連付けます。マネージドポリシーを使うか、カスタムポリシーを作成する方法があります。
AWSマネージドポリシー
よく使うマネージドポリシーは以下の通りです。
| ポリシー名 | TTL | 用途 |
|---|---|---|
| CachingOptimized | Default 86400秒 | S3静的サイト(デフォルト推奨) |
| CachingDisabled | 0秒 | キャッシュを無効にしたいAPI等 |
| CachingOptimizedForUncompressedObjects | Default 86400秒 | 圧縮非対応のオリジン向け |
S3の静的サイトには CachingOptimized がデフォルトで最適です。
カスタムキャッシュポリシーの作成
AWSコンソール → CloudFront → ポリシー → キャッシュポリシー → ポリシーを作成 から設定できます。
設定項目:
- 名前: 識別しやすい名前(例:
static-site-html) - デフォルトTTL / 最小TTL / 最大TTL: 前述の値を設定
- キャッシュキーの設定: クエリ文字列・ヘッダー・Cookieの含め方
静的サイトでHTMLだけキャッシュを短くしたい場合は、HTMLパス用のビヘイビアを別途作成してカスタムポリシーを当てるのが効果的です。
Invalidationの使い方とコスト
Invalidation(キャッシュ無効化)はエッジキャッシュを強制的に削除する機能です。コンテンツを更新したのにユーザーに反映されないときに使います。
Invalidationのコスト
最初の1,000パスは毎月無料です。それを超えると1パスあたり$0.005かかります。
/articles/laravel/artisan-key-generate/ → 1パス
/articles/laravel/* → 1パス(ワイルドカード)
/* → 1パス(全体)
ワイルドカード /* は1パスとしてカウントされるため、全体を一括無効化する場合もコストは最小です。
AWSコンソールからの実行
- CloudFront → ディストリビューションを選択
- 「Invalidations」タブ → 「Create invalidation」
- パスを入力(例:
/*または/articles/laravel/artisan-key-generate/)
AWS CLIからの実行
# 特定パスを無効化
aws cloudfront create-invalidation \\
--distribution-id YOUR_DISTRIBUTION_ID \\
--paths "/articles/laravel/artisan-key-generate/*"
# 全体を無効化
aws cloudfront create-invalidation \\
--distribution-id YOUR_DISTRIBUTION_ID \\
--paths "/*"
Invalidationが完了するまでの時間
通常1〜5分程度で完了しますが、エッジロケーションの数によっては数分かかることもあります。AWSコンソールの「Invalidations」タブでステータスを確認できます。
S3静的サイトでの実践的な設定例
私がこのブログで採用している構成をベースにした設定例を紹介します。
構成
ユーザー → CloudFront → S3(静的ホスティング)
ビヘイビアの分け方
| パスパターン | キャッシュポリシー | TTL設定 |
|---|---|---|
*.html または / | カスタム(短期) | Default 0秒 |
*.css, *.js | CachingOptimized | Default 86400秒 |
*.jpg, *.png, *.webp | CachingOptimized | Default 86400秒 |
/sitemap*.xml | カスタム(中期) | Default 3600秒 |
HTMLをキャッシュしない(TTL=0)設定にしておくと、記事を更新してSimply Staticでエクスポート → S3にアップロードすれば即時反映されます。InvalidationはHTMLをキャッシュする構成にしている場合のみ必要になります。
CloudFront Functionsでのindex.html補完
S3をオリジンとして使う場合、/articles/laravel/artisan-key-generate/ のようなディレクトリ形式のURLにアクセスすると AccessDenied が返ります。
これはCloudFront Functionsで解決できます。
function handler(event) {
var request = event.request;
var uri = request.uri;
// 末尾がスラッシュで終わる場合はindex.htmlを補完
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// 拡張子がない場合もindex.htmlを補完
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
このFunctionsを「ビューワーリクエスト」イベントに関連付けることで、すべてのディレクトリURLが正常に解決されます。
まとめ
CloudFrontのキャッシュ設定は、コンテンツの種類と更新頻度に合わせて使い分けることが重要です。
| 項目 | ポイント |
|---|---|
| TTL | HTMLは短く(0)、CSS/JSは長く(1年)が基本 |
| キャッシュポリシー | S3静的サイトはCachingOptimizedが最適 |
| キャッシュキー | クエリ文字列・ヘッダーを増やすとヒット率が下がる |
| Invalidation | 月1,000パスまで無料。/* で全体無効化が手軽 |
| Cache-Control | オリジン側で設定するとCloudFrontが尊重する |
静的サイトであればHTMLのTTLを0にしてInvalidation不要な構成にするのが、運用コストが最も低くおすすめです。

