
CDN and Caching on WordPress Hosting: Best Settings for TTFB Under 200ms
If your site feels “fast” but analytics still complain about server response times, you’re probably staring at TTFB. Think of TTFB like the time it takes a waiter to say hello and bring the menu. If that hello is snappy, the rest of the meal tends to go smoother.
Here’s the practical, modern playbook to get TTFB under 200ms on WordPress—globally for cached pages via a CDN, and regionally for origin hits—without snake oil or fragile tweaks. We’ll cover what matters right now (post-INP rollout, HTTP/3 age), the exact CDN and cache settings that move the needle, and how to measure the wins.
Why TTFB matters even more in 2024–2025
– TTFB influences LCP: A slow first byte pushes the whole rendering pipeline back.
– Core Web Vitals evolved: Interaction to Next Paint (INP) replaced FID in March 2024, but TTFB still correlates with overall UX and crawl efficiency.
– Search and ads care: Faster responses improve crawl budget, can lift organic performance, and reduce ad load penalties.
– Global audiences expect edge speed: With HTTP/3 and modern CDNs, sub-200ms TTFB for cached HTML is achievable worldwide. Users now notice when you don’t deliver that standard.
What TTFB actually measures
TTFB covers DNS lookup, TCP/TLS handshake, request travel time, and server processing until the first byte is received. With a CDN:
– Cached (edge HIT): Time includes the user-to-CDN path and CDN work. This is where you can easily get under 200ms worldwide.
– Uncached (edge MISS/origin): Time adds the CDN-to-origin hop and your origin’s compute. You’ll want sub-200ms in-region and as low as possible cross-region, but the best fix is a higher cache-hit ratio so you avoid origin.
Reasonable targets
– Cached HTML via CDN: 50–200ms TTFB in major regions when settings are right.
– Origin in-region: 80–300ms for a simple WordPress page with PHP 8.2/8.3, OPcache, Redis object cache, and an optimized database.
– Logged-in and cart/checkout pages: Often dynamic; aim for in-region 150–400ms if not cached, but prefer ESI or targeted caching where safe.
The modern stack that consistently delivers
– Hosting layer
– PHP 8.2 or 8.3 with OPcache enabled and sane memory limits.
– Nginx with FastCGI cache, LiteSpeed Enterprise with LSCache, or a managed stack that ships full-page caching out of the box.
– Redis (persistent object cache) with a reputable plugin (Redis Object Cache Pro or the community plugin).
– MariaDB/MySQL with slow query logging and essential indexes; avoid heavy autoloaded options.
– Place the origin near your largest audience if you can’t cache HTML globally.
-
CDN layer (Cloudflare, Fastly, CloudFront, Bunny, QUIC.cloud—pick one with global POPs and HTTP/3)
- HTTP/2 and HTTP/3 (QUIC) enabled.
- TLS 1.3, OCSP stapling, and an ECDSA certificate.
- Brotli compression (level ~5–7 server-side; most CDNs pick a balanced default).
- 103 Early Hints if available (helps overall paint; not TTFB, but it boosts UX).
- Origin Shield or tiered caching where offered to reduce origin trips.
-
DNS
- Use a fast anycast DNS provider (Cloudflare, NS1, Route 53, etc.).
- Keep records lean; set A/AAAA to your CDN, not the origin.
CDN caching for sub-200ms TTFB
The single biggest lever is caching your HTML at the edge. The trick is doing it safely for WordPress and eCommerce.
-
Cache HTML for anonymous users
- Set Cache-Control headers at the origin that are CDN-friendly, or use your CDN rules to override:
- Cache-Control: public, max-age=60, s-maxage=86400, stale-while-revalidate=30, stale-if-error=86400
- s-maxage controls CDN TTL (longer), max-age is for browsers (shorter while content is “fresh enough”).
- Enable serve-stale-on-error and stale-while-revalidate to cut tail latencies.
- Set Cache-Control headers at the origin that are CDN-friendly, or use your CDN rules to override:
-
Bypass cache on signals that imply personalized or changing content
- Cookies: wp_loggedinwordpress_loggedincommentauthorwoocommerce_cart_hash, wp_woocommercesessionand other auth/session cookies.
- URLs: /wp-admin/, /wp-login.php, /cart, /checkout, /my-account, ?preview=true, ?s= (search), and any custom endpoints that are dynamic.
- Query params to ignore for cache key: utm_*, gclid, fbclid, msclkid, ref. Strip them at the edge or exclude from the key so they don’t bust cache.
-
Normalize the cache key
- Vary only on what truly changes the HTML:
- Accept-Encoding (gzip/brotli) is handled automatically by most CDNs.
- Device or language only if your theme varies HTML by user-agent or locale. Otherwise don’t add unnecessary variations.
- Avoid user-agent variance unless necessary; it destroys hit ratio.
- Vary only on what truly changes the HTML:
-
HTML caching modes on popular CDNs
- Cloudflare: APO for WordPress or Cache Everything with proper bypass/page rules and a Worker/Transform Rule to strip marketing params and ignore non-critical cookies.
- Fastly: Surrogate-Control headers plus VCL/Compute@Edge to purge by Surrogate-Key and normalize cookies/params.
- CloudFront: Cache policy that excludes auth cookies, includes necessary headers only; Lambda@Edge for key normalization.
- Bunny/Flywheel/QUIC.cloud: Enable full-page cache for WordPress integration and configure path and cookie exceptions.
-
Purging strategy
- Use tag-based purging (surrogate keys) if your CDN supports it. Purge only affected pages when a post updates.
- Otherwise, purge homepage, category, and the updated post rather than full-site purges.
- Automate purges via your caching plugin or CDN integration.
What about WooCommerce?
– Exclude cart, checkout, and account pages from HTML caching, or use ESI (Edge Side Includes) for small personalized blocks like the mini-cart.
– Disable or modernize legacy cart fragments (wc-ajax=get_refreshed_fragments) if your theme supports a better pattern; fragments keep pages uncacheable.
– Cache product and category pages for anonymous users with conservative TTLs; purge on stock/price changes via hooks.
WordPress cache plugins: recommended settings
You don’t need every knob—just the ones that reduce origin work and improve cacheability.
-
LiteSpeed Cache (with LiteSpeed server or QUIC.cloud CDN)
- Enable Cache for logged-out visitors and ESI for cart/headers where used.
- Set TTLs: Front page 1–10 minutes, posts/pages 1–24 hours depending on update frequency.
- Object Cache: Redis on; set persistent connection and reasonable TTLs.
- Purge rules tied to post updates, category changes, and WooCommerce product actions.
- CSS/JS optimization helps total load, not TTFB—but Critical CSS + defer is fine. Don’t over-minify to the point of breakage.
-
WP Rocket (origin/page cache) with Cloudflare/Bunny/etc.
- Cache lifespan: 10 hours–7 days depending on content volatility.
- Preload via sitemap to warm critical pages.
- Separate CDN config to avoid double minify/CDN rewrites if your CDN also modifies assets.
- Database cleanup and heartbeat control (sensible, not aggressive).
-
Nginx FastCGI Cache (if you manage the server)
- Key: scheme$request_method$host$request_uri
- Bypass: cookies for auth/cart, paths for admin/cart/checkout.
- Use stale-while-revalidate and stale-if-error equivalents.
- Couple with a purge module or an external cache invalidation process via hooks.
-
Redis Object Cache
- On for all sites, especially WooCommerce, to reduce PHP/DB time when pages can’t be fully cached.
- Monitor hit ratio and memory size; evictions indicate you need more RAM or better key TTLs.
Server-level performance that affects TTFB
– PHP-FPM tuning: Right-size pm.max_children to avoid queuing; don’t starve CPU or RAM.
– OPcache: Enable and increase memory to prevent frequent recompile; validate_timestamps off in production or set a longer recheck interval with a deploy hook to reset.
– Database:
– Keep autoloaded options lean (Compression, transport, and TLS tips
– Brotli for text (HTML, CSS, JS, JSON, SVG). Most CDNs do brotli at the edge; ensure your origin does gzip for CDN-to-origin if needed.
– TLS 1.3 with modern ciphers and ECDSA certificates reduce handshake time.
– HTTP/3 (QUIC) often improves handshake and packet loss resilience, especially on mobile networks.
Cache warming so you don’t pay the MISS penalty
– Warm critical pages on deploy or purge with a lightweight crawler.
– Prioritize homepage, top categories, evergreen landing pages, and sitemaps.
– On Cloudflare, consider Crawler Hints and Tiered Cache to reduce origin fan-out.
Security features without the latency tax
– WAF: Keep it on, but test managed rulesets and bot challenges. Excessive JavaScript challenges and CAPTCHA on HTML can add seconds.
– Rate limiting: Apply to admin endpoints and login APIs, not to public HTML.
– IP reputation/bot fight: Make sure it doesn’t degrade cache HITs. Allow verified bots (Googlebot/Bing) but cache for them, too.
Observability: how to know you’re actually under 200ms
– Test globally:
– WebPageTest: Run from multiple regions. Compare edge HIT vs MISS.
– SpeedCurve or Calibre: Continuous synthetic tests track regressions.
– Real-user monitoring (RUM): Check actual TTFB/LCP by region/device. CrUX can hint at field performance.
– Inspect headers:
– Look for cf-cache-status: HIT / x-cache: HIT / age: N.
– Cache-Control, Surrogate-Control, and vary headers should match your design.
– CLI spot checks:
– curl -I https://example.com to verify headers.
– curl -w “TTFB: %{time_starttransfer}n” -o /dev/null -s https://example.com to measure TTFB from your terminal (use a host near the target region for realism).
– Watch cache-hit ratio: Aim for >90% HIT on anonymous HTML in stable periods. If it’s lower, your cookies/params/variations are likely blowing the key.
Common pitfalls that quietly ruin TTFB
– Setting no-cache or private on HTML unintentionally via a plugin or security header pack.
– Personalization by default: Themes injecting user-specific cookies for all visitors (A/B tools, chat widgets, “recently viewed” lists) that turn off cache. Scope these to JS and APIs, not the base HTML.
– Excessive variation: Caching separately by device, language, geolocation, and user agent when the HTML is actually the same.
– Aggressive full-site purges on every small update, keeping the cache perpetually cold.
– Heavy wp-admin-ajax or REST calls in the page head that block first byte with server-side rendering.
Sample, vendor-agnostic header patterns
– For anonymous HTML at the origin:
– Cache-Control: public, max-age=60, s-maxage=86400, stale-while-revalidate=30, stale-if-error=86400
– Vary: Accept-Encoding
– Surrogate-Key: post-123 category-7 homepage (if your CDN supports surrogate keys)
– For static assets (CSS/JS/fonts/images):
– Cache-Control: public, max-age=31536000, immutable
– Use file hashing in filenames to bust cache on deploy (app.7c9d3.js).
– For admin and personalized endpoints:
– Cache-Control: private, no-store
A minimal, modern WordPress/CDN recipe
– Host and app
– PHP 8.2/8.3, OPcache tuned.
– Redis object cache, persistent.
– Nginx FastCGI cache or LiteSpeed Cache for full-page caching at origin (as a fallback).
– CDN
– HTTP/3 + TLS 1.3 + Brotli.
– Cache HTML for logged-out users; bypass on auth/cart cookies and admin paths.
– Normalize cache key by stripping utm_*/gclid/fbclid from the query string.
– Set s-maxage to at least 1 day; enable stale-while-revalidate and stale-if-error.
– Use tag-based purging or targeted purges on edits.
– WordPress
– Use a mature cache plugin (LiteSpeed Cache, WP Rocket, or carefully tuned W3TC) with sitemap-based preloading.
– Disable legacy cart fragments or use ESI/mini-cart best practices.
– Run real cron, not WP-Cron on page load.
How this plays out in practice
– A typical before/after:
– Before: Origin-serving HTML from a single region with no edge cache; TTFB 600–1200ms globally, 200–400ms in-region.
– After: CDN caches HTML for anonymous pages; normalized keys and long s-maxage; Redis lowers backend time for misses; TTFB 70–180ms on edge HITs across major metros, 120–300ms on misses in-region.
– Managed hosts adding edge caching (e.g., Cloudflare-backed edge caches) have made this easier. Even if you can’t switch hosts, most of the gains come from the CDN and headers you control.
Two quick wins most sites miss
– Strip analytics query params from the cache key at the edge. Your hit ratio jumps, which lowers average TTFB dramatically.
– Use surrogate keys or precise purge-on-update. Avoid the “nuke cache” button unless you changed templates or critical global CSS.
Final word
Chasing TTFB under 200ms isn’t about exotic tricks; it’s about making the CDN do the heavy lifting for anonymous traffic, keeping your origin lean for the misses, and avoiding accidental cache busters. With modern HTTP/3 CDNs, smart cache keys, and WordPress tuned for object and page caching, sub-200ms TTFB on cached pages is not just doable—it’s the baseline your audience expects. The web moved to the edge; your first byte should, too.

Leave a Reply