Serve a Static Site via CloudFront
Learn to serve a static site via CloudFront CDN in this AWS Tutorial step. Hands-on exercise, troubleshooting, and next steps included.
Focus: serve a static site via cloudfront cdn
Your static site is live on S3, but every request travels the world to a single bucket in one region. Latency spikes, bandwidth costs creep up, and one ill-timed spike in traffic could take your whole site down. Serving a static site via CloudFront CDN fixes all of that by caching your content at edge locations across the globe, cutting latency, slashing data transfer costs, and adding a layer of DDoS protection — all with zero code changes.
The Problem This Lesson Solves
If you've followed this track, you've already hosted a static site on S3. That works, but it has three serious limitations:
- Latency: A user in London fetching from a bucket in
us-east-1pays a round-trip of thousands of kilometers for every byte. - Cost: AWS charges premium rates for data transfer out of a region to the internet. Repeated downloads of the same asset burn money fast.
- Resilience: A single bucket is a single point of failure. If the region has issues, your site is gone.
CloudFront solves this by caching your site's files at edge locations — over 600 points of presence in cities worldwide. The first request from a city pulls the file from your origin (the S3 bucket), stores a copy at the edge, and serves every subsequent request from that edge. The result is dramatically faster load times, lower origin load, and reduced egress costs.
Pro tip: The pain is real — a simple image-heavy site can see 70–80% of its bandwidth come from repeat downloads of the same assets. CloudFront turns that repeat traffic into cheap, fast edge hits.
Core Concept / Mental Model
Think of CloudFront as a global caching proxy with a smart delivery network. The mental model has three layers:
- Origin: Your S3 bucket (or EC2, ALB, or custom origin) holds the canonical copy of your content. It's the source of truth.
- Edge locations: These are the intermediate caches scattered around the world. Each edge holds copies of recently requested files with a configurable TTL (time to live).
- Distribution: The CloudFront configuration object that ties origins to edge behavior, URL patterns, cache rules, and security settings. It gives you a stable domain like
d111111abcdef8.cloudfront.net.
When a user requests https://d111111abcdef8.cloudfront.net/index.html, CloudFront does the following at the nearest edge:
- Checks the cache for
index.html. - If fresh (within TTL), returns it instantly to the user.
- If stale or missing, forwards the request to the origin, fetches the file, stores it locally, and returns it.
This is a classic cache-aside pattern, and it's the same idea behind CDNs like Fastly or Cloudflare. The key insight: the edge cache is only as good as its TTL configuration. Too short, and you miss the benefit; too long, and stale content lingers.
How It Works Step by Step
Here's the logical flow of setting up CloudFront for a static S3 site:
- Grant CloudFront access to your bucket — you can use an Origin Access Control (OAC) identity so the bucket is only accessible via CloudFront, not publicly.
- Create a distribution — specify the bucket as the origin, set cache behaviors (e.g., cache everything under
/assets/*with a long TTL), and define the default root object (index.html). - Update DNS — create a CNAME record in Route 53 (or your DNS provider) pointing your custom domain to the distribution's domain, and optionally request an SSL certificate.
- Test and invalidate cache — after deploying, test with
curland use invalidation to purge stale content when you update files.
Each step has a cause-and-effect chain: if you skip OAC, your bucket remains public; if you forget the default root object, visitors get a 403 error; if you set TTL to 0, you lose the caching benefit entirely.
Hands-On Walkthrough
Let's practice. Assume you already have a bucket my-static-site with index.html and styles.css uploaded (from the prior lesson).
Step 1: Create an Origin Access Control (OAC)
In the AWS Console, go to CloudFront → Origin Access Control → Create control. Give it a name and leave the defaults (signing behavior: Sign requests). This creates a principal you'll attach to your bucket policy.
Step 2: Create the Distribution
Go to Distributions → Create distribution. Set:
- Origin domain: select
my-static-site.s3.amazonaws.comfrom the dropdown - Origin access: select Origin access control settings and choose the OAC you created
- Viewer protocol policy: Redirect HTTP to HTTPS
- Cache key / origin requests: keep defaults
- Default root object:
index.html - Description: "Static site distribution"
Click Create distribution. CloudFront will show you the distribution's domain (e.g., d111111abcdef8.cloudfront.net).
Step 3: Update the Bucket Policy
CloudFront gives you a policy snippet. Copy it and attach it to your bucket. The policy looks like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-static-site/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EXAMPLEDISTRIBUTION"
}
}
}
]
}
Step 4: Test the Distribution
Wait a few minutes for the distribution to deploy, then run:
curl -I https://d111111abcdef8.cloudfront.net/index.html
Expected output includes:
HTTP/2 200
content-type: text/html
age: 0
x-cache: Miss from cloudfront
Run it again and you'll see x-cache: Hit from cloudfront — that confirms the edge cache is working.
Step 5: Invalidate Cache When You Update Files
When you upload a new version of styles.css, CloudFront won't know until the TTL expires. To force an update, create an invalidation:
aws cloudfront create-invalidation --distribution-id E1234567890ABC --paths "/index.html" "/*"
This purges all cached objects and forces new fetches from the origin.
Compare Options / When to Choose What
| Feature | Plain S3 Static Hosting | CloudFront + S3 | S3 + CloudFront + WAF |
|---|---|---|---|
| Latency | High for global users | Low (edge caching) | Low |
| Security | Public bucket or signed URLs | OAC + HTTPS | Adds WAF rules (e.g., rate limiting) |
| Cost | High egress from region | Lower egress (edge hits are cheaper) | Slightly higher, but managed DDoS protection |
| Maintenance | Minimal | Minimal + invalidations | Extra rules management |
Choose plain S3 for internal or low-traffic sites where latency doesn't matter. Choose CloudFront + S3 for any public-facing site with global users — it's the best balance of performance and cost. Add WAF only if you expect abusive traffic or have compliance requirements.
Troubleshooting & Edge Cases
- 403 Access Denied on the CloudFront URL: Your bucket policy is missing or the OAC isn't attached. Double-check the
Principaliscloudfront.amazonaws.comand theResourcematches your bucket ARN. - Stale content after update: Increase the cache TTL isn't the problem — you need an invalidation. Run
aws cloudfront create-invalidationor set aCache-Control: no-cacheheader on critical files. x-cache: Misson every request: Your TTL is probably 0, or you're using aCache-Control: no-storeheader on responses. For static assets, aim for a TTL of at least 3600 seconds.- Redirect loop or HTTP/HTTPS mismatch: Ensure the viewer protocol is set to redirect HTTP to HTTPS, and your custom domain's SSL certificate covers the exact domain (including
www). - Index page not served at root: If you request
/and get a 403, you forgot to set the default root object toindex.html.
What You Learned & What's Next
You now know how to serve a static site via CloudFront CDN — you've created a distribution, locked down your bucket with OAC, tested edge caching, and mastered cache invalidation. You've hit every objective of this lesson: explaining the core caching idea and completing a practical S3 + CloudFront setup.
What's next: In the next lesson, you'll dive into Lambda@Edge and CDN security — you'll learn to run lightweight JavaScript functions at edge locations to rewrite URLs, handle authentication, or add headers without touching your server. That's the perfect bridge from static delivery to dynamic, serverless processing.
Go ahead and create a distribution for your own bucket — the 20-minute investment pays off with every global visitor you get.
Practice recap
Create a CloudFront distribution for your existing S3 static site, upload a new version of styles.css, and verify the x-cache header changes from Miss to Hit on the second request. Then invalidate the cache and confirm the updated content is served immediately.
Common mistakes
- Forgetting to attach the OAC policy — you'll see 403 Forbidden on every CloudFront request.
- Setting a TTL of 0 and losing all caching benefits — your distribution behaves like a slow proxy.
- Skipping the default root object (
index.html) — users hitting/get a 403 instead of your site. - Updating files in S3 but not invalidating the cache — stale content persists long after deployment.
Variations
- Use a custom domain with Route 53 and an ACM certificate for a branded URL instead of the default
cloudfront.net. - Set different cache behaviors for
/assets/*vs/index.htmlto pin long TTLs on immutable files. - Combine CloudFront with Lambda@Edge to perform URL rewriting or A/B testing at the edge.
Real-world use cases
- A global marketing site hosted on S3 with CloudFront to slash load times for visitors in Europe and Asia.
- A software download portal using CloudFront to deliver installers at low latency and reduce S3 egress costs.
- A media streaming frontend caching images and video thumbnails at edge locations to handle traffic spikes during product launches.
Key takeaways
- CloudFront caches static content at edge locations, cutting latency and reducing S3 egress costs.
- Use Origin Access Control to keep your bucket private while allowing only CloudFront to read it.
- The default root object setting is essential for serving
index.htmlat the domain root. - Cache invalidation is the tool for forcing immediate content updates after S3 changes.
- Choose CloudFront + S3 over plain S3 hosting for any public site with a global audience.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.