CDN Setup Guide
Cache-Control Headers
# Static assets (JS/CSS/images) — long cache
Cache-Control: public, max-age=31536000, immutable
# HTML pages — revalidate always
Cache-Control: no-cache
# API responses — short cache
Cache-Control: public, max-age=60, s-maxage=300
# Private user data — never cache at CDN
Cache-Control: private, no-store
# CDN-specific (Cloudflare)
Cache-Control: public, max-age=3600, s-maxage=86400
CDN-Cache-Control: max-age=86400
Cache-Control Directives
| Directive | Description |
|---|---|
| max-age=N | Cache for N seconds (browser + CDN) |
| s-maxage=N | CDN cache duration, overrides max-age for shared caches |
| public | Can be stored by CDNs and proxies |
| private | Only browser cache, not CDN/proxy |
| no-cache | Must revalidate before use (not "no caching") |
| no-store | Do not store at all |
| immutable | Content won't change during max-age period |
| stale-while-revalidate=N | Serve stale while refreshing in background |
Nginx Origin Configuration
server {
listen 80;
server_name origin.example.com;
# Static files — long cache
location ~* \.(js|css|woff2|png|jpg|svg|ico)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Vary "Accept-Encoding";
}
# HTML — no cache
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
# API
location /api/ {
add_header Cache-Control "public, max-age=60, s-maxage=300";
proxy_pass http://app:8080;
}
}
Cache Key Strategy
# Vary by Accept-Encoding (compress separately)
Vary: Accept-Encoding
# Vary by content type for API
Vary: Accept
# Cloudflare Cache Rules (example)
# Rule: Cache everything
# Cache TTL: 1 day
# Bypass on cookie: session=*
# Query string handling
# Ignore: utm_source, utm_medium, fbclid
# Include: page, size, sort
CDN Providers Comparison
| Provider | Edge Nodes | Free Tier | Key Feature |
|---|---|---|---|
| Cloudflare | 300+ | Yes (generous) | WAF, Workers, zero-rating |
| AWS CloudFront | 450+ | 1TB/mo (12mo) | Deep AWS integration |
| Fastly | 80+ | Trial only | Real-time purge, VCL |
| BunnyCDN | 114+ | No | Lowest price/GB |
| Azure CDN | 200+ | No | Azure integration |
Cache Invalidation
# Cloudflare API purge
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://example.com/style.css"]}'
# Purge all
--data '{"purge_everything":true}'
# AWS CloudFront invalidation
aws cloudfront create-invalidation \
--distribution-id EDFDVBD6EXAMPLE \
--paths "/*"