Optimizing Cloudflare Cache Rates: Fixing Astro SSR Headers with Nginx Map
These articles are AI-generated summaries. Please check the original sources for full details.
Cloudflare dashboard was showing a 1.1% cache rate
Mustafa ERBAY observed that 98.9% of requests were bypassing Cloudflare to hit his origin VPS due to a misconfigured Cache-Control header. The Astro Node adapter default max-age=0 setting was causing Cloudflare to treat static HTML as dynamic content, forcing 4.05k out of 4.1k requests to hit the origin.
Why This Matters
Default framework behaviors often prioritize safety over performance, leading to ‘defensive’ headers like max-age=0 that inadvertently disable CDN caching. In this instance, the Astro Node adapter assumed every response was fresh for SSR routes, ignoring that 95% of the site was prerendered. This discrepancy led to unnecessary server lag and memory consumption, demonstrating that technical debt often hides in default configurations rather than explicit code errors.
Key Insights
- A 1.1% cache rate resulted in 4,050 out of 4,100 requests hitting the origin server (2026).
- The Astro Node adapter applies a ‘fresh response’ stance for SSR routes, setting max-age=0 even for prerendered static HTML (2026).
- Nginx’s map directive allows conditional header manipulation based on variables like $upstream_http_content_type to selectively override upstream defaults.
- Cloudflare’s Standard caching level respects origin Cache-Control headers, meaning ‘max-age=0’ triggers a DYNAMIC status instead of a HIT.
- Implementing stale-while-revalidate=86400 allows the edge to serve stale content while refreshing in the background, reducing origin pressure (2026).
Working Examples
Nginx map directive to conditionally override Cache-Control headers based on Content-Type.
map $upstream_http_content_type $mb_cache_control {
default $upstream_http_cache_control;
"~*^text/html" "public, max-age=300, s-maxage=3600, stale-while-revalidate=86400";
"~*^application/xml" "public, max-age=900, s-maxage=3600";
"~*^application/rss\+xml" "public, max-age=900, s-maxage=3600";
}
server {
location / {
proxy_pass http://127.0.0.1:3040;
proxy_hide_header Cache-Control;
add_header Cache-Control $mb_cache_control always;
}
}
Practical Applications
- Use case: Using Nginx ‘map’ to selectively apply s-maxage=3600 to text/html while preserving original headers for application/json API responses.
- Pitfall: Omitting the ‘always’ flag in add_header, which causes custom headers to disappear on 4xx and 5xx error responses.
- Use case: Overriding defensive framework defaults at the proxy layer to avoid complex code-level patches in Astro SSR environments.
- Pitfall: Trusting Cloudflare ‘Standard’ caching defaults without verifying specific headers like ‘cf-cache-status’ via curl.
References:
Continue reading
Next article
DevPen: Streamlining Developer Workflows with AI and Monaco Editor
Related Content
Preventing Frontend Regressions through Automated Asset Hashing and Caching Strategies
Solve frontend regressions caused by browser caching using automated asset hashing and Nginx headers to ensure users always receive fresh code.
Deploying Full-Stack Applications for Zero Dollars in 2026
Learn how to deploy a complete full-stack application using a zero-cost infrastructure stack featuring Vercel, Railway, Neon, and Cloudflare R2.
LLM Observability Audits: Reducing Error Rates and Exposing Rubric Disagreements
From a 32% error rate to 0.0%, this audit reveals how fixing infrastructure exposed 17% judge disagreement in LLM evaluations.