Most teams add a CDN to their application for one reason: serve static assets faster. This is correct but undersells what a CDN actually does. Modern CDNs are programmable, globally-distributed compute platforms capable of handling routing, security, transformation, and edge logic.
If you're only using your CDN to cache CSS and JavaScript files, you're using 20% of what you're paying for.
Understanding How CDNs Work
A CDN operates a network of Points of Presence (PoPs) globally. When a user makes a request:
User (Frankfurt) → CDN PoP (Frankfurt)
→ Is the response cached at this PoP?
YES → Return cached response (latency: 5-20ms)
NO → Forward to origin, cache response, return to user
The key insight: CDN caching benefits only materialize when the cache hit rate is high. A 20% hit rate means 80% of requests still go to origin — you're adding latency (the CDN hop) for almost no benefit.
Understanding Cache Hit Ratio
Most CDN dashboards show you global hit ratio. The more useful metric is hit ratio per resource type:
Static assets (JS/CSS/images): should be 95-99%
API responses (public): should be 70-90%
HTML pages: depends on caching strategy
User-specific content: should be 0% (never cache)
If your static asset hit ratio is below 90%, investigate why. Common causes:
- Cache keys include unnecessary query parameters
- Cache-Control headers are too short or missing
- Assets don't have content-hash filenames (requests for
/app.jsbypass cache if the CDN sees different hosts)
Cache Key Configuration
By default, CDNs use the full URL as the cache key. This works but leaves performance on the table.
Normalize Query Parameters
Malicious or innocent variance in query parameters creates cache misses:
/api/products?page=1&sort=price → cached
/api/products?sort=price&page=1 → cache MISS (different key!)
/api/products?page=1&sort=price&fbclid=abc123 → cache MISS (analytics param)
Configure your CDN to ignore irrelevant parameters:
Cloudflare: Cache Rules → Cache Key → Query String
→ Ignore specific parameters: fbclid, utm_source, utm_medium, utm_campaign, gclid
AWS CloudFront: Cache Policy → Query Strings
→ Forward: None (for static)
→ Forward: Selected (whitelist: page, sort, per_page)
Vary Header Handling
The Vary header tells the CDN to store separate cache entries based on request headers. Use it correctly:
# For content that varies by Accept-Encoding (compression)
Vary: Accept-Encoding
# For content that varies by Accept (API versioning)
Vary: Accept, Accept-Encoding
# DANGER: Vary: Cookie caches a version per cookie value
# This creates exponential cache key explosion
# Don't do this for public content
CloudFront and Cloudflare both have controls to collapse variations and avoid the Vary explosion problem.
Origin Protection
The CDN should protect your origin from traffic it doesn't need to handle.
Origin Shield
AWS CloudFront's Origin Shield adds a centralized caching layer between regional edge locations and your origin. Instead of 300 edge locations independently fetching cache misses from your origin, they all go through one centralized location:
Without Origin Shield:
300 edge locations × miss rate × traffic volume = many origin requests
With Origin Shield (us-east-1 shield):
All misses → us-east-1 shield → origin (only if shield misses too)
Shield hit rate: typically 60-80% of what would have been origin requests
This significantly reduces origin load, especially for content with moderate popularity.
IP Allowlisting at Origin
If your CDN is handling all traffic, your origin should only accept requests from CDN IPs:
# Cloudflare: only allow Cloudflare IPs to reach origin
# Cloudflare publishes its IP ranges at https://www.cloudflare.com/ips/
# Nginx: restrict access
allow 103.21.244.0/22;
allow 103.22.200.0/22;
allow 103.31.4.0/22;
allow 104.16.0.0/13;
# ... (all Cloudflare ranges)
deny all;
This prevents attackers from bypassing your CDN (and its WAF, DDoS protection, etc.) by hitting your origin IP directly.
Cloudflare Authenticated Origin Pulls
For stronger verification that requests come from Cloudflare:
# nginx.conf: require Cloudflare client certificate
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client on;
location / {
# Cloudflare will present this certificate
# Your origin rejects requests without it
proxy_pass http://backend;
}
Cloudflare presents a TLS client certificate with every request to your origin. Your origin rejects any request that doesn't have this certificate — even if the attacker somehow finds your origin IP.
Dynamic Content Acceleration
CDNs accelerate dynamic (uncacheable) content through network optimizations:
Cloudflare Argo Smart Routing
Argo routes requests through Cloudflare's optimized backbone network instead of the public internet. The public internet is unpredictable — packets take indirect paths, experience congestion, and have variable latency. Cloudflare's backbone is optimized:
Public internet path (typical):
User → ISP → multiple BGP hops → ... → your origin
Latency: 180ms (highly variable)
Argo path:
User → nearest CF PoP → CF backbone (optimized routing) → your origin
Latency: 120ms (consistent)
Argo typically improves time-to-first-byte for dynamic content by 30-60%. This matters for authenticated APIs, checkout flows, and any content that can't be cached.
TCP Optimizations
Modern CDNs maintain persistent, pre-warmed TCP connections to origins. Establishing a TCP connection requires a handshake (3 round trips). For HTTPS, add TLS negotiation (2 more round trips). CDNs amortize this overhead:
Without CDN:
User → [TCP 3-way handshake] → [TLS negotiation] → [Request/Response] → Done
Total: 5-6 RTTs minimum from user to origin
With CDN:
User → [TCP to CDN PoP: 1-2 RTTs] → CDN has persistent connection to origin
Total: 1-2 RTTs from user's perspective
SSL/TLS at the CDN Layer
Full vs Full Strict SSL Mode
Flexible: User→CDN (HTTPS) CDN→Origin (HTTP) ← INSECURE, never use
Full: User→CDN (HTTPS) CDN→Origin (HTTPS, any cert) ← Acceptable
Full Strict: User→CDN (HTTPS) CDN→Origin (HTTPS, valid cert) ← Best
Always use Full Strict. "Flexible" mode means your origin traffic is unencrypted — the CDN is just providing false security theater.
HTTP to HTTPS Redirect
Configure the redirect at the CDN level, not at your origin. This saves the round trip to your origin for every HTTP request:
Cloudflare: SSL/TLS → Edge Certificates → Always Use HTTPS: ON
CloudFront: Viewer Protocol Policy: Redirect HTTP to HTTPS
Performance Headers and Optimizations
HSTS Preloading
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
With HSTS, browsers remember to use HTTPS and don't even try HTTP. Submit your domain to the HSTS preload list and browsers will use HTTPS without ever making an HTTP request — eliminating even the redirect latency.
HTTP/2 and HTTP/3
Cloudflare: Speed → Optimization → Protocol Optimization → HTTP/3: Enable
HTTP/3 (QUIC) uses UDP instead of TCP, eliminating TCP handshake latency and head-of-line blocking. For users with high packet loss (mobile networks), HTTP/3 can dramatically improve performance. Browser support is excellent.
Image Optimization
Cloudflare Images and similar services transform images on-demand:
<!-- Request any size, CDN serves optimally sized image -->
<img src="/cdn-cgi/image/width=800,format=auto/images/hero.jpg">
<!-- Parameters:
width: resize to width (height scales proportionally)
format=auto: serve WebP to browsers that support it, JPEG otherwise
quality: 1-100, default 85
fit: scale-down, contain, cover, crop, pad
-->
This eliminates the need to generate multiple image sizes at build time — the CDN handles it.
Real-Time Log Analysis
CDN logs reveal cache behavior and traffic patterns:
# Cloudflare Logpush to S3, then analyze with Athena
# Key fields:
# CacheStatus: hit, miss, expired, bypass, revalidated
# EdgeResponseStatus: HTTP status code at CDN
# OriginResponseStatus: HTTP status the CDN got from origin
-- Athena query: cache hit ratio by path prefix
SELECT
split_part(clientrequestpath, '/', 2) AS path_prefix,
COUNT(CASE WHEN cachestatus = 'hit' THEN 1 END) AS hits,
COUNT(*) AS total,
ROUND(100.0 * COUNT(CASE WHEN cachestatus = 'hit' THEN 1 END) / COUNT(*), 2) AS hit_rate
FROM cloudflare_logs
WHERE year='2026' AND month='03'
GROUP BY 1
ORDER BY total DESC
LIMIT 20;
Purging and Cache Invalidation
Purge by Tag
Tag-based purging is more flexible than URL-by-URL purging:
// Set cache tags on origin responses
return response()->json($product)
->header('Cache-Tag', "product-{$product->id} category-{$product->category_id}")
->header('Surrogate-Control', 'max-age=3600');
// When product is updated, purge by tag
$client->post(
"https://api.cloudflare.com/client/v4/zones/{$zoneId}/purge_cache",
[
'json' => [
'tags' => ["product-{$product->id}"]
]
]
);
// Only this product's cached responses are invalidated
// Other products are unaffected
Stale-While-Revalidate
Avoid cache purge races — serve stale content briefly while the cache updates:
Cache-Control: public, max-age=300, stale-while-revalidate=60
After the 5-minute TTL expires, the CDN serves the stale response immediately while fetching a fresh version from origin in the background. Users see no latency spike during revalidation.
Configuration Checklist
For any production CDN setup, verify:
Security:
✓ Full Strict SSL mode enabled
✓ HTTP to HTTPS redirect at CDN level
✓ HSTS enabled (and preload list submitted)
✓ Origin restricted to CDN IPs only
✓ WAF rules enabled
✓ DDoS protection enabled
✓ Bot management configured
Performance:
✓ HTTP/2 and HTTP/3 enabled
✓ Brotli compression enabled
✓ Static assets: Cache-Control max-age=31536000, immutable
✓ Query parameter normalization configured
✓ Analytics parameters (utm_*, fbclid, gclid) in ignore list
✓ Cache hit ratio > 90% for static assets
✓ Cache hit ratio > 60% for public API responses
Operational:
✓ CDN logs streaming to S3 or similar
✓ Alerts on cache hit ratio drop
✓ Purge mechanism tested and documented
✓ Origin shield or equivalent enabled
A well-configured CDN is not a set-and-forget component — it's an active part of your architecture. Regular review of cache hit rates, log analysis for unusual traffic patterns, and incremental configuration improvements pay compounding dividends.
Building something that needs to scale? We help teams architect systems that grow with their business. scopeforged.com