What you will learn
- What CloudFront is and the two problems it solves simultaneously
- CloudFront origins — S3 with OAC, VPC Origins for private ALB, Custom HTTP backends
- Origin Access Control — how to keep your S3 bucket private while serving through CloudFront
- Geo Restriction — blocking or allowing traffic by country
- Cache invalidations — when and how to clear edge caches after content updates
- CloudFront Functions vs Lambda@Edge — which runs where and what each can do
- What Global Accelerator is and the Anycast IP concept that makes it work
- Global Accelerator health checks and sub-1-minute automatic failover
- CloudFront vs Global Accelerator — the decision guide that separates them clearly
Why this matters
Hotstar serves cricket and IPL content to users across India, Southeast Asia, and globally. A video thumbnail request from a user in Chennai should not travel to Mumbai and back — it should be served from a CloudFront edge location in Chennai in milliseconds. Without CloudFront, every request hits the origin server. With CloudFront, 99% of requests are served from edge — the origin barely gets touched. At Zerodha, trading data APIs must respond fast from any location worldwide with consistent latency. Global Accelerator routes API traffic through AWS's private backbone, bypassing the congested public internet. These are not luxury optimisations — at scale they are the difference between a product that feels instant and one that feels slow.
What is Amazon CloudFront
CloudFront is a Content Delivery Network. It caches your content at edge locations around the world so users get it from a nearby location instead of your origin server thousands of miles away.
Without CloudFront: User in Chennai → Server in Mumbai (every request hits origin, high latency) With CloudFront: User in Chennai → Edge Location in Chennai (cached, served locally, fast) Origin server barely touched after first cache populationCloudFront solves two problems simultaneously:
- Improves read performance — content cached at edge, served from nearby
- Reduces origin load — most requests never reach your S3 or EC2
Additional benefits:
- DDoS protection because traffic is distributed across hundreds of edge locations worldwide
- Integration with AWS Shield and WAF
- Hundreds of Points of Presence globally including 10+ across India
CloudFront Origins — Where Your Content Lives
An origin is where CloudFront fetches content from on a cache miss. Three types:
S3 Bucket:
Static files cached at edge globally. Also supports upload to S3 through CloudFront (ingress).
Security uses Origin Access Control (OAC). Your S3 bucket stays private — only CloudFront can access it via OAC credentials. Users hit CloudFront. CloudFront hits S3 with OAC.
Users → CloudFront Edge → (private AWS network via OAC) → S3 Bucket (private) S3 bucket policy: only CloudFront can read from the bucketDirect S3 URLs: return Access Denied to everyone elseVPC Origin (Private ALB or EC2):
For applications in private subnets. CloudFront reaches into your VPC through VPC Origins over the private AWS network — your application is never exposed to the internet.
Users → CloudFront Edge → VPC Origin → Private Subnet → ALB/NLB/EC2Custom Origin (Public HTTP):
Any public HTTP backend — public ALB, any web server, on-premises servers, S3 static website (S3 website is different from S3 bucket origin).
Origin Access Control — Keeping S3 Private
Without OAC, to serve S3 content through CloudFront you had to make the bucket public — exposing it to direct access. OAC solves this.
With OAC setup: S3 bucket policy allows only: Principal = cloudfront.amazonaws.com Condition = source distribution ARN Users hit CloudFront URL → CloudFront fetches from S3 with signed OAC request Users hit S3 URL directly → 403 Access Denied Without OAC (wrong approach): S3 bucket is public → anyone with the S3 URL can access it CloudFront is bypassed entirely — defeats the purposeSetting up OAC:
CloudFront Console: 1. Go to Origins → Edit → Origin access 2. Select: Origin access control settings (recommended) 3. Create new OAC → give it a name 4. CloudFront shows a banner: "Update S3 bucket policy" 5. Copy the generated policy → paste into S3 bucket permissions Done — S3 is now private, only CloudFront can access itRememberAfter creating a distribution with OAC, CloudFront displays a banner reminding you to update the S3 bucket policy. If you skip this step, CloudFront cannot fetch from S3 and users get errors. Always complete both steps.
How CloudFront Caching Works
Client requests: GET /video-thumbnail.jpg Request hits nearest CloudFront Edge Location Edge checks Local Cache: Cache hit → return content immediately (fast, origin never called) Cache miss → forward request to your Origin → Origin returns content → Edge caches it based on TTL → Returns content to client Next request for same file from same region: Served from edge cache — origin never called againTTL (Time To Live):
Controls how long CloudFront holds a cached copy before going back to origin.
Cache-Control: max-age=86400 → cache for 24 hoursCache-Control: no-cache → always validate with originDefault TTL if not specified → 24 hoursGeo Restriction
Control which countries can or cannot access your CloudFront distribution.
Allowlist → users can access ONLY if in approved countries Everyone else gets 403 Forbidden Blocklist → users from listed countries are blocked Everyone else can access normallyCountry detected using a third-party Geo-IP database that maps IP addresses to countries.
Common use case: copyright laws. Video content licensed only for specific countries. Streaming platforms use this to restrict content by region.
## Add geo restriction via CLIaws cloudfront update-distribution \ --id DISTRIBUTION-ID \ --distribution-config '{ "Restrictions": { "GeoRestriction": { "RestrictionType": "whitelist", "Quantity": 2, "Items": ["IN", "SG"] } } }'## Users from India and Singapore allowed, everyone else blockedCache Invalidations — Clearing Stale Content
The problem:
You update a file in S3. CloudFront edge locations still serve the old cached version until TTL expires — which could be 24 hours. Users see outdated content.
You update index.html in S3 ↓CloudFront edges still serving old index.html ↓Users see outdated content until TTL expiresThe fix — cache invalidation:
Force CloudFront to immediately clear its cache and fetch fresh content from origin.
You trigger a Cache Invalidation ↓CloudFront clears cache at ALL edge locations and Regional Caches ↓Next request to any edge → cache miss → fetch fresh from origin ↓Users get updated content immediately## Invalidate all files (full cache wipe)aws cloudfront create-invalidation \ --distribution-id YOUR-DISTRIBUTION-ID \ --paths "/*" \ --region us-east-1## Note: CloudFront API calls go to us-east-1 regardless of distribution region ## Invalidate specific file onlyaws cloudfront create-invalidation \ --distribution-id YOUR-DISTRIBUTION-ID \ --paths "/index.html" "/app.js" \ --region us-east-1 ## Invalidate a folderaws cloudfront create-invalidation \ --distribution-id YOUR-DISTRIBUTION-ID \ --paths "/images/*" \ --region us-east-1Common MistakeUpdating files in S3 and expecting users to see changes immediately. Without a Cache Invalidation, CloudFront keeps serving the cached old version until TTL expires. After any content update that users must see immediately, always run a cache invalidation.
CloudFront Functions and Lambda@Edge
Both let you run code at CloudFront edge locations — close to the user, not in your region.
Four points where code can run:
User ↓[Viewer Request] ← both CloudFront Functions and Lambda@Edge ↓CloudFront ↓[Origin Request] ← Lambda@Edge only ↓Your Origin ↓[Origin Response] ← Lambda@Edge only ↓CloudFront ↓[Viewer Response] ← both CloudFront Functions and Lambda@Edge ↓User| CloudFront Functions | Lambda@Edge | |
|---|---|---|
| Language | JavaScript only | Node.js and Python |
| Execution time | Under 1ms | 5 to 10 seconds |
| Memory | 2 MB | 128 MB to 10 GB |
| Network access | No | Yes |
| Triggers | Viewer Request/Response only | All 4 triggers |
| Scale | Millions req/sec | Thousands req/sec |
| Price | Very cheap, free tier | More expensive, no free tier |
Use CloudFront Functions for:
Cache key normalisation → remove unnecessary query strings before cachingHTTP header manipulation → add, remove, or rewrite headers at edgeURL rewrites and redirects → /old-path → /new-path without hitting originSimple JWT token validation → check token format before passing to originUse Lambda@Edge for:
Complex authentication → validate token against a database via network callReading request body → inspect POST body before forwardingAWS SDK calls at edge → query DynamoDB or call Secrets ManagerDynamic HTML generation → render personalised content at the edgeHands-on Lab — CloudFront with Private S3
Step 1 — Create a private S3 bucket
S3 → Create bucketName: devops-cloudfront-lab-yourname (must be globally unique)Region: ap-south-1Block Public Access: keep ALL settings ON (bucket stays private)Create bucket Upload a test file:S3 → devops-cloudfront-lab-yourname → Upload → Add files → index.html File content:<h1>Served via CloudFront — not directly from S3</h1>Step 2 — Create a CloudFront Distribution
CloudFront → Distributions → Create distribution Origin domain → click the dropdown → select your S3 bucketOrigin access → Origin access control settings (recommended)Click: Create new OAC → give it a name → Create Viewer protocol: Redirect HTTP to HTTPSDefault root object: index.htmlCreate distribution — takes 5-10 minutes to deploy globally Important: After creation CloudFront shows a yellow banner:"You must update the S3 bucket policy"Click: Copy policy → go to your S3 bucket → Permissions → Bucket policy → Paste → Save Without this step CloudFront cannot read from S3.Step 3 — Test access
CloudFront → Distributions → your distribution → Domain name (copy it)Open browser: https://YOUR-DISTRIBUTION.cloudfront.net/index.htmlPage loads — served from the nearest edge location Try the direct S3 URL:https://devops-cloudfront-lab-yourname.s3.ap-south-1.amazonaws.com/index.htmlShould show: 403 Access Denied — bucket is private, only CloudFront can access itStep 4 — Update content and invalidate cache
Update index.html in S3:<h1>Updated content — version 2</h1> Refresh browser → still shows version 1 (CloudFront cached it) CloudFront → Distributions → your distribution → Invalidations → Create invalidationObject paths: /index.html → Create invalidation Wait 30-60 seconds → refresh browser → now shows version 2Step 5 — Cleanup
CloudFront → Distributions → select distribution → Disable (wait for deployed state)Then: Delete distributionS3 → devops-cloudfront-lab-yourname → Empty → Delete bucketProduction Best Practices and Common Pitfalls
- Always use OAC for S3 origins — never make S3 buckets public just to serve through CloudFront
- Set appropriate TTL values — too high means stale content after updates, too low means frequent origin hits
- Use cache invalidations after deployments — especially for HTML and JS files that users must get fresh
- Restrict CloudFront to HTTPS only — use redirect HTTP to HTTPS on the viewer protocol policy
- Use WAF on CloudFront for Layer 7 protection — attach a Web ACL to filter malicious requests at the edge globally
- Use Global Accelerator for latency-sensitive APIs that are not cacheable — gaming, trading, real-time applications
- For static assets with CDN: CloudFront is almost always the right choice — Global Accelerator adds nothing for cacheable content
Quick Reference and Troubleshooting Commands
| Task | Command |
|---|---|
| List distributions | aws cloudfront list-distributions --region us-east-1 |
| Get distribution details | aws cloudfront get-distribution --id <DIST-ID> --region us-east-1 |
| Create invalidation | aws cloudfront create-invalidation --distribution-id <DIST-ID> --paths "/*" --region us-east-1 |
| Check invalidation status | aws cloudfront get-invalidation --distribution-id <DIST-ID> --id <INVAL-ID> --region us-east-1 |
| List Global Accelerators | aws globalaccelerator list-accelerators --region us-west-2 |
| Get accelerator details | aws globalaccelerator describe-accelerator --accelerator-arn <ARN> --region us-west-2 |
| List listeners | aws globalaccelerator list-listeners --accelerator-arn <ARN> --region us-west-2 |
Common problems and fixes:
| Problem | Likely cause | Fix |
|---|---|---|
| 403 from CloudFront on S3 content | OAC not set up or S3 bucket policy not updated | Complete OAC setup and update S3 bucket policy with CloudFront-generated policy |
| Content not updating after S3 upload | Cache TTL not expired | Create an invalidation for the updated paths |
| 502 Bad Gateway from CloudFront | Origin is unreachable | Check origin health, Security Groups, and origin timeout settings |
| Global Accelerator routing to wrong region | Health check failing in correct region | Verify health check endpoint, Security Groups allowing health check source IPs |
| High cache miss rate | TTL too low or cache key includes dynamic parameters | Increase TTL, use cache policies to normalise cache keys |
Common MistakeForgetting to update the S3 bucket policy after creating OAC. CloudFront creates the OAC and generates the required S3 bucket policy — but it does not apply the policy automatically. You must copy the generated policy and apply it to the S3 bucket manually. Without this step CloudFront gets 403 from S3 and users see errors.
Common MistakeUsing Global Accelerator for cacheable static content. Global Accelerator does not cache. Every request travels through the edge to your origin. For static files, images, and videos CloudFront caches at the edge and serves locally — far cheaper and faster than Global Accelerator for this use case.
TipFor a Hotstar-style video platform serving content globally — use CloudFront in front of S3 for video thumbnails, metadata JSON, and static assets (cacheable, high volume). Use Global Accelerator for the real-time API calls (now playing, live scores, chat) that cannot be cached but need low latency worldwide. The two services are complementary, not competitive.
Common Mistakes to Avoid
Common MistakeForgetting to update the S3 bucket policy after setting up OAC. CloudFront creates the OAC and generates the policy — but does not apply it. You must copy it and paste it into the S3 bucket permissions manually. Without this step, every CloudFront request to S3 returns 403.
Common MistakeUsing Global Accelerator for cacheable static content. Global Accelerator routes traffic to your origin on every request — it does not cache. For images, videos, and static files, CloudFront caches at the edge and is far cheaper.
TipAfter updating content in S3, always create a CloudFront invalidation. Without it, edge locations serve the old cached version until TTL expires — which can be 24 hours.