AWS中級 #7 CloudFront で静的サイトを配信
#3 S3 の静的ホスティングで 1 つの限界を見ました — HTTPS が直接できず、ユーザーに近いキャッシュもなく、カスタムドメイン + SSL も無理。その 3 つを一気に解く場が CloudFront です。
CloudFront は AWS の CDN (Content Delivery Network)。世界中 600+ 箇所の Edge Location にキャッシュを置き、ユーザーから最も近い Edge が応答します。静的サイトだけでなく動的 API も通せる万能なサービスです。
この記事では CloudFront の形 → S3 + CloudFront パターン → OAC → キャッシュポリシー → 無効化を 1 本の線で通していきます。
CDN が解く問題 #
S3 静的サイトをそのまま使うと次が悪くなります。
| 問題 | CloudFront が解く場 |
|---|---|
| 米国ユーザーがソウル S3 から取得すると 200ms+ | Edge キャッシュで ms 応答 |
| HTTPS が直接できない | ACM 証明書 + 自動 HTTPS |
| Egress 費用が高い ($0.09/GB) | CloudFront → インターネット ($0.085/GB) + キャッシュヒットは無料 |
| キャッシュヘッダー / 圧縮 / 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 │
│ (ユーザーに最も近い場所) │
│ │
│ キャッシュ確認 │
│ ├── HIT → キャッシュから応答 │
│ └── MISS │
└────────────────────────────────────┘
│ MISS 時
▼
┌────────────────────┐
│ Cache Behavior │
│ (path マッチ / ポリシー)│
└────────┬───────────┘
▼
┌────────┐
│ Origin │ ← S3、ALB、EC2、Lambda Function URL ...
└────────┘中心の場 3 つ:
- 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 にアクセスログを保存 |
| 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 であり、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 の場。サーバーレス静的 + 動的サイト。
Origin Group — failover #
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 — どのクッキーで分けるか
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 に送るヘッダー / クエリ / クッキー |
| 効果 | キャッシュヒット率 | 動的応答に何が影響するか |
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 / hash 付き画像 = 1 年 + immutable — 内容が変われば新ファイル名
- API = 通常キャッシュなし (または short)
S3 + CloudFront パターン #
静的サイトの標準セットアップ。
ユーザー
│
▼
example.com (Route 53 Alias) ──▶ CloudFront
│
▼ (OAC)
S3 my-bucket ← Public Access Block すべて有効
│
▼ Bucket Policy
CloudFront のみ GetObject 許可OAC — Origin Access Control #
旧式は OAI (Origin Access Identity)。新推奨は OAC。
- S3 の PAB をすべて有効 (絶対 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 費用削減 + キャッシュヒット高速化 + WAF 適用
OAI vs OAC #
| OAI (旧) | OAC (新) | |
|---|---|---|
| 認証方式 | CloudFront の仮想 IAM Identity | SigV4 署名 |
| 新リージョン / 機能 | 部分対応 | すべて対応 |
| KMS-encrypted S3 | 追加設定が必要 | なめらか |
| 推奨 | 移行を検討 | 新規のデフォルト |
新規セットアップは OAC、旧は OAI のまま使いつつ移行。
無効化 (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 なので頻繁に呼んでも OK。
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 / 100 万)
- 用途: redirect、ヘッダー追加、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 の場 #
#6 で扱った 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 圧縮 — オプション有効化
- HTTP/2 — デフォルト
- HTTP/3 (QUIC) — オプション
- TLS 1.3 — Security Policy で
この場は ALB 直接公開より CloudFront の方がなめらか。
よくハマる罠 #
1) S3 がいまだに Public #
OAC をセットアップしたのに PAB を有効化せず、S3 が直接アクセス可能 — PAB 4 つすべて有効化 + Bucket Policy が CloudFront のみ許可。
2) CNAME mismatch #
ACM 証明書が *.example.com なのに Distribution の Alternate domain が app.example.com (ワイルドカード子なので OK) — 誤って書くと SSL 証明書 mismatch エラー。証明書 SAN とドメインを正確に揃える。
3) キャッシュが強すぎて新デプロイが見えない #
max-age=31536000 の HTML をそのままキャッシュ → 新デプロイ後もユーザーが旧 HTML を取得。HTML は短く / hashed asset だけ長く。
4) クエリのキャッシュキーが誤っている #
クエリ全部をキャッシュキーに → 同じファイルでも ?v=1、?v=2 ごとに別キャッシュ → ヒット率 0%。本当に影響するクエリだけキャッシュキーに。
5) Default root object 抜け #
/ でリクエストすると 403/404。Default root object = index.html を設定。
6) Origin に送る Host ヘッダー #
S3 Origin の場合 CloudFront が自動で Host ヘッダーを処理。だが ALB / 任意サーバーは Origin Request Policy で Host ヘッダーを伝達 する場を明示。
7) Origin の SSL 証明書が信頼されない #
Custom Origin (自前サーバー) が self-signed → CloudFront が拒否。ACM 発行証明書または信頼された CA を。
8) index.html redirect
#
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;
}まとめ #
今回押さえたこと:
- CloudFront = グローバル CDN。Edge 600+ 箇所でキャッシュ応答
- Distribution + Origin + Cache Behavior の 3 つ
- Origin = S3 / ALB / Custom HTTP / Lambda URL / Origin Group
- S3 + CloudFront + OAC が静的サイト標準パターン
- OAC が新推奨。PAB 4 つすべて有効化、Bucket Policy で CloudFront のみ許可
- Cache Policy でキャッシュキー (クエリ/ヘッダー/クッキー) + TTL。Origin Request Policy は Origin へ送る場
- TTL 戦略 — HTML 短く、hashed asset 1 年 + immutable
- 無効化 はたまに。Hashed filename パターン が無効化を使わない道
- CloudFront Functions = 速くて安い。Lambda@Edge = 強力だが重い
- Signed URL / Cookie で非公開コンテンツ
- ACM 証明書は必ず
us-east-1 - 圧縮 / HTTP/2 / HTTP/3 が自動
- 罠 — S3 public、CNAME mismatch、キャッシュ強すぎ、クエリキー誤り、default root、Host ヘッダー、Origin SSL、path rewrite
次回 — AWS 上級スタート #
これで AWS 中級 7 編 が締めくくられました。EC2 / VPC / S3 / RDS / Route 53 / ALB / CloudFront という基本道具箱が一所にそろいました。
ここから上に コンテナ / サーバーレス / イベント駆動 の場が積み上がります。AWS 上級 #1 ECS と Fargate では、EC2 上に直接アプリを乗せていた場をコンテナへ移し、ASG のコンテナ版である ECS / Fargate の運用を整理します。