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

DirectiveDescription
max-age=NCache for N seconds (browser + CDN)
s-maxage=NCDN cache duration, overrides max-age for shared caches
publicCan be stored by CDNs and proxies
privateOnly browser cache, not CDN/proxy
no-cacheMust revalidate before use (not "no caching")
no-storeDo not store at all
immutableContent won't change during max-age period
stale-while-revalidate=NServe 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

ProviderEdge NodesFree TierKey Feature
Cloudflare300+Yes (generous)WAF, Workers, zero-rating
AWS CloudFront450+1TB/mo (12mo)Deep AWS integration
Fastly80+Trial onlyReal-time purge, VCL
BunnyCDN114+NoLowest price/GB
Azure CDN200+NoAzure 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 "/*"