How to Set Up a CDN with Cloudflare and AWS CloudFront: A Step‑by‑Step Guide
A content delivery network (CDN) puts copies of your static assets—images, CSS, JavaScript, fonts—on servers that sit close to your visitors. The result is faster page loads, lower origin server load, and built‑in protection against traffic spikes. Two of the most popular options for developers are Cloudflare, which offers a generous free tier and an all‑in‑one dashboard, and AWS CloudFront, which integrates tightly with the rest of the Amazon Web Services ecosystem. This guide walks you through the entire process of setting up either service, shows how to tune caching and security, and explains when one might be a better fit than the other.
Why a CDN Matters for Modern Sites
Without a CDN, every request travels from the user’s browser to your origin server, no matter where that server lives. If your site is hosted in a single region, a visitor on the other side of the world can add hundreds of milliseconds of pure network latency before the first byte arrives. A CDN cuts that distance by serving content from an edge location that is often just a few tens of miles away.
Beyond latency, a CDN provides:
- DDoS absorption – malicious traffic is filtered at the edge before it reaches your origin.
- SSL termination – the CDN handles the TLS handshake, freeing up CPU on your server.
- Bandwidth savings – edge servers serve cached copies, reducing the amount of data that must be pulled from your origin.
- Automatic failover – if one edge node goes down, traffic is routed to the next nearest node.
These benefits translate directly into better Core Web Vitals, higher search rankings, and a smoother experience for your users.
Cloudflare vs. AWS CloudFront: Choosing the Right Tool
Both platforms deliver content globally, but they differ in pricing model, feature set, and operational complexity.
| Aspect | Cloudflare | AWS CloudFront |
|---|---|---|
| Pricing | Fixed monthly plans (Free, $25 Pro, $200 Business). Bandwidth is unmetered. | Pay‑as‑you‑go: you pay per GB of data transfer and per 10,000 HTTP requests. A generous 12‑month free tier includes 1 TB transfer and 10 million requests. |
| Setup | Change nameservers to Cloudflare’s; the service proxies traffic automatically. | Create a distribution in the AWS console, point it at an origin (S3, EC2, ALB, etc.), then add a CNAME or alias record in DNS. |
| Built‑in optimizations | Auto minify, Brotli compression, Polish (image WebP/AVIF), Rocket Loader, Argo Smart Routing (paid). | Lambda@Edge and CloudFront Functions for custom code at the edge; Origin Shield to reduce origin fetches; detailed CloudWatch metrics. |
| Integration | Works with any host; offers DNS, SSL, WAF, and a bot‑management suite. | Deeply integrated with S3, EC2, API Gateway, WAF, Shield, and Certificate Manager. |
| Control | Some advanced knobs are abstracted away; you rely on Cloudflare’s defaults for many settings. | Full control over cache behaviors, request/response headers, and price classes. |
If you want the quickest path to a production‑ready CDN with minimal ongoing cost, start with Cloudflare’s free tier. If your infrastructure already lives on AWS and you need fine‑grained control over caching logic or want to keep everything under a single billing account, CloudFront is the natural choice.
Setting Up Cloudflare
1. Create an Account and Add Your Site
- Sign up at cloudflare.com and verify your email.
- Click Add a Site, enter your domain (e.g.,
example.com), and let Cloudflare scan your existing DNS records. - Review the imported records; make sure every A, CNAME, MX, and TXT entry is present.
2. Point Your Domain to Cloudflare
Cloudflare will show you two nameservers (e.g., lea.ns.cloudflare.com). Log into your domain registrar and replace the existing nameservers with these two. Propagation usually finishes within minutes, but allow up to 48 hours for safety.
3. Enable Proxying (the Orange Cloud)
In the DNS dashboard, toggle the cloud icon next to each record you want CDN‑protected (typically your A and www CNAME records) to orange. Gray clouds mean DNS‑only—use those for services like mail or FTP that should bypass the CDN.
4. Configure SSL/TLS
- Go to SSL/TLS → Overview and set the encryption mode to Full (Strict). This requires a valid certificate on your origin (Let’s Encrypt works fine).
- Turn on Always Use HTTPS and Automatic HTTPS Rewrites to mixed‑content fix insecure resources.
5. Define Caching Rules
Cloudflare offers Page Rules (legacy) and the newer Cache Rules interface. For a typical WordPress or static site:
| Rule | Match | Cache Level | Edge TTL | Browser TTL |
|---|---|---|---|---|
| Static assets | .example.com/.{css,js,woff2,woff,ttf,eot,svg,png,jpg,jpeg,gif,ico} | Cache Everything | 1 month | 1 month |
| Images in uploads | .example.com/wp-content/uploads/ | Cache Everything | 7 days | 7 days |
| Admin & login | .example.com/wp-admin/ <br> *.example.com/wp-login.php | Bypass | – | – |
| HTML pages (optional) | .example.com/ | Cache Everything | 4 hours | 1 hour |
If you run a static site built with a generator (Hugo, Jekyll, Next.js), you can cache all HTML for a longer period (e.g., 12 hours) because updates are infrequent.
6. Activate Performance Features
- Auto Minify (HTML, CSS, JS) – under Speed → Optimization.
- Brotli compression – enabled automatically for supported browsers.
- Rocket Loader – test first; it can interfere with certain JavaScript frameworks.
- Polish (WebP/AVIF) and Mirage (mobile image optimization) – require Pro or higher.
- Enable Always Online – serves cached pages if your origin goes down.
7. Purge Cache on Content Changes
Install the official Cloudflare WordPress plugin (or use the provided PHP snippet) to automatically purge the updated URL whenever a post is saved. This ensures visitors never see stale HTML after you publish.
Setting Up AWS CloudFront
1. Prepare Your Origin
CloudFront can pull from many origins; the most common for static sites is an Amazon S3 bucket.
- Create an S3 bucket (e.g.,
my-site-assets) in the region closest to your primary audience. - Upload your static files. For immutable assets (hashed filenames), set the
Cache-Controlheader topublic, max-age=31536000, immutablewhen you upload:
aws s3 cp style.abc123.css s3://my-site-assets/style.abc123.css \
--cache-control "public,max-age=31536000,immutable"
- (Optional) Enable Origin Access Control (OAC) so that only CloudFront can read the bucket. This keeps the bucket private and forces all traffic through the CDN.
2. Create the Distribution
- Open the CloudFront console and click Create Distribution.
- Choose Web (the default) and set the Origin Domain to your S3 bucket (or the DNS name of an EC2 instance/ALB).
- Under Origin Access, select the OAC you created.
- Set Viewer Protocol Policy to Redirect HTTP to HTTPS (or HTTPS Only if you prefer).
- Choose Allowed HTTP Methods – GET, HEAD for static sites; add OPTIONS, PUT, POST if you need CORS preflight or API endpoints.
3. Configure Cache Behavior
Create two cache behaviors if you need different treatment for assets vs. HTML:
- *Path Pattern:
.css,.js,.jpg,.png,.woff2** - Cache Policy:
CachingOptimized(TTL 24 hours) - Compress Objects: Yes
- Origin Request Policy:
CORS-S3Origin(forces forwarding of necessary headers)
- *Path Pattern:
/(default)** - Cache Policy: Custom – set Min TTL 0, Max TTL 4 hours, Default TTL 1 hour.
- Forward Cookies: None
- Forward Query Strings: None (unless your app relies on them).
- Origin Request Policy:
AllViewer(forwards headers, cookies, query strings – adjust as needed).
4. Attach a Custom Domain and SSL Certificate
- Request a certificate in AWS Certificate Manager (ACM) for
cdn.example.com(or the apex domain) – must be inus-east-1. - Validate via DNS (the fastest method) and wait for the certificate to move to Issued.
- In the CloudFront distribution, under General Settings → Alternate Domain Names (CNAMEs), add your custom domain.
- Select the ACM certificate, choose a Security Policy (the default
TLSv1.2_2021works fine), and enable HTTP/2 (HTTP/3 can be toggled on if desired). - In your DNS provider, create a CNAME record pointing
cdn.example.comto the CloudFront domain (e.g.,a1b2c3d4.cloudfront.net). For the apex domain, use an ALIAS/ANAME record if your registrar supports it.
5. Set Up Cache Invalidation
When you deploy a new version, you’ll need to tell CloudFront to evict stale objects.
- Full invalidation (
/*) costs $0.005 per 1,000 paths after the first 1,000 free paths each month. Use sparingly. - Path‑specific invalidation (e.g.,
/index.html /app.js) is cheaper. - Preferred method: use versioned filenames (hash‑based) for assets so that a new deploy automatically gets a new URL, eliminating the need for invalidation. For HTML, keep a short TTL (e.g., 5 minutes) or invalidate only that file.
6. Enable Logging and Monitoring
- Turn on Standard Access Logs to an S3 bucket for deep analysis.
- In CloudWatch, monitor CacheHitRatio, 4xx/5xx, and BytesOut to spot issues early.
- Set up alarms if the hit ratio drops below 80 % or if error rates climb.
Optimizing Cache and Headers
Whether you choose Cloudflare or CloudFront, the origin’s Cache-Control header is the source of truth for how long edge nodes and browsers may store a response.
Static Assets with Versioned Filenames
Cache-Control: public, max-age=31536000, immutable
max-agetells browsers to keep the file for a year.immutable(supported by modern browsers) prevents revalidation even on a manual reload, assuming the URL never changes.
Assets Without Version Numbers
Cache-Control: public, max-age=604800, stale-while-revalidate=86400
- One‑week browser cache.
stale-while-revalidatelets the CDN serve a slightly stale object while fetching a fresh copy in the background, hiding latency spikes.
HTML Pages
Cache-Control: public, max-age=300, s-maxage=3600
- Browsers re‑validate every five minutes.
- CDN can keep a copy for an hour, reducing origin load while still picking up updates relatively quickly.
API Endpoints & Private Data
Cache-Control: private, no-store, must-revalidate
- Prevents any caching by browsers or shared caches.
Vital Header: Vary: Accept-Encoding
If your origin serves both gzip and Brotli variants, you must include Vary: Accept-Encoding. Without it, a CDN might cache only the compressed version and serve it to a client that does not support compression, resulting in garbled content.
SSL/TLS Best Practices
- Origin Certificate – Even if the CDN provides a free edge certificate, keep a valid certificate on your origin (Let’s Encrypt is free and easy to automate). Set Cloudflare to Full (Strict) or CloudFront to HTTPS Only for origin connections.
- HTTP Strict Transport Security (HSTS) – Enable on the CDN (Cloudflare: SSL/TLS → Edge Certificates → HSTS) or via a response header policy in CloudFront. Include a
max-ageof at least 31536000 seconds and considerincludeSubDomainsandpreloadif you’re ready. - Automatic HTTPS Rewrites – Cloudflare’s feature rewrites
http://links tohttps://in HTML, CSS, and JS, eliminating mixed‑content warnings. - Origin Shield (CloudFront) – Adds an extra caching layer that reduces the number of requests hitting your origin, especially useful for geographically dispersed audiences.
Cache Invalidation Strategies
Invalidation is necessary when you cannot rely on versioned filenames (e.g., HTML pages, API responses). Keep these tips in mind:
- Prefer versioning – Append a content hash to filenames (
app.3f2e1d.js). Changes automatically produce a new URL, so the cache misses without any API calls. - Use soft TTLs for dynamic content – Set a short
max-age(5 minutes) and rely onstale-while-revalidateto serve stale content while fetching a fresh version. - Batch invalidations – If you must purge many files, combine them into a single invalidation request to stay within the free tier limits.
- Monitor cost – CloudFront charges per path after the first 1,000 free paths each month. Cloudflare’s purge API is free on all plans, making it attractive for frequent updates.
Monitoring, Testing, and Ongoing Tuning
After you’ve deployed the CDN, verify that it’s actually delivering cached responses.
- Check response headers –
curl -I https://example.com/style.cssshould show: - Cloudflare:
CF-Cache-Status: HIT - CloudFront:
X-Cache: Hit from cloudfront - Measure TTFB – Use tools like WebPageTest or KeyCDN’s performance test from multiple locations. Expect a drop from 200‑300 ms (origin only) to 15‑30 ms when cached.
- Review analytics – Cloudflare’s Analytics → Cache → Cache Hit Ratio; CloudFront’s CacheHitRatio metric in CloudWatch. Aim for > 90 % on static assets.
- Run Lighthouse – Confirm improvements in Largest Contentful Paint (LCP) and Total Blocking Time (TBT).
- Set up alerts – Notify you if the hit ratio falls below a threshold or if error rates spike.
Cost Considerations
| Scenario | Cloudflare Cost | CloudFront Cost (approx.) |
|---|---|---|
| Low‑traffic personal blog (< 5 GB/month) | Free tier (unmetered bandwidth) | Free tier: 1 TB + 10 M requests → effectively $0 |
| Medium site (100 GB/month, 2 M requests) | Free tier still covers bandwidth; optional Pro $20/mo for WAF & image optimization | 100 GB × $0.085/GB ≈ $8.50 + request fee + request fees (~$1) → ~ $10/mo |
| High‑traffic static site (5 TB/month) | Business plan $200/mo (unmetered) | 5 TB × $0.085/GB ≈ $425 + request fees → significantly higher |
If your traffic is mostly cacheable static assets, Cloudflare’s flat‑fee model often wins at scale. CloudFront becomes attractive when you already run other AWS services, need custom edge logic (Lambda@Edge), or want granular price‑class control to exclude expensive regions.
Common Pitfalls and How to Avoid Them
| Symptom | Likely Cause | Fix |
|---|---|---|
| Users see old content after a deploy | Missing cache‑busting (no hashed filenames) or stale TTL too long | Adopt versioned filenames or reduce TTL; purge/invalidate as needed |
| Mixed‑content warnings (HTTP resources on HTTPS page) | Origin serves HTTP assets or CDN rewrites not enabled | Enable Automatic HTTPS Rewrites (Cloudflare) or enforce HTTPS only (CloudFront); fix hardcoded http:// links |
| High origin load despite CDN | Cache‑Control missing or set to no-cache; cookies/query strings needlessly varied | Ensure static assets send proper public, max-age headers; strip unnecessary cookies/query strings in cache policy |
| SSL handshake errors | Origin certificate expired or CN mismatch; Cloudflare set to Flexible | Install a valid origin cert; switch Cloudflare to Full (Strict) |
| CORS blocking fonts or API calls | Missing Vary: Accept-Encoding or Access-Control-Allow-Origin header | Add the headers at origin or via Cloudflare Transform Rules / CloudFront Response Headers Policy |
| Unexpected charges on CloudFront | Large number of invalidation paths or high request count | Switch to versioned filenames; tighten cache policies to reduce origin fetches; monitor usage in CloudWatch Billing |
Conclusion
Setting up a CDN is one of the highest‑impact, low‑effort moves you can make for a modern website. Cloudflare gives you a fast, free‑tier path with a friendly interface and built‑in performance tools, while AWS CloudFront offers deep integration, programmable edge functions, and a pay‑as‑you‑go model that aligns well with existing AWS workloads.
Whichever platform you pick, focus on three pillars:
- Correct DNS and SSL configuration – traffic must flow through the CDN securely.
- Smart cache headers – let the edge nodes store static assets for as long as safely possible while keeping dynamic content fresh.
- Reliable purge or versioning strategy – ensure visitors always see the latest version after you deploy.
By following the step‑by‑step instructions above, monitoring the key metrics, and iterating on your cache rules, you’ll see noticeable drops in Time to First Byte, improvements in LCP and CLS, and a healthier origin server that can handle genuine traffic spikes without breaking a sweat. Happy caching!
