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 と統合 |
| DDoS | AWS Shield Standard で自動 |
S3 + CloudFront はすべての静的サイトの標準パターンです。
CloudFront の構造 #
ユーザー
│
│ 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 を作る #
aws cloudfront create-distribution \
--origin-domain-name my-bucket.s3.ap-northeast-2.amazonaws.com \
--default-root-object index.html設定項目は次のとおりです。
| オプション | 意味 |
|---|---|
| Origin domain | S3 バケットまたは ALB DNS または直接ドメイン |
| Default root object | / リクエスト時に送るファイル (index.html) |
| Alternate domain (CNAME) | example.com, www.example.com |
| SSL certificate | ACM (必ず us-east-1) |
| Price class | どの大陸の Edge まで使うか |
| Logging | S3 に access log を保存 |
| WAF | Web ACL を連結 |
Price Class #
| Price Class | 意味 |
|---|---|
| All | 全世界のすべての Edge — 費用が最も高い |
| 200 | 米国 / 欧州 / アジア / 豪州 |
| 100 | 米国 / 欧州 / イスラエル / 一部アジア — 最も安い |
韓国 / 日本のユーザーだけなら 200 以上を推奨します。グローバルサービスは All です。
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 の加速用途です。
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 ごとに別の動作を与えられます。
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 が提供する基本ポリシーとカスタムポリシーがあります。
CachingOptimized ← 静的資産 (画像 / JS / CSS)
CachingOptimizedForUncompressedObjects ← 圧縮されていない資産
CachingDisabled ← API キャッシュしない
Elemental-MediaPackage ← メディアストリーミングキャッシュキー(何が違えば別のキャッシュ項目になるか)は次で決めます。
- Query string — すべて / 一部 / なし
- Header — どのヘッダーで区別するか
- Cookie — どの cookie で区別するか
Query: 無視
Header: 無視 (または Accept, Accept-Encoding)
Cookie: 無視Query: すべて
Header: Accept-Language, CloudFront-Is-Mobile-Viewer
Cookie: session-idOrigin Request Policy #
Origin へ何を送るかを決めます。キャッシュキーとは別の概念です。
| Cache Policy | Origin Request Policy | |
|---|---|---|
| 何を決定 | キャッシュキー + TTL | Origin へ送るヘッダー / クエリ / cookie |
| 効果 | キャッシュヒット率 | 動的応答に何が影響するか |
Response Headers Policy #
応答ヘッダーを自動で追加または修正します。Strict-Transport-Security、X-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 の中に入れば)。
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 パターン #
静的サイトの標準セットアップです。
ユーザー
│
▼
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 です。
- 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 Identity | SigV4 署名 |
| 新リージョン / 機能 | 部分サポート | すべて |
| KMS-encrypted S3 | 追加設定が必要 | 滑らか |
| 推奨 | マイグレーション検討 | 新セットアップの基本 |
新セットアップは OAC を使い、旧方式は OAI を使っていてマイグレーションします。S3 の PAB と Bucket Policy は 第10章 S3 のセキュリティ評価順をそのまま従います。
無効化 (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 パターン — 無効化を使わない #
本当の運用では無効化を使いません。代わりに次のパターンを使います。
ビルド結果:
/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 テスト、認証トークンの検査です。
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 を制限します。
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 のリージョンルールです。
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.htmlredirect ができない — S3 静的サイトの/about/→/about/index.htmlの自動変換が OAC 構成ではできません。CloudFront Function で path rewrite を直接行います。
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;
}練習問題 #
- §「S3 + CloudFront パターン」の図を見ずに、ユーザーリクエストがドメインから S3 まで届く経路を、第12章 Route 53 の Alias から OAC、Bucket Policy まで順に書いてみてください。そして 第10章 S3 の静的ホスティングで ON にした public read ポリシーを、ここではなぜ逆に解除するのかを一文で説明してみてください。
- 新しいデプロイの後でもユーザーが旧画面を見るという報告が入りました。§「Cache Versioning パターン」を根拠に、無効化を毎回呼び出す代わりにどんなキャッシュ設定(HTML と hashed asset の TTL)を置くべきかを具体的に書いてみてください。
- 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 の運用を整理します。