{"id":806,"date":"2026-08-06T02:11:19","date_gmt":"2026-08-06T02:11:19","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=806"},"modified":"2026-08-06T02:11:19","modified_gmt":"2026-08-06T02:11:19","slug":"nginx-fastcgi-cache-microcaching-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/","title":{"rendered":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Every PHP request on a typical WordPress or Laravel VPS spends 100\u2013300 ms in PHP-FPM even when the rendered page barely changes. Nginx&#8217;s <code>fastcgi_cache<\/code> stores the finished HTML and serves repeat visitors from memory or disk in under 10 ms \u2014 a 10\u201330x drop in time-to-first-byte using one <code>http<\/code> block and a couple of <code>location<\/code> directives. Unlike <code>proxy_cache<\/code>, it is built for upstreams speaking FastCGI, so it applies directly to php-fpm.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The cache zone lives in RAM for its key index and on disk for the payloads, and it competes with your other disk usage. <a href=\"https:\/\/virtualserversvps.com\/#providers\">see the full specs on our VPS comparison table<\/a> and give the cache its own partition if your provider allows it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How fastcgi_cache Works<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fastcgi_cache_path \/var\/cache\/nginx levels=1:2\n                   keys_zone=DYNAMIC:100m inactive=60m max_size=2g;<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><code>keys_zone<\/code> holds the metadata index in RAM \u2014 100m handles roughly 100,000 cache entries.<\/li><li><code>levels=1:2<\/code> spreads files across subdirectories so the filesystem does not choke on one giant directory.<\/li><li><code>inactive=60m<\/code> evicts entries not accessed for an hour, and <code>max_size<\/code> caps the disk footprint.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Caching the PHP Location<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>location ~ \\.php$ {\n    fastcgi_cache DYNAMIC;\n    fastcgi_cache_key \"$scheme$request_method$host$request_uri\";\n    fastcgi_cache_valid 200 301 302 60m;\n    fastcgi_cache_use_stale error timeout updating;\n    fastcgi_pass unix:\/run\/php\/php8.3-fpm.sock;\n    include fastcgi_params;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The cache key must include scheme, method, host, and URI so HTTPS and HTTP versions, or two domains on one server, never serve each other&#8217;s pages. <code>fastcgi_cache_use_stale<\/code> serves a stale copy when PHP-FPM is down \u2014 the difference between a degraded page and a 502.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Set the key at the <code>http<\/code> level so every <code>server<\/code> block shares it, and keep the zone name unique per site when several applications run on one VPS. If you serve both <code>www<\/code> and apex domains, redirect one to the other first \u2014 otherwise the same page is cached twice and the hit ratio drops.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One warning about <code>fastcgi_cache_valid<\/code>: it only sets TTLs for status codes you name, and any response without a matching rule is not cached. Include 200, 301, and 302 for normal pages, and give 404s a short TTL so a flood of bad-URL requests does not hammer PHP-FPM either.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Microcaching: Cache Short, Cache Often<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>fastcgi_cache_valid 200 1s;\n# or, for a news site: fastcgi_cache_valid 200 5s;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Microcaching sets a TTL of one to five seconds. It is safe for logged-out traffic because the page changes so little in that window, yet it absorbs the thundering herd when a front-page link or a newsletter blast hits: hundreds of concurrent visitors collapse into one PHP-FPM request per second instead of hundreds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Combine microcaching with <code>fastcgi_cache_lock on<\/code> to prevent cache stampedes. When the TTL expires and ten requests hit the same URL at once, the lock lets only one reach PHP-FPM while the others wait for it to repopulate the cache \u2014 without the lock, all ten would regenerate the page and you would be back to the load you were avoiding.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Start at 5s for a blog or news site and 1s for pages with user-specific widgets you cannot easily bypass.<\/li><li>Watch the cache hit ratio in logs; if it stays below 80%, your cache key or bypass rules are too aggressive.<\/li><li>Reserve 15\u201320% of RAM for the keys_zone \u2014 a swap-thrashing server with a huge cache index is slower than no cache at all.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Bypassing the Cache for Logged-In Users<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>set $skip_cache 0;\nif ($request_method = POST)      { set $skip_cache 1; }\nif ($query_string != \"\")         { set $skip_cache 1; }\nif ($request_uri ~* \"\/wp-admin\/|\/wp-json\/|\/cart\/|\/checkout\/\") { set $skip_cache 1; }\nif ($http_cookie ~* \"wordpress_logged_in|woocommerce_items_in_cart\") { set $skip_cache 1; }\n\nfastcgi_cache_bypass $skip_cache;\nfastcgi_no_cache $skip_cache;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Logged-in sessions, shopping carts, and POST requests must never be cached \u2014 a cached checkout page is a data leak. These <code>if<\/code> guards flip <code>$skip_cache<\/code> and both directives honor it: bypass skips reading the cache, no_cache skips writing it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>if<\/code> blocks are evaluated at rewrite time and are safe here because they only set a variable \u2014 they do not perform actions like redirects or rewrites, which is where Nginx <code>if<\/code> gets dangerous. For WooCommerce or other cookie-heavy apps, add your plugin&#8217;s cookies to the regex so cart and session pages always hit PHP-FPM.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Purging the Cache on Content Updates<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>map $request_method $purge_method {\n    PURGE 1;\n    default 0;\n}\nlocation ~ \/purge(\/.*) {\n    allow 127.0.0.1;\n    deny all;\n    fastcgi_cache_purge DYNAMIC \"$scheme$request_method$host$1\";\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With <code>ngx_cache_purge<\/code> compiled in, a <code>curl -X PURGE http:\/\/127.0.0.1\/purge\/<\/code> from a <code>save_post<\/code> hook or a deploy script invalidates exactly the affected URLs instead of flushing the whole zone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you cannot compile the purge module, the fallback is a short TTL: pages self-invalidate within their validity window, so a 60-second TTL means the worst case is a one-minute-old page after an update. Many WordPress setups pair a 60s TTL with a purge plugin and get both freshness and most of the performance win.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parameters That Matter<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Parameter<\/th><th>Effect<\/th><th>Typical value<\/th><\/tr><\/thead><tbody><tr><td>keys_zone size<\/td><td>Metadata memory<\/td><td>100m per ~100k URLs<\/td><\/tr><tr><td>inactive<\/td><td>Eviction window<\/td><td>60m<\/td><\/tr><tr><td>fastcgi_cache_valid<\/td><td>Per-status TTL<\/td><td>200 60m; 404 1m<\/td><\/tr><tr><td>max_size<\/td><td>Disk cap<\/td><td>2g<\/td><\/tr><tr><td>use_stale<\/td><td>Serve during upstream failure<\/td><td>error timeout updating<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Testing with curl<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -sI https:\/\/example.com\/ | grep -i x-cache-status\n# MISS on the first hit, HIT on the second \u2014 that is the cache working<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add <code>add_header X-Cache-Status $upstream_cache_status;<\/code> in the location while testing, then remove it in production so the header does not leak to visitors.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">FastCGI caching is the single highest-leverage change for PHP sites on a small VPS \u2014 it converts a burst of concurrent visitors into one upstream request. Tune the TTL per page type and watch the hit ratio in your access logs. When you size the server for it, <a href=\"https:\/\/virtualserversvps.com\/#providers\">compare plans side by side on our comparison table<\/a> to get enough RAM for both PHP-FPM and the cache zone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Prefer to tune cache headers instead of hand-editing Nginx configs? Cloudways enables Varnish and Redis caching from its control panel on every managed VPS plan. See <a href=\"https:\/\/cloudways.com\/en\/?id=2010927&amp;data1=virtualserversvps\" rel=\"noreferrer noopener sponsored\" target=\"_blank\">Cloudways plans and pricing<\/a> if you want caching without the config file.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Every PHP request on a typical WordPress or Laravel VPS spends 100\u2013300 ms in PHP-FPM even when the rendered page barely changes. Nginx&#8217;s fastcgi_cache stores the finished HTML and serves&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":1,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-806","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites\" \/>\n<meta property=\"og:description\" content=\"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-06T02:11:19+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/\",\"name\":\"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-06T02:11:19+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/","og_locale":"en_US","og_type":"article","og_title":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites","og_description":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites","og_url":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-06T02:11:19+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/","name":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-06T02:11:19+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/nginx-fastcgi-cache-microcaching-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Nginx FastCGI Cache and Microcaching on a VPS: Configs for Dynamic Sites"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/806","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=806"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/806\/revisions"}],"predecessor-version":[{"id":808,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/806\/revisions\/808"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=806"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=806"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}