A properly configured CDN reduces origin server load by 85-95% and cuts global P50 latency from 200-400ms to under 30ms. The key decisions are cache key design, TTL policies per content type, invalidation strategy, and security header propagation. This guide covers production-ready configurations for Cloudflare, AWS CloudFront, and self-hosted CDN setups.
According to the 2025 HTTP Archive report, sites using a CDN load 52% faster on average than those serving directly from origin. However, 41% of CDN configurations contain at least one critical misconfiguration, most commonly caching authenticated responses, missing security headers, or invalidating too aggressively.
---
Edge Caching Rules
Edge caching rules determine what content is cached at CDN edge nodes, for how long, and under what conditions.
Cache-Control Headers
<h1>Static assets: cache for 1 year, immutable</h1>
<h1>(use content hashing in filenames for cache busting)</h1>
Cache-Control: public, max-age=31536000, immutable
<h1>HTML pages: revalidate on every request</h1>
Cache-Control: public, max-age=0, must-revalidate
<h1>API responses: short cache for read endpoints</h1>
Cache-Control: public, max-age=60, s-maxage=300
<h1>Private content: never cache at edge</h1>
Cache-Control: private, no-store
| Content Type | max-age | s-maxage (CDN) | Stale-While-Revalidate | Immutable |
| JS/CSS bundles (hashed) | 1 year | 1 year | No | Yes |
| Images (hashed) | 1 year | 1 year | No | Yes |
| Fonts | 1 year | 1 year | No | Yes |
| HTML pages | 0 | 5 min | 1 hour | No |
| API (public) | 60s | 5 min | 30s | No |
| API (authenticated) | 0 | 0 | No | No |
Cloudflare Page Rules Example
<h1>Cloudflare cache rules via API</h1>
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/pagerules" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
-d '{
"targets": [{"target": "url", "constraint": {"operator": "matches", "value": "example.com/static/*"}}],
"actions": [
{"id": "cache_level", "value": "cache_everything"},
{"id": "edge_cache_ttl", "value": 2592000},
{"id": "browser_cache_ttl", "value": 31536000}
],
"status": "active"
}'
---
Cache Invalidation Strategies
Cache invalidation is the hardest problem in CDN management. The three approaches are TTL-based expiry, tag-based purging, and URL-based purging.
<h1>Cloudflare: Purge specific URLs</h1>
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/api/products", "https://example.com/pricing"]}'
<h1>Cloudflare: Purge by cache tag</h1>
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 '{"tags": ["product-catalog", "pricing-page"]}'
<h1>CloudFront: Create invalidation</h1>
aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths "/api/products" "/pricing"
| Strategy | Latency | Cost | Precision | Best For |
| TTL expiry | Bounded by TTL | Free | Low | Static content |
| URL purge | 2-30 seconds | Per request | High | Individual pages |
| Tag purge | 2-30 seconds | Per request | Medium | Content groups |
| Full purge | 2-60 seconds | Per request | None | Emergency only |
---
Origin Shielding
Origin shielding adds an intermediate cache layer between edge nodes and your origin server. Instead of 200+ edge nodes hitting your origin, a single shield node consolidates requests.
Without origin shielding, a cache miss at any edge node hits your origin. With 200 edge nodes and a 5-minute TTL, your origin receives approximately 200 requests per cacheable URL every 5 minutes during peak traffic. Origin shielding reduces this to 1 request per 5 minutes regardless of edge node count.
<h1>CloudFront: Enable origin shield</h1>
aws cloudfront update-distribution \
--id E1234567890 \
--origin-shield \
Enabled=true,OriginShieldRegion=us-east-1
---
Security Headers
CDN edge nodes should add security headers to all responses.
<h1>Cloudflare Transform Rules or Worker</h1>
<h1>Add security headers to all responses</h1>
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
| Header | Purpose | Impact |
| HSTS | Force HTTPS | Prevents downgrade attacks |
| X-Content-Type-Options | Prevent MIME sniffing | Blocks content-type attacks |
| X-Frame-Options | Prevent clickjacking | Blocks iframe embedding |
| Content-Security-Policy | Control resource loading | Prevents XSS |
| Permissions-Policy | Restrict browser APIs | Reduces attack surface |
---
WebSocket Support Through CDN
Most CDNs now support WebSocket connections, but configuration is required to prevent the CDN from buffering or terminating long-lived connections.
<h1>Nginx CDN proxy configuration for WebSocket</h1>
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
For DNS configuration that works with your CDN setup, see our DNS management guide. Teams implementing SSL at the CDN edge should read our SSL/TLS certificate management guide. For a broader performance strategy including CDN, caching, and backend optimization, check our low-latency hosting architecture guide.
---
Frequently Asked Questions
Should I cache API responses at the CDN edge?
Cache public, read-only API responses (product listings, search results, public profiles) with short TTLs (1-5 minutes). Never cache authenticated API responses, POST/PUT/DELETE requests, or responses containing user-specific data. Use the Vary header to create separate cache entries for different Accept-Language or Accept-Encoding values.
How do I debug CDN cache misses?
Check response headers: CF-Cache-Status (Cloudflare), X-Cache (CloudFront), or X-Cache-Status (custom). Common miss reasons: Vary header mismatch, query string differences, Set-Cookie in response (prevents caching), or Cache-Control: private. Use curl with -I flag to inspect headers without downloading the body.
Is stale-while-revalidate safe for production?
Yes, for non-critical content. Stale-while-revalidate serves the cached version immediately while fetching a fresh copy in the background. Users see slightly stale content for one request after TTL expiry, but they get instant response times. Do not use it for financial data, authentication state, or real-time pricing.
How much does CDN caching reduce origin costs?
A well-configured CDN with 90%+ cache hit rate reduces origin bandwidth by 90% and origin compute (CPU) by 60-80%. For a site serving 10 million requests per day, this translates to roughly $200-500 per month in saved origin infrastructure costs, depending on content type and provider.
Should I use a multi-CDN setup?
Multi-CDN is justified only at very high traffic volumes (100M+ requests/day) or when you need guaranteed uptime beyond a single CDN SLA (99.99%+). For most applications, a single CDN with proper failover to origin is sufficient. Multi-CDN adds complexity in cache invalidation, SSL certificate management, and DNS routing.