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.

AspectCloudflareAWS CloudFront
PricingFixed 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.
SetupChange 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 optimizationsAuto 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.
IntegrationWorks with any host; offers DNS, SSL, WAF, and a bot‑management suite.Deeply integrated with S3, EC2, API Gateway, WAF, Shield, and Certificate Manager.
ControlSome 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

  1. Sign up at cloudflare.com and verify your email.
  2. Click Add a Site, enter your domain (e.g., example.com), and let Cloudflare scan your existing DNS records.
  3. 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:

RuleMatchCache LevelEdge TTLBrowser TTL
Static assets.example.com/.{css,js,woff2,woff,ttf,eot,svg,png,jpg,jpeg,gif,ico}Cache Everything1 month1 month
Images in uploads.example.com/wp-content/uploads/Cache Everything7 days7 days
Admin & login.example.com/wp-admin/ <br> *.example.com/wp-login.phpBypass
HTML pages (optional).example.com/Cache Everything4 hours1 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.

  1. Create an S3 bucket (e.g., my-site-assets) in the region closest to your primary audience.
  2. Upload your static files. For immutable assets (hashed filenames), set the Cache-Control header to public, max-age=31536000, immutable when you upload:
   aws s3 cp style.abc123.css s3://my-site-assets/style.abc123.css \
       --cache-control "public,max-age=31536000,immutable"
  1. (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

  1. Open the CloudFront console and click Create Distribution.
  2. Choose Web (the default) and set the Origin Domain to your S3 bucket (or the DNS name of an EC2 instance/ALB).
  3. Under Origin Access, select the OAC you created.
  4. Set Viewer Protocol Policy to Redirect HTTP to HTTPS (or HTTPS Only if you prefer).
  5. 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

  1. Request a certificate in AWS Certificate Manager (ACM) for cdn.example.com (or the apex domain) – must be in us-east-1.
  2. Validate via DNS (the fastest method) and wait for the certificate to move to Issued.
  3. In the CloudFront distribution, under General Settings → Alternate Domain Names (CNAMEs), add your custom domain.
  4. Select the ACM certificate, choose a Security Policy (the default TLSv1.2_2021 works fine), and enable HTTP/2 (HTTP/3 can be toggled on if desired).
  5. In your DNS provider, create a CNAME record pointing cdn.example.com to 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-age tells 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-revalidate lets 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-age of at least 31536000 seconds and consider includeSubDomains and preload if you’re ready.
  • Automatic HTTPS Rewrites – Cloudflare’s feature rewrites http:// links to https:// 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:

  1. 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.
  2. Use soft TTLs for dynamic content – Set a short max-age (5 minutes) and rely on stale-while-revalidate to serve stale content while fetching a fresh version.
  3. Batch invalidations – If you must purge many files, combine them into a single invalidation request to stay within the free tier limits.
  4. 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 headerscurl -I https://example.com/style.css should 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

ScenarioCloudflare CostCloudFront 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 optimization100 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

SymptomLikely CauseFix
Users see old content after a deployMissing cache‑busting (no hashed filenames) or stale TTL too longAdopt 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 enabledEnable Automatic HTTPS Rewrites (Cloudflare) or enforce HTTPS only (CloudFront); fix hardcoded http:// links
High origin load despite CDNCache‑Control missing or set to no-cache; cookies/query strings needlessly variedEnsure static assets send proper public, max-age headers; strip unnecessary cookies/query strings in cache policy
SSL handshake errorsOrigin certificate expired or CN mismatch; Cloudflare set to FlexibleInstall a valid origin cert; switch Cloudflare to Full (Strict)
CORS blocking fonts or API callsMissing Vary: Accept-Encoding or Access-Control-Allow-Origin headerAdd the headers at origin or via Cloudflare Transform Rules / CloudFront Response Headers Policy
Unexpected charges on CloudFrontLarge number of invalidation paths or high request countSwitch 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:

  1. Correct DNS and SSL configuration – traffic must flow through the CDN securely.
  2. Smart cache headers – let the edge nodes store static assets for as long as safely possible while keeping dynamic content fresh.
  3. 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!

Share this post:
How to Set Up a CDN with Cloudflare and AWS CloudFront: A Step‑by‑Step Guide