Docs
/
AWS Cloud
Chapter 10

10 — CloudFront & CDN

What is CloudFront?

AWS Content Delivery Network — caches content at 400+ edge locations worldwide for fast delivery.

Without CDN:
  User (Tokyo) → Origin (us-east-1): 200ms

With CloudFront:
  User (Tokyo) → Edge (Tokyo): 10ms    ← cache hit
  User (Tokyo) → Edge → Origin: 200ms  ← cache miss (first request only)

How It Works

┌──────────┐     ┌──────────────┐     ┌─────────────┐
│  Client   │ ──→ │ CloudFront   │ ──→ │   Origin    │
│ (browser) │     │ Edge Location│     │ S3 / ALB /  │
└──────────┘     └──────────────┘     │ API Gateway │
                   Cache hit? ✅       └─────────────┘
                   Return cached        Only on cache miss

Distribution Setup

# Origins: where CloudFront fetches content from
# - S3 bucket (static files)
# - ALB / EC2 (dynamic API)
# - API Gateway
# - Custom HTTP server

# Behaviors: rules for how to cache
# /api/*     → ALB origin, no caching
# /static/*  → S3 origin, cache 1 year
# /*         → S3 origin, cache 1 day

Cache Control

Cache-Control headers from origin:

Cache-Control: public, max-age=31536000    → Cache 1 year (static assets)
Cache-Control: no-cache                     → Revalidate every request
Cache-Control: no-store                     → Never cache
Cache-Control: private, max-age=0           → Don't cache (user-specific)

Cache Key

CloudFront caches based on:

  • URL path
  • Query strings (configurable: none, whitelist, all)
  • Headers (configurable)
  • Cookies (configurable)
/api/users?page=1  → different cache entry than
/api/users?page=2

Tip: Only include necessary query strings in cache key
     to maximize cache hit ratio

Invalidation

Force CloudFront to re-fetch from origin.

# Invalidate specific paths
aws cloudfront create-invalidation \
  --distribution-id E1234567890 \
  --paths "/index.html" "/static/app.js"

# Invalidate everything
aws cloudfront create-invalidation \
  --distribution-id E1234567890 \
  --paths "/*"

# Better approach: use versioned filenames
# /static/app.abc123.js → never needs invalidation
# Change filename on each deploy (handled by webpack/vite hash)

Lambda@Edge / CloudFront Functions

Run code at edge locations.

CloudFront FunctionsLambda@Edge
RuntimeJavaScriptNode.js, Python
Execution time< 1msUp to 30s
Memory2 MB128-10240 MB
Network accessNoYes
Cost1/6th of Lambda@EdgeHigher
Use casesURL rewrites, header manipulation, redirectsAuth, A/B testing, dynamic content
// CloudFront Function: URL rewrite for SPA
function handler(event) &#123;
  var request = event.request;
  var uri = request.uri;

  // SPA: serve index.html for all non-file routes
  if (!uri.includes('.')) &#123;
    request.uri = '/index.html';
  &#125;
  return request;
&#125;

Signed URLs / Signed Cookies

Restrict access to private content.

import &#123; getSignedUrl &#125; from '@aws-sdk/cloudfront-signer';

const signedUrl = getSignedUrl(&#123;
  url: 'https://d123.cloudfront.net/premium/video.mp4',
  keyPairId: 'K1234567890',
  privateKey: privateKeyString,
  dateLessThan: new Date(Date.now() + 3600 * 1000).toISOString(), // 1 hour
&#125;);

S3 + CloudFront (Static Site)

S3 bucket (private, no public access)
    ↓
CloudFront (Origin Access Control)
    ↓
Custom domain + ACM certificate (HTTPS)
    ↓
Route 53 DNS

Benefits:
  - HTTPS everywhere
  - Global edge caching
  - S3 stays private (no direct access)
  - DDoS protection (AWS Shield)

Key Takeaways

  • CloudFront = global CDN with 400+ edge locations
  • Use versioned filenames for static assets to avoid invalidation
  • Configure Cache-Control headers at the origin for proper caching behavior
  • CloudFront Functions for simple tasks (URL rewrite, redirects) — cheapest option
  • Lambda@Edge for complex logic (auth, dynamic content)
  • Use Origin Access Control to keep S3 private while serving via CloudFront
  • Signed URLs for private/premium content distribution