What Is a Content Delivery Network?
A Content Delivery Network (CDN) is a geographically distributed network of servers that delivers web content from locations physically close to the user requesting it. Without a CDN, every request travels to your origin server — which might be in Frankfurt, Germany, while your visitor is in Sydney, Australia. That is approximately 16,000 kilometers of network hops, adding 200-300 milliseconds of latency just from the speed of light through fiber optic cables.
With a CDN, that same request is served from a Point of Presence (PoP) in Sydney, reducing latency to 5-20 milliseconds. The CDN stores a cached copy of your content at each edge location and serves it directly to nearby users. The result is dramatically faster page loads, reduced origin server load, improved reliability through redundancy, and built-in DDoS protection.
In this guide, we will break down exactly how CDNs work, how to configure the most popular providers, and the technical details of cache control that determine how effectively your CDN performs.
Sydney, AU
Anycast routing
Sydney edge
HIT or MISS
< 20ms latency
How Edge Caching Works
Edge caching is the core mechanism of every CDN. When a user requests a resource that has never been requested through that specific edge server before, the CDN fetches it from your origin server, stores a copy, and serves it to the user. All subsequent requests for the same resource at that edge location are served directly from cache — no trip to the origin required.
Cache HIT vs Cache MISS
Cache MISS (First Request)
The edge server does not have the content cached. It fetches from origin, stores a copy, and serves to the user. Total latency: 200-500ms (origin + edge).
Cache HIT (Subsequent Requests)
The edge server has the content cached. It serves directly without contacting origin. Total latency: 5-20ms. This is where the real performance gain happens.
$ curl -sI https://example.com/style.css | grep -i "cf-cache-status\|x-cache\|age"
cf-cache-status: HIT
age: 3847
# First request (MISS)
$ curl -sI https://example.com/new-page.html | grep cf-cache-status
cf-cache-status: MISS
# Second request (HIT - now cached)
$ curl -sI https://example.com/new-page.html | grep cf-cache-status
cf-cache-status: HIT
Anycast DNS Routing
CDNs use Anycast DNS routing to direct users to their nearest edge server. In traditional (unicast) DNS, a domain resolves to a single IP address, and all users connect to that one server. With Anycast, the same IP address is announced from multiple locations worldwide. When a user makes a DNS query, the internet's BGP routing protocol automatically directs the request to the geographically nearest server announcing that IP.
Cache-Control Headers: The Complete Guide
The Cache-Control HTTP header is how your origin server tells the CDN (and browsers) how to cache each response. Getting these headers right is the difference between a CDN that saves 95% of your origin traffic and one that barely helps.
| Directive | Who It Affects | What It Does |
|---|---|---|
public | CDN + Browser | Response can be cached by any cache, including CDN edge servers |
private | Browser only | Response can only be cached in the user's browser, not by CDN |
max-age=N | CDN + Browser | Cache is valid for N seconds from the time of the request |
s-maxage=N | CDN only | Overrides max-age for shared caches (CDN). Browser ignores this. |
no-cache | CDN + Browser | Must revalidate with origin before serving (NOT "do not cache") |
no-store | CDN + Browser | Do not cache the response at all. Use for sensitive data. |
immutable | Browser | Resource will never change. Browser skips revalidation even on reload. |
stale-while-revalidate=N | CDN + Browser | Serve stale content for N seconds while fetching a fresh version in the background |
no-cache Does NOT Mean "Do Not Cache." The name is misleading. no-cache means "cache it, but always check with the origin before serving." To truly prevent caching, use no-store. Many developers use no-cache thinking it prevents caching, then wonder why their CDN is still serving cached content.
Recommended Cache-Control by Content Type
# Static assets with hash in filename (main.a1b2c3.js)
location ~* \.(js|css)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Images (might be updated, 6-month cache)
location ~* \.(jpg|jpeg|png|gif|webp|avif|svg|ico)$ {
add_header Cache-Control "public, max-age=15552000";
}
# Fonts (rarely change, 1-year cache)
location ~* \.(woff2?|ttf|eot|otf)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
# HTML pages (short cache with background revalidation)
location ~* \.html$ {
add_header Cache-Control "public, max-age=300, s-maxage=3600, stale-while-revalidate=86400";
}
# API responses (private, no CDN caching)
location /api/ {
add_header Cache-Control "private, no-cache, no-store";
}
Cache Invalidation Strategies
The hardest part of CDN caching is knowing when to invalidate cached content. Phil Karlton famously said, "There are only two hard things in Computer Science: cache invalidation and naming things." Here are the practical strategies:
Cache Purging
Manually tell the CDN to delete specific cached resources. All major CDNs offer purge APIs. Cloudflare allows purging by URL, tag, or entire zone. Use when content changes are infrequent and you need immediate updates.
Cache Busting (Versioning)
Append a version string or hash to the filename: style.v3.css or app.a1b2c3.js. Since the URL changes, the CDN treats it as a completely new resource. The most reliable approach for static assets.
Short TTL + Stale-While-Revalidate
Set a short max-age (5 minutes) with a long stale-while-revalidate (24 hours). Users always get fast responses (served from cache), but the CDN checks for updates every 5 minutes in the background.
Cache Tags (Surrogate Keys)
Tag cached responses with identifiers (e.g., product-123, category-shoes). When a product changes, purge all resources tagged with that product ID. Available on Fastly, Cloudflare Enterprise, and Varnish.
Setting Up Cloudflare (Free Tier)
Cloudflare is the most widely used CDN, and its free tier is remarkably generous. Here is a complete setup guide:
ava.ns.cloudflare.com and lee.ns.cloudflare.com). Propagation takes 1-24 hours.$ curl -X POST \
"https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{"files":["https://example.com/style.css","https://example.com/logo.png"]}'
{"success":true,"result":{"id":"abc123"}}
# Purge everything (use sparingly)
$ curl -X POST \
"https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-d '{"purge_everything":true}'
BunnyCDN: The Developer-Friendly Alternative
BunnyCDN is a popular alternative to Cloudflare, especially for developers who want simple pricing and excellent performance. It uses a pull zone model where you point BunnyCDN at your origin, and it caches content automatically.
$ curl -X POST \
"https://api.bunny.net/pullzone/{pull_zone_id}/purgeCache" \
-H "AccessKey: {api_key}"
{"HttpCode":200,"Message":"OK"}
# Purge specific URL
$ curl -X POST \
"https://api.bunny.net/purge?url=https://cdn.example.com/style.css" \
-H "AccessKey: {api_key}"
| Feature | Cloudflare Free | BunnyCDN | KeyCDN |
|---|---|---|---|
| Pricing | Free | $0.01/GB (pay-as-you-go) | $0.04/GB (min $4/month) |
| Global PoPs | 310+ | 114+ | 60+ |
| DNS management | Included | Separate service | No |
| DDoS protection | Included | Basic | Basic |
| Image optimization | Pro plan only | Included | No |
| WebP/AVIF auto-convert | Polish (Pro) | Optimizer | No |
| Custom SSL | Free | Free (Let's Encrypt) | Free (Let's Encrypt) |
| Real-time analytics | Yes | Yes | Yes |
Origin Shield: Protecting Your Server
Origin Shield is a CDN feature that adds an extra caching layer between your edge PoPs and your origin server. Without Origin Shield, if your content expires in 100 different PoPs simultaneously, your origin receives 100 requests. With Origin Shield, only the shield server contacts your origin — the 100 PoPs fetch from the shield instead.
Cache expired
Single layer
1 request only
HTTPS with CDN
Running HTTPS through a CDN involves three connection segments, each with its own encryption:
| Segment | Encryption | Certificate |
|---|---|---|
| User → CDN Edge | TLS 1.2/1.3 | CDN's certificate (or your custom cert) |
| CDN Edge → Origin Shield | TLS (internal) | CDN's internal certificates |
| CDN/Shield → Origin | TLS (Full Strict) | Your origin's certificate (Let's Encrypt, etc.) |
CDN for Dynamic Content
CDNs are not just for static files. Modern CDNs can accelerate dynamic content too, though the strategies differ:
Short-TTL Caching
Cache API responses for 5-60 seconds with s-maxage. This absorbs traffic spikes without serving significantly stale data. A 30-second cache on a popular API endpoint can reduce origin load by 90% during peak traffic.
Stale-While-Revalidate
Serve cached content immediately while checking for updates in the background. Users get instant responses, and the data is never more than one TTL cycle old. Ideal for dashboards and feeds.
Edge Computing
Run code at the CDN edge (Cloudflare Workers, Fastly Compute). Process requests, modify responses, or serve personalized content without hitting your origin. Sub-millisecond cold starts make this viable for real-time applications.
WebSocket Through CDN
Most CDNs now support WebSocket connections. Cloudflare passes WebSocket traffic through its network, providing DDoS protection and routing optimization for real-time applications like chat and live updates.
Performance Metrics: Cache Hit Ratio
The most important CDN metric is your cache hit ratio — the percentage of requests served from cache versus those that hit your origin. A well-configured CDN should achieve 90-99% cache hit ratio for static content.
If your cache hit ratio is below 80%, investigate these common causes:
- Missing or incorrect Cache-Control headers on your origin
- Query strings creating unique cache keys for the same content
- Vary header set too broadly (e.g.,
Vary: *) - Content being marked as private or no-store unintentionally
- Low traffic to specific URLs (cache expires before next request)
- Cookies being sent for static asset requests
Common CDN Mistakes
| Mistake | Impact | Fix |
|---|---|---|
| Caching authenticated content | Security breach | Use private, no-store for any response containing user data |
| Missing Vary header | Wrong content served | Add Vary: Accept-Encoding minimum; Vary: Accept for image format negotiation |
| Caching Set-Cookie responses | Session hijacking | Strip Set-Cookie from cacheable responses or mark them no-store |
| Too-short TTL on static assets | Low hit ratio | Use 1-year TTL with cache busting for versioned assets |
| No cache purge automation | Stale content | Integrate CDN purge API into your deployment pipeline |
| Ignoring mobile vs desktop | Wrong version served | Use Vary: User-Agent or responsive design (no separate mobile site) |
Cost Analysis
CDN pricing varies significantly by provider and usage pattern. Here is a realistic cost breakdown for a site serving 1 TB of content per month:
| Provider | Monthly Cost (1 TB) | Notes |
|---|---|---|
| Cloudflare Free | $0 | Unlimited bandwidth on free plan; limited features |
| Cloudflare Pro | $20/month | Image optimization, WAF, more analytics |
| BunnyCDN | $10 | Pay-per-use, no minimum commitment |
| KeyCDN | $40 | Pay-per-use, $4 minimum |
| AWS CloudFront | $85 | First 10 TB at $0.085/GB |
| Fastly | $100+ | Enterprise features, real-time logging |
Implementation Checklist
Whether you choose Cloudflare, BunnyCDN, or any other provider, follow this checklist to ensure your CDN is configured correctly:
- Set proper Cache-Control headers on your origin for every content type
- Use "Full (Strict)" SSL mode — never Flexible
- Add Vary: Accept-Encoding to all text-based responses
- Enable compression (Gzip and/or Brotli) at both origin and CDN
- Never cache responses containing Set-Cookie or authentication data
- Use cache busting (filename hashing) for CSS and JavaScript
- Set up automatic cache purging in your deployment pipeline
- Monitor cache hit ratio — target 90%+ for static content
- Enable HTTP/2 and HTTP/3 at the CDN edge
- Configure Origin Shield if your server has limited capacity
A properly configured CDN is one of the most cost-effective performance investments you can make. The combination of reduced latency, decreased origin load, improved reliability, and built-in security makes CDN adoption a no-brainer for any serious website. Start with Cloudflare's free tier to experience the benefits immediately, then evaluate paid options as your traffic grows and your optimization needs become more specific.