AWS for DevOps — CloudFront
12.2 — CloudFront
CloudFront is AWS’s CDN (Content Delivery Network). It caches your content at 400+ edge locations worldwide, reducing latency for users everywhere.
Real-World Analogy
CloudFront is like a chain of local bookstores. Instead of every customer ordering from the main warehouse (your origin server), each city has a local store (edge location) with copies of popular books. If the local store doesn’t have the book, it orders from the warehouse once and stocks it for future customers.
How CloudFront Works
User (Mumbai) User (London)
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Edge Location│ │ Edge Location│
│ Mumbai │ │ London │
│ (cached) │ │ (cached) │
└──────┬───────┘ └──────┬───────┘
│ cache miss │ cache miss
└──────────┬──────────────────┘
▼
┌──────────┐
│ Origin │
│ (S3/ALB) │
└──────────┘
Creating a Distribution
# Create a CloudFront distribution with an S3 origin
$ aws cloudfront create-distribution \
--distribution-config '{
"CallerReference": "my-dist-2026",
"Origins": {
"Quantity": 1,
"Items": [{
"Id": "S3-my-website",
"DomainName": "my-website-bucket.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": "origin-access-identity/cloudfront/E1234567890"
}
}]
},
"DefaultCacheBehavior": {
"TargetOriginId": "S3-my-website",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": ["HEAD", "GET"]
},
"ForwardedValues": {
"QueryString": false,
"Cookies": {"Forward": "none"}
},
"MinTTL": 0,
"DefaultTTL": 86400,
"MaxTTL": 31536000
},
"Enabled": true,
"Comment": "My website CDN"
}'
CloudFront with ALB Origin
For API backends, put CloudFront in front of your ALB:
# Distribution with ALB origin
# Origins.Items[0]:
{
"Id": "ALB-api",
"DomainName": "my-alb-123.ap-south-1.elb.amazonaws.com",
"CustomOriginConfig": {
"HTTPPort": 80,
"HTTPSPort": 443,
"OriginProtocolPolicy": "https-only"
}
}
Origin Types
| Origin | Use Case | Example |
|---|---|---|
| S3 Bucket | Static websites, assets | CSS, JS, images |
| ALB | Dynamic API content | REST API, GraphQL |
| EC2 | Legacy applications | Custom origin |
| MediaStore | Video streaming | Live/on-demand video |
| Custom origin | Any HTTP server | On-premises server |
Cache Invalidation
When you deploy new content, invalidate the cache:
# Invalidate specific paths
$ aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths '/index.html' '/css/*' '/js/*'
{
"Invalidation": {
"Id": "I1234567890",
"Status": "InProgress"
}
}
# Invalidate everything (use sparingly)
$ aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths '/*'
Cache Behaviors
Route different paths to different origins:
| Path Pattern | Origin | TTL | Use Case |
|---|---|---|---|
/api/* |
ALB | 0 (no cache) | Dynamic API |
/static/* |
S3 | 86400 (1 day) | CSS, JS, images |
/images/* |
S3 | 604800 (7 days) | User uploads |
Default (*) |
S3 | 3600 (1 hour) | HTML pages |
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
| Caching API responses | Users see stale data | Set TTL=0 for /api/* paths |
| Not invalidating after deploy | Users see old version | Invalidate or use versioned filenames (app.v2.js) |
| No custom error pages | Users see XML errors from S3 | Configure custom error responses (403 → /index.html) |
| HTTP origin (not HTTPS) | Data in transit not encrypted | Set OriginProtocolPolicy: https-only |
Quick Reference
| Task | Command |
|---|---|
| Create distribution | aws cloudfront create-distribution --distribution-config '...' |
| List distributions | aws cloudfront list-distributions |
| Invalidate cache | aws cloudfront create-invalidation --distribution-id ID --paths '/path' |
| Get distribution | aws cloudfront get-distribution --id ID |
| Disable distribution | Update config with Enabled: false, then delete |
Next → ALB vs NLB