目次
14 章

CloudFront で静的サイトを配信

AWS のグローバル CDN、CloudFront。Origin / Behavior / Cache Policy の流れ、S3 + CloudFront 静的ホスティングパターン、OAC で S3 を安全に隠す方法、そして無効化(invalidation)の運用の流れまで整理します。

第10章 S3 の静的ホスティング方式には限界があります。HTTPS ができず、ユーザーの近くでキャッシュもできず、カスタムドメインと SSL もすぐには付きません。この3つを一気に解くサービスが CloudFront です。

CloudFront は AWS の CDN (Content Delivery Network) です。全世界 600 ほどの Edge Location にキャッシュを置き、ユーザーに最も近い Edge が応答します。静的サイトだけでなく動的 API も通過させられます。

本章では CloudFront の構造から始め、S3 + CloudFront パターン、OAC、キャッシュポリシー、無効化まで一本に整理します。ここで使う ACM のリージョンルールは 第13章 ALB / NLB と ACM の延長であり、ドメイン接続は 第12章 Route 53 の Alias です。2部の EC2 / VPC / S3 / RDS / Route 53 / ALB / CloudFront という基本の道具箱が、本章で一つにまとまります。

CDN が解く問題 #

S3 静的サイトをそのまま使うと、次が良くありません。

問題CloudFront が解く機能
米国のユーザーがソウル S3 から受け取ると 200ms+Edge キャッシュで ms 応答
HTTPS が直接できないACM 証明書 + 自動 HTTPS
Egress 費用が高い ($0.09/GB)CloudFront → インターネット ($0.085/GB) + キャッシュ hit は無料
キャッシュヘッダー / 圧縮 / HTTP/2 / HTTP/3 を直接自動
WAF / Shield を直接CloudFront と統合
DDoSAWS Shield Standard で自動

S3 + CloudFront はすべての静的サイトの標準パターンです。

CloudFront の構造 #

CloudFront Distribution の構造
 ユーザー
  │ HTTPS request: example.com/path/to/asset.js
┌────────────────────────────────────┐
│       CloudFront Edge Location      │
│       (ユーザーに最も近い地点)         │
│                                      │
│    Cache を確認                         │
│      ├── HIT → キャッシュから応答             │
│      └── MISS                        │
└────────────────────────────────────┘
                │ MISS 時
        ┌────────────────────┐
        │   Cache Behavior   │
        │  (path マッチ / ポリシー)   │
        └────────┬───────────┘
            ┌────────┐
            │ Origin │  ← S3, ALB, EC2, Lambda Function URL ...
            └────────┘

核心となる構成要素は次のとおりです。

  • Distribution — 一束の設定です(ドメイン + 証明書 + 動作)。
  • Origin — キャッシュミス時に受け取る場所です(S3、ALB、ユーザードメインなど)。
  • Cache Behavior — path マッチとキャッシュポリシー、Origin マッチです。

Distribution を作る #

シンプルな CloudFront Distribution
aws cloudfront create-distribution \
  --origin-domain-name my-bucket.s3.ap-northeast-2.amazonaws.com \
  --default-root-object index.html

設定項目は次のとおりです。

オプション意味
Origin domainS3 バケットまたは ALB DNS または直接ドメイン
Default root object/ リクエスト時に送るファイル (index.html)
Alternate domain (CNAME)example.com, www.example.com
SSL certificateACM (必ず us-east-1)
Price classどの大陸の Edge まで使うか
LoggingS3 に access log を保存
WAFWeb ACL を連結

Price Class #

Price Class意味
All全世界のすべての Edge — 費用が最も高い
200米国 / 欧州 / アジア / 豪州
100米国 / 欧州 / イスラエル / 一部アジア — 最も安い

韓国 / 日本のユーザーだけなら 200 以上を推奨します。グローバルサービスは All です。

Origin — どこで受け取るか #

S3 Origin #

最もよくある場合です。静的サイト / 画像 / ビデオに使います。

S3 Origin
Origin: my-bucket.s3.ap-northeast-2.amazonaws.com
        (REST API endpoint, NOT the s3-website-... URL)

s3-website-* URL ではなく REST API URL を使います。そうしてこそ OAC で安全に保護できます。

Custom Origin (ALB / 任意の HTTP サーバー) #

ALB / EC2 / 外部サーバーも Origin になれます。このパターンは動的 API の加速用途です。

ALB Origin
Origin: my-alb-1234567890.elb.ap-northeast-2.amazonaws.com
HTTPS Port: 443
SSL Protocols: TLSv1.2, TLSv1.3
Origin Path: (なし または /api)

ALB → CloudFront → ユーザーのパターンは、WAF + Edge SSL termination + キャッシュの役割をします。

Lambda Function URL Origin #

Lambda が直接 Origin の役割をします。サーバーレスの静的 + 動的サイトに使います(第17章 Lambda 基礎)。

Origin Group — フェイルオーバー #

Primary Origin が死ぬと Secondary へ移ります。マルチリージョンの DR 構成です。

Cache Behavior — ルーティング + キャッシュポリシー #

同じ Distribution の中で path ごとに別の動作を与えられます。

Cache Behavior の役割
Path Pattern   | Origin | Cache Policy | TTL
---------------+--------+--------------+--------
/api/*         | ALB    | NoCaching    | 0
/static/*      | S3     | Optimized    | 1 day
default (*)    | S3     | Optimized    | 1 hour

処理順は path pattern のマッチ(具体的なものが先)で、マッチがなければ default へ行きます。

Cache Policy #

キャッシュの動作を定義します。AWS が提供する基本ポリシーとカスタムポリシーがあります。

基本 Cache Policy
CachingOptimized               ← 静的資産 (画像 / JS / CSS)
CachingOptimizedForUncompressedObjects  ← 圧縮されていない資産
CachingDisabled                ← API キャッシュしない
Elemental-MediaPackage         ← メディアストリーミング

キャッシュキー(何が違えば別のキャッシュ項目になるか)は次で決めます。

  • Query string — すべて / 一部 / なし
  • Header — どのヘッダーで区別するか
  • Cookie — どの cookie で区別するか
単純な静的資産のキャッシュキー
Query: 無視
Header: 無視 (または Accept, Accept-Encoding)
Cookie: 無視
言語 / デバイス分離 SSR のキャッシュキー
Query: すべて
Header: Accept-Language, CloudFront-Is-Mobile-Viewer
Cookie: session-id

Origin Request Policy #

Origin へ何を送るかを決めます。キャッシュキーとは別の概念です。

Cache PolicyOrigin Request Policy
何を決定キャッシュキー + TTLOrigin へ送るヘッダー / クエリ / cookie
効果キャッシュヒット率動的応答に何が影響するか

Response Headers Policy #

応答ヘッダーを自動で追加または修正します。Strict-Transport-SecurityX-Content-Type-Options のようなセキュリティヘッダーに使います。

推奨セキュリティヘッダー
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; ...

TTL — どれだけキャッシュするか #

キャッシュ TTL の基準は次のとおりです。

TTL役割
0キャッシュしません。すべてのリクエストが Origin へ
60 ~ 300 秒よく変わるコンテンツ (ニュースの見出し)
1 時間 ~ 1 日一般的な静的資産
1 年 (max-age=31536000)hashed filename (app.abc123.js)

Cache-Control ヘッダー #

Origin 応答の Cache-Control ヘッダーが優先します(Min/Default/Max TTL の中に入れば)。

Origin の Cache-Control 応答
Cache-Control: public, max-age=31536000, immutable   ← hashed asset (1年)
Cache-Control: public, max-age=300                   ← HTML ページ (5分)
Cache-Control: no-store                              ← キャッシュ絶対しない

運用の基準は次のとおりです。

  • HTML は短く(60s ~ 5min) — 新しいビルドを速く見せます。
  • JS / CSS / 画像 with hash は1年 + immutable — コンテンツが変われば新しいファイル名になります。
  • API は通常キャッシュしない(または短く)。

S3 + CloudFront パターン #

静的サイトの標準セットアップです。

S3 + CloudFront 標準パターン
ユーザー
example.com (Route 53 Alias) ──▶ CloudFront
                                    ▼ (OAC)
                                  S3 my-bucket  ← Public Access Block すべて ON
                                    ▼ Bucket Policy
                                  CloudFront だけに GetObject 許可

OAC — Origin Access Control #

旧方式は OAI (Origin Access Identity) です。新しい推奨方式は OAC です。

OAC の役割
- S3 の PAB すべて ON (public 絶対に不可)
- Bucket Policy が CloudFront の OAC だけを許可:

  {
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Principal": { "Service": "cloudfront.amazonaws.com" },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EXXXXXX"
        }
      }
    }]
  }

こうすると次のようになります。

  • S3 への直接アクセスはすべて遮断されます。s3.amazonaws.com/my-bucket/x で入ってくると 403 です。
  • CloudFront だけが通過します。Edge キャッシュを経てこそ応答します。
  • Egress 費用の削減とキャッシュ hit の加速、WAF の適用を同時に得ます。

OAI vs OAC #

OAI (旧方式)OAC (新方式)
認証方式CloudFront の仮想 IAM IdentitySigV4 署名
新リージョン / 機能部分サポートすべて
KMS-encrypted S3追加設定が必要滑らか
推奨マイグレーション検討新セットアップの基本

新セットアップは OAC を使い、旧方式は OAI を使っていてマイグレーションします。S3 の PAB と Bucket Policy は 第10章 S3 のセキュリティ評価順をそのまま従います。

無効化 (Invalidation) #

キャッシュされたオブジェクトを満了前に強制的に空にする動作です。デプロイ直後に新しいバージョンを即時に見せます。

Invalidation を作る
aws cloudfront create-invalidation \
  --distribution-id EXXXXXX \
  --paths "/*"

使う方式は次のとおりです。

  • 静的サイトのデプロイ後に /* を1回。
  • 特定のページだけ更新: /index.html /about.html
  • ワイルドカード: /blog/2026/*

費用の落とし穴 #

CloudFront の invalidation は最初の 1000 path が月無料で、その後は path あたり $0.005 です。/* 1回が 1 path なので、頻繁に呼び出しても大丈夫です。

Cache Versioning パターン — 無効化を使わない #

本当の運用では無効化を使いません。代わりに次のパターンを使います。

Hashed filename パターン
ビルド結果:
  /static/app.abc123.js   ← コンテンツハッシュ
  /static/app.def456.js   ← 次のビルドは別のハッシュ

HTML は短くキャッシュ (1分)、JS/CSS は1年:
  Cache-Control: public, max-age=31536000, immutable

新しいデプロイ時:
  /index.html が新しいハッシュの JS を指す
  HTML キャッシュ満了 (1分) → 新しい JS が自動ロード

このパターンなら invalidation なしで即時に反映しながら、キャッシュ効率を最大に維持します。

Lambda@Edge / CloudFront Functions #

Edge でリクエスト / 応答を横取りしてコードを実行する役割です。

CloudFront Functions #

  • JavaScript ES5 だけが使えます。
  • リクエスト / 応答の viewer 段階だけを処理します。
  • 5ms 以内、1MB 以内のメモリです。
  • 非常に安いです($0.10 / 百万)。
  • 用途は redirect、header 追加、A/B テスト、認証トークンの検査です。
シンプルな redirect
function handler(event) {
  var request = event.request;
  if (request.uri === '/old-page') {
    return {
      statusCode: 301,
      statusDescription: 'Moved Permanently',
      headers: { 'location': { value: '/new-page' } }
    };
  }
  return request;
}

Lambda@Edge #

  • Node.js / Python を使います。
  • 4段階(viewer request / origin request / origin response / viewer response)を処理します。
  • 5秒(viewer) / 30秒(origin)の限度です。
  • 高くて遅いですが強力です。
  • 用途は動的コンテンツの変換、マルチリージョンのルーティング、複雑な認証です。

最近は可能な限り CloudFront Functions で始め、足りないときにだけ Lambda@Edge を使います。

Signed URL / Signed Cookie — 非公開コンテンツ #

有料ビデオや専用ダウンロードのような場合に使います。CloudFront の署名で時間と IP を制限します。

Signed URL の形
https://d111111abcdef8.cloudfront.net/video.mp4?
  Expires=1714992000&
  Signature=...
  Key-Pair-Id=APKAEX...
  • Signed URL — 1つの資源に対する1つの URL です。
  • Signed Cookie — 1人のユーザーが複数の資源にアクセスします(サイト単位の定期購読)。

S3 の presigned URL とは異なります。CloudFront Edge で検証するので、よりグローバルでキャッシュが可能です。

CloudFront と ACM のリージョンルール #

第13章 ALB / NLB と ACM で扱った ACM のリージョンルールです。

CloudFront 証明書は常に us-east-1
ACM (us-east-1)
  ├── *.example.com         ← CloudFront が使用
  └── example.com

ACM (ap-northeast-2)
  ├── api.example.com       ← ALB が使用

コンソールで証明書を受け取るときは、必ず N. Virginia (us-east-1) へリージョンを切り替えます。

圧縮と HTTP/2 / HTTP/3 #

CloudFront が自動で処理します。

  • gzip / Brotli 圧縮 — オプションを ON にします。
  • HTTP/2 — デフォルトです。
  • HTTP/3 (QUIC) — オプションです。
  • TLS 1.3 — Security Policy で決めます。

この処理は ALB を直接露出するより CloudFront のほうが滑らかです。

よく出会う落とし穴 #

  • S3 が依然として Public — OAC をセットアップしたが PAB を ON にせず S3 が直接アクセス可能な場合です。PAB 4つをすべて ON にし、Bucket Policy が CloudFront だけを許可するようにします。
  • CNAME mismatch — ACM 証明書が *.example.com なのに Distribution の Alternate domain が app.example.com(ワイルドカードの子なので OK)の場合は大丈夫ですが、誤って埋め込むと SSL 証明書 mismatch エラーが出ます。証明書の SAN とドメインを正確に合わせます。
  • キャッシュが強すぎて新しいデプロイが見えないmax-age=31536000 の HTML をそのままキャッシュすると、新しいデプロイの後でもユーザーが旧 HTML を受け取ります。HTML は短く、hashed asset だけ長く置きます。
  • クエリのキャッシュキーが誤り — クエリをすべてキャッシュキーに入れると、同じファイルも ?v=1?v=2 ごとに別のキャッシュになりヒット率が 0% になります。本当に影響のあるクエリだけをキャッシュキーに入れます。
  • Default root object 欠落/ でリクエストすると 403/404 が出ます。Default root object を index.html に設定します。
  • Origin へ送る Host ヘッダー — S3 Origin は CloudFront が自動で Host ヘッダーを処理します。しかし ALB や任意のサーバーは Origin Request Policy で Host ヘッダーの転送オプションを明示します。
  • Origin の SSL 証明書が信頼されない — Custom Origin(自前のサーバー)が self-signed だと CloudFront が拒否します。ACM 発行の証明書や信頼された CA を使います。
  • index.html redirect ができない — S3 静的サイトの /about//about/index.html の自動変換が OAC 構成ではできません。CloudFront Function で path rewrite を直接行います。
path rewrite Function
function handler(event) {
  var request = event.request;
  var uri = request.uri;
  if (uri.endsWith('/')) {
    request.uri = uri + 'index.html';
  } else if (!uri.includes('.')) {
    request.uri = uri + '/index.html';
  }
  return request;
}

練習問題 #

  1. §「S3 + CloudFront パターン」の図を見ずに、ユーザーリクエストがドメインから S3 まで届く経路を、第12章 Route 53 の Alias から OAC、Bucket Policy まで順に書いてみてください。そして 第10章 S3 の静的ホスティングで ON にした public read ポリシーを、ここではなぜ逆に解除するのかを一文で説明してみてください。
  2. 新しいデプロイの後でもユーザーが旧画面を見るという報告が入りました。§「Cache Versioning パターン」を根拠に、無効化を毎回呼び出す代わりにどんなキャッシュ設定(HTML と hashed asset の TTL)を置くべきかを具体的に書いてみてください。
  3. CloudFront 証明書をソウルで発行してはいけない理由を §「CloudFront と ACM のリージョンルール」を根拠に書き、これが 第13章 ALB / NLB と ACM のリージョンマッピング表とどう一致するかをつなげてみてください。

一行まとめ: CloudFront は Edge 600 ほどでキャッシュ応答するグローバル CDN で、Distribution + Origin + Cache Behavior で構成される。S3 + CloudFront + OAC が静的サイトの標準パターンで、このとき S3 の PAB 4つをすべて ON にし、Bucket Policy で CloudFront だけを許可する。TTL は HTML 短く hashed asset 1年が定石なので無効化なしで即時に反映され、CloudFront 証明書は常に us-east-1 で発行する。

次の章 #

これで2部の EC2 / VPC / S3 / RDS / Route 53 / ALB / CloudFront という基本の道具箱が一つにまとまりました。次の 第15章 ECS と Fargate から始まる3部では、その上にコンテナ / サーバーレス / イベント駆動の領域を加えます。EC2 の上に直接アプリを立ち上げていた方式をコンテナへ移し、ASG のコンテナ版である ECS / Fargate の運用を整理します。

X