Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

On a small VPS, the safest way to reduce application work is to cache only identical, public responses and to prevent bursts of cache misses from reaching the origin at once. Use proxy_cache for an HTTP upstream, fastcgi_cache for PHP or another FastCGI application, add explicit bypass rules for logged-in and personalized requests, then measure hit rate, origin time, CPU, memory, disk I/O and errors before expanding the cache.

What Nginx caching does

Nginx can store an upstream response on disk and serve later requests for the same cache key without contacting the application server each time. The shared-memory zone tracks keys and metadata, while the cache files hold response data. This can reduce PHP, application-server and database work, but it does not automatically improve every workload: a low hit rate, expensive disk I/O, cache churn or extra compression work can leave a small VPS slower.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

There are two different modules to choose between:

Situation Directive family What is cached Main design concern
Nginx proxies HTTP to an application server proxy_cache HTTP responses received from the upstream Correct proxy cache key, public/private classification and upstream headers
Nginx passes requests to PHP or another FastCGI process fastcgi_cache FastCGI responses, normally for GET and HEAD requests FastCGI key, bypass rules, session cookies and application-specific invalidation

Do not treat these directives as interchangeable. First identify whether the VPS serves static files directly, proxies an HTTP service, or runs a FastCGI application. Static files usually need efficient file serving and sensible browser cache headers rather than an upstream response cache.

Decide what is safe to cache

Start with public, repeatable pages

The first candidates are anonymous GET and HEAD requests whose output is the same for many visitors: documentation, public articles, landing pages and other read-only pages. A cache entry should represent a response that can safely be shown to every request sharing its key. Exclude writes and requests whose output depends on identity, permissions, cart contents, a preview mode or a one-time token.

Bypass authentication and personalization

Do not cache authenticated or personalized responses by default. Nginx documentation describes bypassing when an Authorization header or session-related cookie is present. Responses carrying Set-Cookie are also not cached by default unless response-header processing is changed. That default protects users from receiving another user’s content; do not disable it merely to increase the hit rate.

Typical bypass signals include:

  • An Authorization header.
  • Login, session, preview, shopping-cart or account cookies.
  • Query parameters used for previews, tracking that changes output, searches or other personalized views.
  • Methods other than GET and HEAD, especially POST, PUT, PATCH and DELETE.
  • Administrative paths, checkout flows, webhooks and APIs that return user-specific data.

Keep the bypass decision consistent with the cache key. If two URLs can produce different public content, include the relevant variation in the key or bypass caching for that request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose between proxy_cache and fastcgi_cache

Proxy caching for an HTTP upstream

Use proxy_cache when Nginx sends the request to an HTTP application server. The cache key commonly includes the scheme, request method and host/path combination. Make the key explicit enough to distinguish every response variation you allow, but avoid including irrelevant values that create thousands of one-off entries.

FastCGI caching for PHP and similar applications

Use fastcgi_cache when Nginx communicates with a FastCGI process. FastCGI caching has its own cache key, GET/HEAD method controls, bypass and no-cache rules, cache locking, revalidation and stale-response directives. A common beginner mistake is to copy a proxy-cache example into a FastCGI location without adapting the FastCGI parameters and session-cookie logic.

Comparison point Proxy cache FastCGI cache
Application protocol HTTP upstream reached through proxy_pass FastCGI upstream reached through fastcgi_pass
Best initial content Public responses from an application server Public, anonymous PHP or other FastCGI pages
Key and variation Build with proxy_cache_key and the variables your public responses require Build with fastcgi_cache_key and the variables required by the FastCGI application
Bypass signals Authorization, cookies, methods, query parameters and upstream no-cache signals The same signals, plus application session conventions and FastCGI parameters
Freshness controls proxy_cache_valid, upstream cache headers, revalidation and stale directives fastcgi_cache_valid, upstream cache headers, revalidation and stale directives
Miss protection proxy_cache_lock and related lock settings fastcgi_cache_lock and related lock settings
Invalidation Expire entries, purge them operationally, or change the key/version Expire entries, purge them operationally, or change the key/version
Observability Add a response header such as a locally chosen HIT/MISS indicator Add a response header such as a locally chosen HIT/MISS indicator

Configure a small proxy cache safely

Define the cache path and shared-memory zone in the http {} context, not inside an individual server {} block. The example below is a starting point, not a universal capacity recommendation.

http {
    proxy_cache_path /var/cache/nginx levels=1:2
        keys_zone=public_proxy:32m
        max_size=2g
        inactive=30m
        use_temp_path=off;

    proxy_cache_lock on;
    proxy_cache_lock_timeout 10s;

    server {
        listen 80;
        server_name example.test;

        location / {
            proxy_pass http://app_upstream;
            proxy_cache public_proxy;
            proxy_cache_methods GET HEAD;
            proxy_cache_key "$scheme$request_method$host$request_uri";
            proxy_cache_valid 200 10m;
            proxy_cache_valid 404 1m;

            proxy_cache_bypass $skip_cache;
            proxy_no_cache $skip_cache $upstream_http_set_cookie;
            add_header X-Cache-Status $upstream_cache_status always;
        }
    }
}

Define $skip_cache from your site’s actual signals, for example by mapping an authorization header, a session cookie and a preview argument to 1. Do not paste a cookie regular expression without checking the cookie names your application really sets. Also verify whether the upstream sends Set-Cookie; the proxy_no_cache condition above prevents storing that response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why the cache path settings matter

  • keys_zone=public_proxy:32m creates a shared-memory index named public_proxy. The size is metadata capacity, not the disk-cache size.
  • max_size=2g limits cache-file storage; choose a value that leaves room for the operating system, logs and application data.
  • inactive=30m allows Nginx to remove entries that have not been used for that period, subject to cache manager work.
  • use_temp_path=off keeps temporary files under the cache path. Keeping temporary and cache files on the same filesystem lets Nginx rename a completed file instead of copying it.
  • proxy_cache_valid supplies defaults by status code. A response’s X-Accel-Expires, Expires or Cache-Control headers can control or override freshness, so inspect upstream headers before assuming the configured duration is effective.

Configure FastCGI caching for a public PHP location

FastCGI uses a separate cache zone and directives. Put the path in http {}, then enable it only in the PHP or FastCGI location that serves cacheable public pages.

http {
    fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2
        keys_zone=public_fastcgi:32m
        max_size=2g
        inactive=30m
        use_temp_path=off;

    server {
        listen 80;
        server_name example.test;

        location ~ .php$ {
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_pass unix:/run/php/php-fpm.sock;

            fastcgi_cache public_fastcgi;
            fastcgi_cache_methods GET HEAD;
            fastcgi_cache_key "$scheme$request_method$host$request_uri";
            fastcgi_cache_valid 200 10m;
            fastcgi_cache_valid 404 1m;

            fastcgi_cache_bypass $skip_cache;
            fastcgi_no_cache $skip_cache $upstream_http_set_cookie;
            fastcgi_cache_lock on;
            add_header X-FastCGI-Cache $upstream_cache_status always;
        }
    }
}

Use the parameter names and socket path supplied by your distribution and PHP-FPM configuration. Test the generated configuration with nginx -t before reloading. A successful syntax test does not prove that the cache is safe; request an anonymous page, then test a logged-in session, a preview URL and a response that sets a cookie.

Stop cache misses from overwhelming the origin

Enable cache locking

When an item is missing or expired, many visitors can request it at the same time. Without a lock, every request may reach the application. With proxy_cache_lock on or fastcgi_cache_lock on, one request populates the item while other requests wait for the result, reducing a thundering herd against a small upstream. Set a lock timeout appropriate to the endpoint; an excessively short timeout lets waiting requests escape to the origin, while an excessively long timeout makes failures feel stalled.

Use stale responses deliberately

Stale-response directives can let Nginx serve an older object while the upstream is updating or temporarily failing. This is useful for public, non-critical pages, but it is not appropriate for account balances, orders or other data that must be current. Define which errors or updating conditions may use stale content, and make sure operators know that the page can be older than the origin.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Revalidate instead of refilling blindly

Where the upstream supports validators, revalidation can check whether an object changed rather than transferring the full body again. Confirm how your application emits validators and how its cache-control policy interacts with Nginx; upstream headers can change the effective lifetime.

Reduce connection and response overhead

Upstream keepalive

Keepalive connections avoid repeated TCP and protocol setup between Nginx and the upstream. They require compatible protocol settings. For FastCGI, fastcgi_keep_conn on is required for keepalive connections to function.

Keepalive is not a total connection limit. Nginx explicitly notes that the keepalive directive does not limit the total number of connections an Nginx worker can open to upstream servers. Set worker, upstream and operating-system limits based on measured concurrency; use connection limits or queueing mechanisms when you need a hard cap.

Compression for proxied responses

By default, Nginx does not compress responses to proxied requests. Enable gzip selectively when bandwidth is a constraint and the VPS has CPU headroom:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
gzip on;
gzip_proxied any;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json application/xml image/svg+xml;

The minimum-size threshold avoids spending CPU on tiny responses. Do not gzip already-compressed formats such as JPEG, PNG, WebP or most video. Check that the upstream and Nginx do not double-compress, and monitor CPU as well as transferred bytes.

Operate the cache on a small VPS

Plan disk, memory and restart windows

Reserve disk space for cache files without starving the application, database, logs or swap. The shared-memory zone consumes RAM, while cache files consume disk and generate metadata and I/O. Nginx warns that loading an entire cache at startup can consume enough resources to slow performance during the first minutes after a restart. Large caches therefore need deliberate restart windows and monitoring immediately after reloads or restarts.

Invalidate changes safely

Time-based expiry is simplest for content that can be a few minutes old. For urgent changes, use an approved purge mechanism, remove the affected cache files during a maintenance window, or version the cache key when deploying a major representation change. Never delete a live cache directory casually while Nginx is serving it; coordinate filesystem operations and verify ownership and permissions afterward.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Expose status while testing

A temporary response header based on $upstream_cache_status can show values such as a miss, hit, bypass or expired fetch. Restrict diagnostic headers if they reveal internal details, and remove or limit them once validation is complete. Test with a cache-busting request only when you intentionally want to observe an origin fetch.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Measure whether caching actually helps

There is no universal latency or throughput percentage to promise. The result depends on the application, cache-hit rate, object size, storage, CPU, memory and traffic pattern. Record a baseline before enabling caching, then compare the same traffic pattern afterward.

  • Hit rate: distinguish hits, misses, bypasses and expired entries; a high miss rate may indicate an over-specific key or short freshness period.
  • Origin response time: measure time spent waiting for PHP, the application server and the database on misses.
  • CPU: watch both application CPU and Nginx CPU, especially after enabling gzip.
  • Memory: include the shared cache zone, workers, PHP-FPM or application processes and the operating system.
  • Disk I/O and space: observe cache-manager activity, latency and free space, not just total cache size.
  • Errors: check upstream timeouts, 5xx responses, stale serves and lock timeouts.

Expand the cache only when public responses remain correct and these measurements show a real reduction in origin work without unacceptable resource pressure.

A practical rollout checklist

  1. Identify the request path: static file, HTTP proxy or FastCGI.
  2. List public GET and HEAD endpoints and mark every personalized, authenticated, write or preview route as bypassed.
  3. Define the cache path and shared zone in http {}; keep temporary and cache files on the same filesystem where possible.
  4. Choose a cache key that includes every response-changing dimension and excludes irrelevant query noise.
  5. Set status-specific lifetimes with proxy_cache_valid or fastcgi_cache_valid, then inspect upstream cache headers.
  6. Enable cache locking for busy public endpoints and decide whether stale responses are acceptable.
  7. Configure upstream keepalive only after confirming protocol behavior; use fastcgi_keep_conn on for FastCGI.
  8. Enable gzip only for suitable text responses, with a minimum-size threshold and CPU monitoring.
  9. Run nginx -t, reload during a controlled window and test anonymous, logged-in, cookie-setting, preview and error cases.
  10. Compare hit rate, origin time, CPU, memory, disk I/O and errors with the pre-cache baseline.

Common failure modes and fixes

Logged-in users receive public content

Check that authorization headers and session cookies set both bypass and no-cache conditions, and that the test account does not share an already-populated public key. Purge affected entries after correcting the rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The cache fills but hit rate stays low

Inspect the key for unnecessary query parameters, method differences, host variations and cookies. Increase freshness only after confirming that the response is safe to reuse; otherwise, a low hit rate may be the correct behavior.

The origin still receives bursts on a popular miss

Confirm that the relevant cache-lock directive is enabled in the exact location handling the request. Review lock timeout, upstream errors and whether bypass rules are sending the burst around the cache.

FastCGI keepalive has no effect

Verify the upstream protocol and set fastcgi_keep_conn on. Also check PHP-FPM or the FastCGI server’s process and connection limits; Nginx keepalive cannot override those limits.

Restarts make the VPS sluggish

Reduce cache size or schedule restarts when traffic is low, and monitor disk and memory during cache loading. A cache that is too large for the machine can erase the benefit it provides during normal operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Bottom line

For a beginner VPS, cache a narrow set of anonymous GET and HEAD responses first. Choose proxy_cache for HTTP upstreams and fastcgi_cache for FastCGI, protect the cache with authorization and cookie bypass rules, use locking to prevent miss storms, and add keepalive or gzip only when their protocol and CPU costs are understood. Treat measurements and correctness tests—not a promised percentage improvement—as the evidence for every next change.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.