CloudFront
CloudFront is AWS’s global CDN. Caches origin responses at 600+ edge locations, terminates TLS, runs functions at the edge. Origin = S3, ALB, custom HTTP backend, or another CloudFront distribution.
Create, cache, OAC, functions, invalidate
EXAMPLE
# 1) Create a distribution (Console / CLI / IaC)
aws cloudfront create-distribution --distribution-config file://dist-config.json
# dist-config.json (abbreviated)
{
"CallerReference": "unique-string",
"Comment": "app.example.com",
"Enabled": true,
"DefaultRootObject": "index.html",
"PriceClass": "PriceClass_100", // 100 = NA + EU; All = global; cheapest first
"Origins": {
"Quantity": 1,
"Items": [{
"Id": "s3-origin",
"DomainName": "my-bucket.s3.us-east-1.amazonaws.com",
"S3OriginConfig": { "OriginAccessIdentity": "" }
}]
},
"DefaultCacheBehavior": {
"TargetOriginId": "s3-origin",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": { "Quantity": 2, "Items": ["GET","HEAD"] },
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", // Managed-CachingOptimized
"Compress": true
},
"ViewerCertificate": { "CloudFrontDefaultCertificate": true }
}
# 2) Custom domain (Route53 → CloudFront)
# 1. Issue ACM cert in us-east-1 (CloudFront only reads from us-east-1)
# 2. Add Alternate Domain Name (CNAME) on the distribution
# 3. Set ViewerCertificate to use that cert
# 4. Route53: A record alias → d111111.cloudfront.net
# 3) Origin Access Control (OAC) — secure S3 origin
# Replaces Origin Access Identity (OAI — legacy).
# 1. Create OAC; 2. Attach to distribution; 3. Update S3 bucket policy
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCloudFrontReadOnly",
"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/E1ABCDEF"
}
}
}]
}
# Block all public access on the bucket. Only CloudFront can read it.
# 4) Cache behaviour patterns
#
# Static assets (long TTL, immutable filenames):
# Cache-Control: public, max-age=31536000, immutable
# /assets/main.<hash>.js → cache 1 year
#
# HTML / API (short TTL):
# Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60
# /index.html → cache 60s, refresh in background
#
# Personalised (no caching):
# Cache-Control: no-store
# /api/me → never cached at the edge
# 5) Managed cache policies (preferred over Legacy)
# CachingOptimized : default; caches by URL
# CachingDisabled : never cache
# CachingOptimizedForUncompressedObjects : pre-compressed origins
# Elemental-MediaPackage : streaming
# Amplify : SPA defaults
# 6) Origin request policy
# Decides which headers / cookies / query strings get forwarded to the origin.
# Use 'AllViewer' if origin needs everything; 'UserAgentRefererHeaders' for selective.
# 7) Invalidate the cache (push updates immediately)
aws cloudfront create-invalidation \
--distribution-id E1ABCDEF \
--paths '/index.html' '/assets/styles.css'
# Wildcards
aws cloudfront create-invalidation --distribution-id E1ABCDEF --paths '/*'
# Cost: first 1000 path invalidations / month free; $0.005 each after.
# Better: hash filenames + long max-age so you NEVER need to invalidate /assets/*.
# 8) CloudFront Functions — JS at the edge (cheap, fast, limited)
# Use case: header rewrites, A/B routing, simple URL rewrites, redirect insertion
# Limit: 1 ms CPU, 2 MB memory, no network access
function handler(event) {
const request = event.request;
// Add canonical headers
request.headers['x-canonical-host'] = { value: 'app.example.com' };
// Pretty URLs (e.g. /about → /about/index.html)
if (request.uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!request.uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
# 9) Lambda@Edge — Node.js / Python at the edge (slower, more capable)
# Use case: auth, A/B testing with origin lookups, image manipulation, SSR for SEO
# Limit: 5 sec CPU, 128 MB memory, can call other AWS APIs
export const handler = async (event) => {
const req = event.Records[0].cf.request;
// Auth gate
const auth = req.headers.authorization?.[0]?.value;
if (!auth || !await verifyToken(auth)) {
return {
status: '401',
statusDescription: 'Unauthorized',
body: JSON.stringify({ error: 'unauthorised' }),
};
}
return req;
};
# 10) Geographic restrictions / WAF
# CloudFront supports country-level allow / deny lists.
# For richer rules (bots, rate limits, IP reputation), attach AWS WAF.
# 11) Signed URLs / cookies — private content delivery
import { getSignedUrl } from '@aws-sdk/cloudfront-signer';
const url = getSignedUrl({
url: 'https://app.example.com/private/file.pdf',
keyPairId: 'KEYPAIRIDXXX',
privateKey: fs.readFileSync('./cf-private-key.pem', 'utf8'),
dateLessThan: new Date(Date.now() + 5 * 60_000).toISOString(), // 5 min
});
# Use for: paywalled assets, time-limited downloads, private S3 content over CloudFront.
# 12) Logs
# Standard logs → S3 (5-min lag). Real-time logs → Kinesis (sub-second).
aws cloudfront update-distribution --id E1ABCDEF --distribution-config '{
"Logging": {
"Bucket": "my-cf-logs.s3.amazonaws.com",
"Prefix": "app/",
"IncludeCookies": false,
"Enabled": true
}
}'
# Combine with Athena to query.
# 13) Cost levers
# - PriceClass — restrict edge locations to NA+EU (cheapest) if your users are concentrated
# - Compression — enable; cuts bytes-out by ~70% for text
# - Long max-age + hashed filenames — minimise origin requests + invalidations
# - HTTP/2 + 3 — set-and-forget speed boost
# - Avoid invalidations; use cache busting via filenames
# - CloudFront Functions for header tweaks (cheaper than Lambda@Edge)
# 14) Common patterns
# Static site (SPA) : S3 origin + OAC + CachingOptimized + cf-function for /index.html
# API + cache : ALB origin + custom cache policy by URL + Vary on Authorization
# Image resizer : Lambda@Edge resizes on origin response + caches result
# Multi-region failover : Origin Group with primary + secondary
# Streaming : Elemental MediaPackage origin + CachingDisabled on manifests
# 15) Anti-patterns
# ❌ Cache-Control: no-cache on everything → CDN useless
# ❌ Invalidate /* on every deploy → use hashed filenames instead
# ❌ S3 bucket public + CloudFront → defeats the security benefit; use OAC
# ❌ Forwarding all headers to origin → defeats caching
# ❌ TLS cert in wrong region (must be us-east-1)
# ❌ Lambda@Edge for header tweaks (use CloudFront Functions; 10x cheaper)
# 16) Observability
# CloudWatch metrics: Requests, TotalErrorRate, BytesDownloaded, OriginLatency
# Real-time dashboards via Real User Monitoring (RUM)
# Alarms on CacheHitRate dropping (origin pressure)
Why it matters
CloudFront + OAC + S3 origin + hashed-filename caching is the cheap-and-fast modern static-site stack. Add CloudFront Functions for header tweaks, Lambda@Edge for anything heavier — never invalidate on every deploy.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…