CloudFront
🔥 1. Core Concepts
1.1 Edge Locations
- Global network of POPs (Points of Presence)
- Reduce latency by serving cached content closest to the user
- Automatically choose the best route
1.2 Distributions
A CloudFront distribution is the configuration object that defines:
- Where origin content comes from (S3, ALB, API Gateway, EC2, Custom Origin)
- What caching rules apply
- What security settings apply.
There are two types:
| Type | Description |
|---|---|
| Web distribution | Standard distribution for websites, APIs, static/dynamic assets |
| RTMP distribution | Deprecated |
⚙️ 2. Origins
CloudFront can pull content from:
S3 Origin
- Most common use
- CloudFront acts as a secure front layer over S3
- Supports Origin Access Control (OAC) for private buckets (replaces old OAI)
Custom Origin
Examples:
- Application Load Balancer (ALB)
- EC2
- Any HTTP server
- API Gateway endpoints
- Containers on ECS/EKS
- Even non-AWS servers
Origin Groups
- Failover strategy (Primary → Secondary)
- Used for high availability setups (e.g., multi-region S3)
🧠 3. Caching Model
CloudFront caches objects at edge locations based on:
- Path pattern
- Headers
- Cookies
- Query strings
- Cache key policies
Cache Key = What determines uniqueness
Good practice:
Keep the cache key small unless needed → Reduce edge misses → Faster performance → Lower cost.
Examples:
| Scenario | Recommended Cache Key |
|---|---|
| Static assets | URL path only |
| Authenticated API | Path + Authorization header (or JWT claims) |
| Image resizing | Path + width/height query params |
⏱️ 4. TTL Rules
CloudFront respects:
- Cache-Control headers (max-age, s-maxage)
- Expires header
- If none provided → default TTL
Default TTL values (you can override):
- Minimum TTL – 0 seconds
- Default TTL – 24 hours
- Maximum TTL – 1 year
🔐 5. Security Features
✔ Origin Access Control (OAC)
- Lets CloudFront access private S3
- Enforces signed requests
- Recommended over OAI
✔ Geo restrictions
Block or allow countries.
✔ Custom SSL Certificates
Attach via ACM (must be in us-east-1).
✔ HTTPS-only enforcement
✔ AWS WAF Integration
Add WAF Web ACL for:
- Rate limiting
- IP allow/block
- Bot Control
- Managed rule sets
✔ Shield Standard (free)
DDoS protection included.
🤖 6. Edge Compute Options
6.1 CloudFront Functions
Ultra-light JavaScript
Runs at viewer request/response
Sub-millisecond latency
Cheap (millions of executions per $)
Use cases:
- URL rewrites
- Header manipulation
- AB testing
- Simple redirects
6.2 Lambda@Edge
Full Node.js/Python runtime
Runs at both viewer and origin events
Higher latency & cost
Use cases:
- Authentication at the edge
- Dynamic HTML rewriting
- Personalization at the edge
- Multi-origin routing logic
🛰️ 7. Common CloudFront Architectures
7.1 S3 Static Website Hosting
- S3 bucket (private)
- CloudFront distribution with OAC
- React/Vite build output uploaded
- Cache invalidation on deployments
7.2 CDN for a Backend API
- Origin: ALB or API Gateway
- Improves global latency
- Adds WAF + caching
7.3 Multi-origin Routing
- /api → API Gateway
- /static → S3
- /images → S3 + image optimization lambda@edge
📤 8. Invalidation
When you want to invalidate cached files:
Types:
| Pattern | Usage |
|---|---|
/index.html |
Deploying new frontend |
/static/* |
Full static asset flush |
/* |
Full wipe (expensive) |
Invalidations cost money (free up to 1,000 paths monthly).
Better strategy:
- Use cache-busting filenames (React/Vite do this automatically).
💰 9. Pricing (Simplified)
Pricing depends on:
- Region
- Data out
- Requests
- Functions@edge usage
- Invalidation count
Approx (Australia users served from Sydney POP):
- ~$0.085 per GB (AU → user)
- $0.60 per 1M HTTP requests
- CloudFront Functions: ~$0.10 per 1M invocations
- Lambda@Edge: similar to Lambda but billed per region
📦 10. Real-World Best Practices (2025)
⭐ Use OAC (not OAI) for S3
⭐ Use CloudFront Functions for rewrites/AB tests
⭐ Use WAF for all public-facing traffic
⭐ Compress (gzip/brotli) content before S3 upload
⭐ Use immutable caching for assets:
Cache-Control: public, max-age=31536000, immutable
⭐ Deploy versioned builds (avoid invalidations)
⭐ Prefer API Gateway as origin for serverless backends
⭐ Enable HTTP/3
📘 11. CloudFront Logging + Monitoring
Logs
- Standard logs → S3
- Realtime logs → Kinesis Data Streams
Metrics
- Miss rate
- Hit rate
- 5xx errors
- 4xx spikes
- Throughput and latency
🧩 12. When to Use CloudFront
Use CloudFront if: ✓ You serve users globally ✓ You serve static assets ✓ You want to hide your S3 bucket ✓ You want DDoS + WAF protection ✓ You want to accelerate APIs ✓ You want caching for performance + cost savings
🆚 13. CloudFront vs Alternatives
| Feature | CloudFront | Cloudflare | Akamai |
|---|---|---|---|
| Edge count | ~600+ | ~300+ | ~4,000+ |
| Edge compute | Lambda@Edge | Workers (strong) | EdgeWorkers |
| AWS native | ✔ | ✖ | ✖ |
| Custom SSL | Free | Free | Paid |
| WAF | Excellent | Excellent | Enterprise |
CloudFront wins for AWS-native architectures.
📦 14. CloudFront with React / Next.js / Vite
S3 + CloudFront
- Upload
/dist - Invalidate
/index.html
Server-Side Rendered Apps
Next.js → via S3+Lambda@Edge or Amplify Hosting
CloudFront handles:
- Static assets
- API
- Image optimization
📄 15. Example CloudFront Config for a Modern Web App
Behaviors
| Path | Origin | TTL | Notes |
|---|---|---|---|
/assets/* |
S3 | 1 year | immutable |
/api/* |
ALB/API GW | 0 (no cache) | Include auth headers |
/ |
S3 | 0–10 seconds | HTML not cached long |
/_next/* |
S3 or Lambda@Edge | 1 year | Next.js |
Security
- OAC enabled
- WAF ACL attached
- HTTPS-only
- Geo restriction optional
🎯 If you want, I can also generate:
✅ A CloudFront + S3 deployment guide ✅ A Terraform/CDK template ✅ A fully working React/Vite hosting pipeline ✅ Cache optimization plan for your specific app ✅ Invalidations strategy ✅ Architecture diagram for your project
Just tell me!
CloudFront + S3 deployment guide
0. Assumptions
React app created with something like:
npx create-react-app my-app # or npm create vite@latest my-app -- --template reactYou want:
- S3 = static file origin
- CloudFront = CDN + HTTPS + cache + custom domain (optional)
I’ll break it into:
- Build React app
- Create & configure S3 bucket
- Upload build to S3
- Create CloudFront distribution
- (Optional) Custom domain + HTTPS
- (Optional) Cache invalidation on deploy
- Bonus: small deploy script
1️⃣ Build the React app
From your React project root:
# CRA
npm run build
# or Vite
npm run buildYou’ll get something like:
- CRA:
build/ - Vite:
dist/
That folder is what goes to S3.
2️⃣ Create the S3 bucket
In the AWS Console:
- Go to S3 → Create bucket
- Bucket name: e.g.
my-react-app-prod - Region: usually same as rest of your stack (e.g.
ap-southeast-2) - Uncheck “Block all public access” only if you plan to use S3 website hosting directly. For CloudFront best practice, keep it blocked and use OAC.
We’ll assume private bucket + CloudFront Origin Access Control (OAC).
2.1 Folder layout in S3
Upload your built assets (we’ll do the actual upload in step 3), so the bucket will look like:
index.htmlasset-manifest.json(CRA)static/...orassets/...(bundles, CSS, etc.)
No subfolder required unless you want a v1/, v2/ structure.
3️⃣ Upload build artifacts to S3
Simplest (manual) way:
- In S3 bucket → Upload → drag/drop contents of
build/(ordist/), not the folder itself.
CLI version (nice for future automation):
# Using AWS CLI v2
aws s3 sync build/ s3://my-react-app-prod/ \
--delete \
--exclude "*.map"Or for Vite:
aws s3 sync dist/ s3://my-react-app-prod/ --delete --exclude "*.map"--delete removes old files that no longer exist locally, keeping the bucket in sync.
4️⃣ Create the CloudFront distribution
In the AWS Console:
Go to CloudFront → Create distribution
Origin section:
Origin domain: pick your S3 bucket (
my-react-app-prod.s3.amazonaws.comor the “Bucket” option).Origin access:
- Choose Origin access control settings (recommended)
- Create new OAC if you don’t have one yet.
After creating the distribution, CloudFront will show you a bucket policy snippet. Copy it and apply it to the S3 bucket so that only CloudFront can read from it.
Default cache behavior
Viewer protocol policy: Redirect HTTP to HTTPS
Allowed HTTP methods:
- For static SPA:
GET, HEADis enough.
- For static SPA:
Cache policy:
- Start with CachingOptimized or CachingDisabled while developing.
- Later, use a custom policy with long TTLs for
/static/*or/assets/*.
Settings
Price class: e.g.
Use only North America and EuropeorUse All Edge Locations(depends on your users).Alternate domain name (CNAME): leave blank for now (we’ll set custom domain in step 5).
SSL/TLS certificate: default CloudFront certificate for
*.cloudfront.net(change later if you add a custom domain).Default root object: set this to
index.htmlThis is crucial so that hits to
https://dXXXX.cloudfront.net/return your React app.
Create distribution
Once status is Deployed, you’ll have a URL like:
https://d123abcd.cloudfront.net/
Open it and you should see your React app.
5️⃣ SPA routing (React Router) with CloudFront
If you use React Router (/dashboard, /settings, etc.), hitting those paths directly will 404 at the origin unless you handle them.
Goal: For any unknown path, CloudFront should serve index.html so the client-side router can handle it.
You have a few options:
Option A: SPA-style 404 fallback via Custom Error Response
- Edit your CloudFront distribution → Error pages tab → Create custom error response
- For HTTP error code:
404 - Customize error response: Yes
- Response page path:
/index.html - HTTP response code:
200
Now if CloudFront/origin returns a 404, it serves index.html with a 200 response. React Router then handles the route.
6️⃣ (Optional) Custom domain + HTTPS via ACM
If you want https://app.mycompany.com:
Get a certificate in ACM
- Region: us-east-1 (CloudFront requirement).
- Request public certificate → include your domain (e.g.
app.mycompany.com). - Validate via DNS (CNAME).
Update CloudFront distribution
In distribution Settings:
- Alternate domain name (CNAME):
app.mycompany.com - Custom SSL certificate: choose the ACM cert you created.
- Alternate domain name (CNAME):
Configure DNS (Route 53 or your DNS host)
Add a CNAME or ALIAS record:
- Name:
app.mycompany.com - Value: your CloudFront domain
d123abcd.cloudfront.net
- Name:
Once DNS propagates, https://app.mycompany.com will serve your app via CloudFront.
7️⃣ Cache invalidation for React deploys
Because React build outputs are usually fingerprinted (e.g. main.4c5f2d.js), you rarely need to invalidate everything.
Minimum you should invalidate on each deploy:
/index.html
In CloudFront console:
- Invalidations → Create invalidation
- Path:
/index.html
CLI:
aws cloudfront create-invalidation \
--distribution-id D123ABC456 \
--paths "/index.html"If you don’t have hashed filenames (not recommended), you might temporarily invalidate /static/* or /*.
8️⃣ Simple deploy script (bash)
You can wrap all of this into a tiny script and plug into CI (GitHub Actions, etc.)
#!/usr/bin/env bash
set -euo pipefail
DISTRIBUTION_ID="D123ABC456"
BUCKET_NAME="my-react-app-prod"
BUILD_DIR="build" # or dist for Vite
echo "▶ Building React app..."
npm run build
echo "▶ Syncing ${BUILD_DIR}/ to s3://${BUCKET_NAME}/ ..."
aws s3 sync "${BUILD_DIR}/" "s3://${BUCKET_NAME}/" \
--delete \
--exclude "*.map"
echo "▶ Creating CloudFront invalidation for /index.html ..."
aws cloudfront create-invalidation \
--distribution-id "${DISTRIBUTION_ID}" \
--paths "/index.html"
echo "✅ Deploy complete."Hook this into:
make deploy- GitHub Actions workflow (run on push to
main)
9️⃣ Summary Checklist
Here’s the “did I forget anything?” checklist: