← Back to Blog

CDN Setup Guide: Speed Up Your Website Globally

A Content Delivery Network caches your website's assets across dozens of edge locations worldwide, slashing load times for users far from your origin server. This guide walks through setting up Cloudflare and AWS CloudFront from scratch, configuring cache rules that actually work, and validating that caching is functioning correctly.

Why Your Website Needs a CDN

Without a CDN, every user - whether they are in Tokyo or Toronto - connects to your single origin server. If your server is in us-east-1, a user in Singapore experiences 250–300ms of network latency before a single byte of your page is delivered. That is before any processing time.

A CDN solves this by caching static content (HTML, CSS, JS, images, fonts) at edge nodes close to the user. The performance improvement is immediate and dramatic:

  • Time to First Byte (TTFB): Drops from 250ms to 15-30ms for cached responses
  • Origin server load: Reduced by 60-90% when static assets are fully cached
  • DDoS protection: CDNs absorb volumetric attacks at the edge before they reach your origin
  • SSL termination: The CDN handles TLS handshakes, reducing cryptographic overhead on your origin
  • Bandwidth costs: CDN bandwidth is typically 5-10x cheaper than origin server bandwidth

CDN Options: Which to Choose

The three most common CDN choices for developers and small-to-medium sites are:

  • Cloudflare: The easiest setup. Acts as a DNS proxy, so all traffic routes through Cloudflare automatically. Free tier is genuinely useful. Best choice for most websites.
  • AWS CloudFront: Deep integration with AWS services (S3, ALB, API Gateway). Pay-per-use pricing. More configuration required but highly flexible. Best choice when your stack is already AWS.
  • Fastly: Developer-friendly with real time purge API and edge computing (Compute@Edge). More expensive but excellent for complex caching logic. Best for large-scale applications with dynamic caching needs.

Option 1: Cloudflare Setup (Step-by-Step)

Cloudflare is the fastest way to get a CDN in front of your website. The setup takes about 15 minutes.

  1. Create a Cloudflare account at cloudflare.com and click "Add a Site". Enter your domain name.
  2. Select a plan. The Free plan includes CDN, DDoS protection, and SSL. It is sufficient for most sites. Pro ($20/mo) adds image optimization and advanced WAF rules.
  3. Cloudflare scans your DNS records and imports them. Review the list carefully. Ensure all records are present before changing nameservers.
  4. Enable the orange cloud (proxy) on DNS records. Records with a gray cloud are DNS-only (no CDN). Click the cloud icon next to your A/CNAME records to enable proxying. The orange cloud means Cloudflare will cache and proxy traffic to that hostname.
  5. Update your nameservers at your domain registrar to the two Cloudflare nameservers shown in the dashboard. This is the critical step - traffic will not route through Cloudflare until nameservers are updated.
  6. Wait for propagation. DNS changes typically take 5–30 minutes but can take up to 48 hours. Cloudflare's dashboard shows "Active" when it is working.
# Verify Cloudflare is active by checking the CF-Ray header
curl -sI https://yourdomain.com | grep -i cf-ray
# CF-Ray: 8b2a3f4e5c6d7890-LHR  ← if this appears, Cloudflare is active

Cloudflare Cache Configuration

After activation, configure caching under Caching > Configuration:

  • Caching Level: Set to "Standard". This caches based on the query string (ignores query parameters for static assets).
  • Browser Cache TTL: "Respect Existing Headers" is the correct choice - it honours the Cache-Control headers your origin sends.
  • Always Online: Serves cached pages if your origin is down. Enable this.

To cache HTML pages (Cloudflare does not cache HTML by default), create a Cache Rule:

Cache Rule:
  When: hostname equals yourdomain.com AND path matches /*
  Then: Cache Eligibility = Eligible for cache
        Edge TTL = 4 hours
        Browser TTL = 1 hour

Option 2: AWS CloudFront Setup (Step-by-Step)

CloudFront is the right choice if your origin is an S3 bucket, an EC2 instance, an ALB, or an API Gateway endpoint.

  1. Open the CloudFront console and click "Create Distribution".
  2. Set the Origin Domain. For an S3 bucket: select it from the dropdown and enable OAC (Origin Access Control) so the bucket is only accessible via CloudFront. For an EC2 or ALB: enter the DNS name as a Custom Origin.
  3. Configure the Default Cache Behavior:
    • Viewer Protocol Policy: "Redirect HTTP to HTTPS"
    • Allowed HTTP Methods: GET, HEAD (add PUT/POST/DELETE only for API endpoints)
    • Cache Policy: "CachingOptimized" for static assets, or create a custom policy
    • Origin Request Policy: "CORS-S3Origin" for S3 buckets
  4. Add alternate domain names (CNAMEs). Enter your domain (www.yourdomain.com) and select an ACM certificate for HTTPS.
  5. Create the distribution. CloudFront generates a domain like d1234567890.cloudfront.net.
  6. Update your DNS. Add a CNAME record: www.yourdomain.com CNAME d1234567890.cloudfront.net. For the apex domain (yourdomain.com), use an ALIAS or ANAME record pointing to the CloudFront domain.
# Verify CloudFront is active
curl -sI https://www.yourdomain.com | grep -i x-cache
# X-Cache: Hit from cloudfront  ← cached response
# X-Cache: Miss from cloudfront ← cache miss, fetched from origin

CloudFront Cache Invalidation

When you deploy a new version of your site, you need to invalidate CloudFront's cache:

# Invalidate all files (use sparingly - costs $0.005 per 1000 paths after first 1000/month)
aws cloudfront create-invalidation \
  --distribution-id E1234567890ABC \
  --paths "/*"

# Invalidate specific files
aws cloudfront create-invalidation \
  --distribution-id E1234567890ABC \
  --paths "/index.html" "/app.js" "/style.css"

Check Your DNS and CDN Configuration

Use our free DNS Lookup tool to verify CNAME records, check propagation status, and confirm your CDN setup is working correctly.

Open DNS Lookup →

Cache-Control Headers: The Most Important Setting

Your origin server's Cache-Control headers determine how long CDNs and browsers cache your content. Get these right:

# Static assets with versioned filenames (cache forever)
Cache-Control: public, max-age=31536000, immutable
# Use when filename includes a hash: style.abc123.css

# HTML pages (cache briefly, revalidate)
Cache-Control: public, max-age=300, s-maxage=3600
# max-age = browser cache (5 min), s-maxage = CDN cache (1 hour)

# API responses (do not cache)
Cache-Control: no-store, no-cache, must-revalidate

# User-specific content (browser cache only, not CDN)
Cache-Control: private, max-age=600

The key distinction: max-age controls browser caching, while s-maxage specifically controls CDN (shared cache) TTL. When you want long CDN caching but short browser caching, use both directives together.

The most common CDN caching mistake is not including a content hash in asset filenames. Without hashed filenames, you cannot safely cache assets for more than a few minutes because you cannot predict when a user's browser will pick up the old cached version after a deployment.

Cache-Busting: How to Deploy Updates Safely

Long-lived caches require a cache-busting strategy so users always get the latest version after a deployment:

  • Content hashing in filenames (best practice): Build tools like Webpack, Vite, and Parcel automatically append a content hash to asset filenames: app.3f2e1d.js. When the file changes, the hash changes, the filename changes, and caches automatically miss.
  • Query string versioning: Append a version to URLs: style.css?v=1.2.3. Less reliable because some CDNs ignore query strings by default.
  • Manual cache purge: After deployment, trigger a CDN cache purge for changed files. Cloudflare has a "Purge Cache" button and API. CloudFront uses invalidations (see above).

Step-by-Step: Validating CDN Performance

After setup, verify that caching is working correctly:

  1. Check cache hit headers using curl or browser DevTools:
    curl -sI https://yourdomain.com/style.css | grep -i cache
    # CF-Cache-Status: HIT          ← Cloudflare served from cache
    # Age: 3600                     ← cached for 3600 seconds
    # Cache-Control: public, max-age=86400
  2. Test from multiple geographic locations using tools like keycdn.com/tools/performance-test or webpagetest.org. Compare TTFB from different regions.
  3. Confirm your origin is not being hammered. In Cloudflare Analytics, check the "Cached" vs "Uncached" request ratio. A healthy static site should have 70-90%+ cache hit rate.
  4. Run a PageSpeed Insights test before and after CDN setup. You should see significant improvements in LCP (Largest Contentful Paint) and TTFB for users in distant regions.

Common CDN Configuration Mistakes

  • Caching pages with user-specific content: If your HTML contains user data (name, cart count, etc.) and you cache it at the CDN level, all users get the same page. Use Cache-Control: private for personalized pages, or use ESI (Edge Side Includes) to cache the layout and embed dynamic fragments.
  • Not setting Vary: Accept-Encoding: If your origin serves both gzip-compressed and uncompressed responses, the CDN must cache them separately. Add Vary: Accept-Encoding to your response headers.
  • Caching 404 responses: If your origin returns a 404 for a missing asset and the CDN caches it, every subsequent request gets the cached 404 even after you fix the file. Set short TTLs for error responses.
  • Forgetting to update DNS TTL before the switchover: Lower your DNS record TTL to 60 seconds at least 24 hours before pointing to a CDN. This ensures fast rollback if something goes wrong.
  • SSL mismatches: Cloudflare's default SSL mode is "Flexible" (HTTP between Cloudflare and origin), which can cause redirect loops if your origin also enforces HTTPS. Set it to "Full (Strict)".

FAQ

Does a CDN help with dynamic content?

Yes, in two ways. First, the CDN's TCP/TLS termination at the edge reduces connection latency even for uncached requests. Second, modern CDNs support edge computing (Cloudflare Workers, CloudFront Functions) that let you run logic at the edge to personalize or transform responses without hitting your origin.

Will a CDN break my website?

It can, if misconfigured. The most common issue is caching pages that should not be cached (login pages, checkout flows, admin areas). The fix is to ensure those pages send Cache-Control: no-store or to set up CDN bypass rules for authenticated routes.

How do I prevent Cloudflare from caching my admin panel?

Create a Page Rule or Cache Rule in Cloudflare: "If URL matches yourdomain.com/admin/* then Cache Level = Bypass". Alternatively, ensure your admin pages send Cache-Control: private, no-store in their response headers.

Is Cloudflare free CDN good enough for a production site?

Yes, for most sites. The Cloudflare free plan includes unlimited CDN bandwidth, DDoS protection, free SSL, and caching. Thousands of high-traffic production sites run on the free plan. You pay for advanced features like image optimization, custom WAF rules, Workers, and analytics - not for bandwidth.

What is the difference between CDN cache and browser cache?

Browser cache stores files on the user's device. CDN cache stores files on CDN edge servers. A CDN cache hit saves the round trip to your origin server. A browser cache hit saves the round trip to the CDN. Both are important: s-maxage controls CDN TTL, max-age controls browser TTL. Use both in your Cache-Control headers to maximize performance.

Use our free tool here → DNS Lookup on SecureBin.ai

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.