Home / Knowledge Base / Performance & Speed / How to Set Up WordPress Caching on a VPS or VDS: Nginx, PHP-FPM and Plugin Settings That Actually Work Together
  1. Home
  2. »
  3. Knowledge Base
  4. »
  5. Performance & Speed
  6. »
  7. How to Set Up WordPress…

How to Set Up WordPress Caching on a VPS or VDS: Nginx, PHP-FPM and Plugin Settings That Actually Work Together

Table of Contents

How to Set Up WordPress Caching on a VPS or VDS: Nginx, PHP-FPM and Plugin Settings That Actually Work Together

Who This Caching Setup Is For (And What You Will Have Working At The End)

This guide is for people running WordPress or WooCommerce on a single VPS or virtual dedicated server, who want a fast, reliable cache without spending days guessing at Nginx directives and plugin options.

Typical situations include:

  • Moving from shared hosting to a VPS/VDS and needing a proper stack rather than “one click” defaults.
  • Rebuilding a slow single server that already runs Nginx, PHP-FPM and MySQL/MariaDB but struggles under traffic.
  • Running WooCommerce on a VPS and seeing timeouts or cart issues when you enable caching.

By the end, you will have:

  • Nginx serving static assets directly with sensible browser cache headers.
  • Optional simple Nginx microcaching for anonymous pages.
  • A WordPress cache plugin aligned with Nginx so you avoid duplicated work and conflicts.
  • Safe rules for WooCommerce and logged in users.
  • PHP-FPM tuned so cache misses do not bring the server down.

The guide assumes:

  • Linux VPS or VDS with root or sudo access.
  • Nginx + PHP-FPM + MySQL or MariaDB.
  • One or a handful of WordPress sites on the server.

If you want more background on how this stack fits together, the article on choosing and tuning a web stack on a single server is a good primer.

If managing all of this yourself feels heavy, then Virtual dedicated servers designed for WordPress and WooCommerce or fully managed WordPress hosting if you prefer caching and stack tuning handled for you can take much of the work away, but this guide focuses on a do it yourself VPS.

The Three Caching Layers You Need To Think About

A simple layered diagram showing a user’s browser, an optional edge/acceleration layer, Nginx, PHP-FPM and the WordPress/database backend, with cache icons at each relevant layer to illustrate how requests flow and where responses can be cached.

Browser cache and HTTP headers

The browser cache is the first layer. If you tell browsers to keep CSS, JavaScript and images for a while, repeat visits become much faster and you cut bandwidth.

You control this with HTTP headers, mainly:

  • Cache-Control (modern directive, supports fine grained rules)
  • Expires (older but still widely used)
  • ETag and Last-Modified (validation, for when content may change)

You will set most of these in Nginx rather than inside WordPress.

Nginx-level caching and static file delivery

Nginx is very good at serving static content directly from disk and can provide a fast page cache before PHP is involved.

Two key roles:

  • Static files such as .css, .js, images and fonts, served quickly from disk with long cache headers.
  • Microcaching of HTML responses for a short time (for example 10 to 60 seconds) for anonymous users, which can flatten spikes in traffic.

Static delivery will be in your Nginx server block. Microcaching is optional and must be configured carefully so it does not affect logins, carts or personalised content.

WordPress layer: page cache, object cache and fragment cache

Inside WordPress, there are three common caches:

  • Page cache: stores the final HTML of each page. This is what most “caching plugins” focus on.
  • Object cache: stores database query results and other data structures so that repeated requests do not keep hitting MySQL.
  • Fragment cache: stores pieces of page output. Used by some themes or plugins for specific widgets or layouts.

The balance you want on a single VPS:

  • Let Nginx serve static files.
  • Use a WordPress page cache plugin that cooperates with Nginx.
  • Add object cache (Redis or Memcached) when you have WooCommerce or heavy plugins.

For a deeper explanation of how these layers fit together, see Understanding WordPress Caching Layers.

Where PHP-FPM and database performance fit into the picture

Even with good caching, some requests always hit PHP-FPM and the database:

  • First visitor to a page before it is cached.
  • Logged in users and WooCommerce carts.
  • Admin area and AJAX calls.

PHP-FPM needs enough workers to handle realistic traffic, but not so many that it exhausts RAM and swaps. Your database needs sensible buffers and indexes so queries finish quickly. The G7Cloud guide on PHP workers, concurrency and WooCommerce explains this connection.

Preparing Your VPS or VDS for Caching

Baseline server checks: CPU, RAM, disk and PHP version

Before touching Nginx, confirm the basics:

  • CPU: 2 vCPUs is a comfortable minimum for a modest WooCommerce shop. Brochure sites can manage with 1, but 2 gives more headroom.
  • RAM: 2 GB is usually enough for a single small site, 4 GB or more is safer for WooCommerce or multiple sites.
  • Disk: Use SSD or NVMe only. Check df -h to ensure you are not close to full.
  • PHP version: use a supported version (PHP 8.1 or newer at the time of writing). Run php -v to check.

Managed platforms that focus on web hosting performance features such as tuned PHP and database stacks usually handle sensible defaults for you, but on a self managed VPS these checks are your responsibility.

File structure: where Nginx, PHP-FPM and WordPress live

On a typical Debian/Ubuntu server:

  • Nginx site configs are under /etc/nginx/sites-available/ and symlinked from /etc/nginx/sites-enabled/.
  • PHP-FPM pool configs are under /etc/php/8.x/fpm/pool.d/.
  • WordPress lives somewhere like /var/www/example.com/public.

Ensure ownership and permissions are sensible:

chown -R www-data:www-data /var/www/example.com
find /var/www/example.com -type d -exec chmod 755 {} \;
find /var/www/example.com -type f -exec chmod 644 {} \;

This reduces permission related errors when caching plugins create cache folders.

Security basics that affect caching: HTTPS, firewalls and bad bot traffic

You should have:

  • HTTPS via Let’s Encrypt or a commercial certificate.
  • A firewall (for example ufw or firewalld) allowing only 80/443 plus SSH.
  • Fail2ban or similar for basic brute force defence.

Bad bots and aggressive crawlers can destroy the benefits of caching by constantly requesting uncached URLs or bypassing cache rules. G7Cloud’s bot protection within the G7 Acceleration Network filters abusive and non human traffic before it reaches PHP or the database, which helps keep response times stable and reduces wasted server load during busy periods.

When a managed platform or acceleration layer can take care of edge caching for you

An edge or acceleration network sits between users and your VPS, caching content geographically closer to visitors and filtering unwanted traffic.

For example, the G7 Acceleration Network provides edge caching, bot filtering, image optimisation and security headers automatically. In that case, you may keep Nginx configuration simpler and let the network handle full page caching, focusing mainly on correct bypass rules for logins and WooCommerce.

Configuring Nginx for Fast Static Assets and Simple Page Caching

Clean Nginx server block for WordPress (no conflicting legacy rules)

A minimal server block for WordPress on HTTPS might look like:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.php index.html;

    # SSL config here...

    include /etc/nginx/snippets/wordpress-static.conf;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }

    location ~* \.(php|phtml)$ {
        deny all;
    }
}

Keep the WordPress rules simple. Remove old Apache-style .htaccess assumptions and unnecessary rewrites.

Serving static assets directly: CSS, JS, images and fonts

In /etc/nginx/snippets/wordpress-static.conf you can add:

location ~* \.(?:css|js|jpg|jpeg|gif|png|webp|avif|ico|svg|woff2?)$ {
    access_log off;
    log_not_found off;
    try_files $uri =404;
}

This tells Nginx to deliver static files directly from disk and not pass them to PHP. If you offload images to an edge network, such as the G7 Acceleration Network, static delivery will often happen there instead, taking further load off your VPS.

Setting sensible browser cache headers in Nginx

Add cache headers in the same static block:

location ~* \.(?:css|js|jpg|jpeg|gif|png|webp|avif|ico|svg|woff2?)$ {
    access_log off;
    log_not_found off;
    expires 30d;
    add_header Cache-Control "public, max-age=2592000, immutable";
    try_files $uri =404;
}

The immutable directive works best if you use versioned file names (for example style.12345.css). Many themes and plugins already do this when you update assets.

If you use an acceleration network that handles image conversion, note that the G7 Acceleration Network automatically converts images to AVIF and WebP on the fly, usually cutting image weight by more than 60 percent without extra plugins or changes inside WordPress.

Optional: safe Nginx microcaching for anonymous traffic

Microcaching can protect your VPS during spikes by caching HTML for a short time. Add this to the http block in nginx.conf:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:10m
                 inactive=60s max_size=500m;

In your server block:

set $no_cache 0;

# Do not cache logged in users or WooCommerce sessions
if ($http_cookie ~* "wordpress_logged_in_|woocommerce_items_in_cart|wp_woocommerce_session_") {
    set $no_cache 1;
}

location / {
    proxy_cache_bypass $no_cache;
    proxy_no_cache $no_cache;

    proxy_cache WORDPRESS;
    proxy_cache_valid 200 30s;
    proxy_cache_valid 404 1m;
    add_header X-Proxy-Cache $upstream_cache_status;

    try_files $uri $uri/ /index.php?$args;
}

This is a simple example and you must test WooCommerce thoroughly. Keep microcache times short and never cache logged in users or cart / checkout traffic.

Tuning PHP-FPM So Caching Has Something Fast To Talk To

A visual explaining how Nginx passes dynamic requests to PHP-FPM workers, showing a queue of requests, a limited number of workers and how caching reduces the number of dynamic requests hitting PHP-FPM.

How PHP-FPM workers interact with Nginx and WordPress

Nginx passes PHP requests to PHP-FPM via a socket or TCP port. Each request occupies a PHP-FPM worker until it finishes. If all workers are busy, new requests queue and users see slow responses or 502/504 gateway errors.

Caching reduces how often this happens, but PHP-FPM still needs sane limits.

Choosing a process manager (dynamic vs ondemand) for a typical WordPress VPS

PHP-FPM pool configuration is usually in /etc/php/8.x/fpm/pool.d/www.conf. Two useful settings are:

  • dynamic: keeps some workers always ready, good for steady traffic.
  • ondemand: starts workers only when needed, good for low traffic sites.

For a typical production WordPress VPS, dynamic is a safe starting point. Example:

pm = dynamic
pm.max_children = 12
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8

Adjust pm.max_children based on RAM and typical PHP memory usage.

Setting max children and timeouts so cache misses do not cause 502/504s

Estimate pm.max_children as:

max_children ≈ (PHP RAM limit fraction of system RAM) / estimated PHP memory per request

Example:

  • Server RAM: 4 GB
  • Allocate roughly 2 GB to PHP-FPM
  • Average PHP request uses around 128 MB

Then pm.max_children ≈ 2048 / 128 ≈ 16. It is safer to start at 12 and monitor.

Also check:

request_terminate_timeout = 60s

This stops very slow scripts from hanging workers forever.

Monitoring PHP-FPM under load and avoiding “too many workers, not enough RAM”

Monitor with top or htop. Watch:

  • Swap usage (avoid any if possible).
  • Number of php-fpm processes during traffic.
  • CPU saturation during cache misses.

If you see 502/504 responses during spikes, the guide on diagnosing and fixing WordPress 502/504 errors provides a deeper troubleshooting path.

Choosing and Configuring a WordPress Cache Plugin That Plays Nicely With Nginx

What a cache plugin should do (and what Nginx should already be handling)

On an Nginx VPS, your caching plugin does not need to manage everything. Ideally, it should:

  • Generate static HTML files for each page (page cache).
  • Set correct rules for WooCommerce and logged in users.
  • Optionally manage object caching (Redis or Memcached) if you choose.

Let Nginx handle gzip or Brotli compression and browser cache headers. Avoid enabling duplicate features in both Nginx and the plugin.

Recommended plugin categories: full page cache vs object cache vs all in one

  • Full page cache plugins create HTML snapshots of each page. Examples include popular performance plugins that can store cache on disk.
  • Object cache plugins integrate WordPress with Redis or Memcached. These are very helpful for WooCommerce.
  • All in one plugins combine page cache, object cache, minification and sometimes CDN features.

On a VPS with Nginx, page cache + object cache is usually enough. Use minification cautiously because it can break scripts and makes debugging harder.

Key plugin settings to align with Nginx: cache path, cache TTL, gzip/Brotli, browser cache

Adjust these in your plugin:

  • Cache storage method: choose “Disk” or “Disk enhanced” so Nginx can serve cached HTML quickly.
  • Cache path: leave defaults unless you have a separate data disk; ensure the directory is writable by the web user.
  • TTL (time to live): 10–60 minutes for most blogs, 5–15 minutes for busy WooCommerce shops.
  • Compression: disable gzip/Brotli compression in the plugin if you already have them configured in Nginx.
  • Browser cache: if you configure this in Nginx, disable the plugin’s browser cache settings to avoid conflicting headers.

Avoiding double work and conflicts: compression, minification and CDN features

Conflicts to avoid:

  • Do not enable HTML/CSS/JS minification in multiple plugins at once.
  • Do not use a plugin’s CDN feature if an acceleration network such as the G7 Acceleration Network already handles edge delivery.
  • Keep image optimisation in one place. If your host’s network converts images to AVIF/WebP automatically, turn off heavy compression plugins in WordPress to avoid double processing.

Safe Caching Rules for WooCommerce and Logged In Users

A conceptual graphic showing which WooCommerce pages can be cached and which must always be dynamic, using different colours or shapes to distinguish safe cached pages from sensitive areas like cart and checkout.

Pages you must never serve from a full-page cache

For WooCommerce, never cache:

  • /cart/
  • /checkout/
  • /my-account/ and related account pages
  • Any pages handling vouchers, custom pricing or user specific content

Also avoid full page cache for /wp-admin/ and /wp-login.php.

Using cookies and URL rules to bypass cache for carts, checkout and account areas

Ensure both Nginx and your cache plugin bypass cache when certain cookies are present, for example:

  • woocommerce_items_in_cart
  • wp_woocommerce_session_*
  • wordpress_logged_in_*

Most WooCommerce-aware cache plugins include these by default, but confirm in the settings. In Nginx, we used the $http_cookie condition earlier to drive $no_cache.

Handling personalised pricing, vouchers and dynamic fragments

If you use:

  • Role based pricing
  • Voucher / discount plugins with dynamic totals
  • GeoIP based pricing

you may need to reduce what is cached on pages that show different content per user. Options include:

  • Disabling page cache on specific URLs or product categories.
  • Using fragment caching (widgets that render dynamic bits separately).
  • Shortening cache TTL on shop and product pages.

The article on WooCommerce caching without breaking carts covers advanced rules and patterns in more depth.

Testing WooCommerce with caching: real-world scenarios to run through

Always test:

  1. Browse as a guest, add products to basket, go to cart and checkout.
  2. Log in as a customer, repeat cart and checkout.
  3. Apply a voucher; confirm totals update correctly.
  4. Change stock levels in admin and confirm product pages reflect them after cache expiry or a manual purge.

Note: when an edge network or WAF is doing the caching for you

If a service such as the G7 Acceleration Network handles edge caching, you typically set “do not cache” rules for WooCommerce-sensitive URLs and cookies at the edge, and reduce or disable full page cache on the origin. The network can still cache static assets and anonymous product/category pages while respecting carts and checkouts.

Object Caching and Database Load: When Redis or Memcached Help

What object caching is and why it helps heavy plugins and WooCommerce

Object caching stores the results of expensive queries and operations. WooCommerce, membership plugins and page builders make many database calls per request. With an object cache, repeated queries are served from memory instead of hitting MySQL each time.

Comparing file-based object cache to Redis or Memcached on a VPS

  • File-based: stores cache data on disk. Better than nothing, but much slower than memory and adds disk I/O.
  • Redis: in-memory key value store, persistent, very common for WordPress.
  • Memcached: simple in-memory cache, non-persistent, also widely supported.

On a VPS, Redis is usually the most practical: good performance and straightforward configuration.

Basic Redis/Memcached setup and WordPress integration plugins

Example Redis install on Debian/Ubuntu:

apt update
apt install redis-server php-redis

Enable Redis and ensure it listens on 127.0.0.1 only for security. Then in WordPress:

  • Install a Redis object cache plugin.
  • Enable object cache inside the plugin’s settings.

Watch RAM usage after enabling, especially on smaller VPS plans.

How object cache interacts with page cache and when to invalidate it

Object cache sits behind page cache. If a page is served from page cache, object cache is not touched. On cache misses or for logged in traffic, object cache reduces the work for PHP and MySQL.

Most plugins handle invalidation automatically on content changes. If you see stale data in the front end, clear both page cache and object cache together.

Testing, Monitoring and Troubleshooting Your Caching Setup

An abstract dashboard-style image hinting at CPU, RAM and response time graphs on a VPS, to illustrate monitoring whether caching is working as intended.

How to confirm Nginx is serving cached pages vs hitting PHP

Useful checks:

  • Enable a header from your cache plugin, for example X-Cache: HIT / MISS.
  • In Nginx microcache, the X-Proxy-Cache header we added will show HIT, MISS or BYPASS.
  • Use curl -I https://example.com/ to inspect response headers.

Spotting cache hits and misses in response headers

Examples:

curl -I https://example.com/

HTTP/2 200
x-proxy-cache: HIT
x-cache: HIT

or

HTTP/2 200
x-proxy-cache: MISS
x-cache: MISS

You want consistent HIT for anonymous home, category and blog pages after the first request.

Tools to test performance

Use:

  • WebPageTest to see waterfall charts and confirm static assets and HTML are cached.
  • Google PageSpeed Insights to verify Core Web Vitals over time.
  • Real browser tests in incognito and logged in modes to check WooCommerce behaviour.

If your host provides an acceleration layer like the G7 Acceleration Network, it will also handle on the fly conversion of images to AVIF/WebP, improving Web Vitals by reducing image sizes significantly without extra configuration.

Common problems: mixed content, stale pages, 502/504 under load and what to change first

  • Mixed content: ensure WordPress site URLs are set to HTTPS and that any reverse proxy or edge network forwards the correct scheme.
  • Stale pages: shorten cache TTL or enable automatic cache purge on content updates in your plugin.
  • 502/504 errors: check PHP-FPM worker limits, slow database queries and whether bad bots are causing excessive uncached requests.

If resource usage stays high even after caching, the guide on troubleshooting high CPU and memory usage on WordPress walks through next steps.

Watching server graphs to see whether caching is actually reducing load

On your VPS dashboard or monitoring tool, look for:

  • Lower average CPU under similar traffic.
  • Reduced disk I/O and database queries per second.
  • Stable PHP-FPM process counts during traffic spikes.

The article on reading WordPress hosting resource graphs helps interpret these metrics.

Keeping Your Caching Setup Stable Over Time

A conceptual image showing legitimate visitors being served quickly from cache while abusive bots are filtered away before they reach the server, to illustrate the value of bot protection alongside caching.

Deploying theme and plugin updates without wiping or poisoning the cache

When you update themes or plugins:

  • Clear cache for affected URLs (for example, product pages if you update WooCommerce templates).
  • Avoid clearing the entire cache unnecessarily, especially before busy trading periods.
  • Test on a staging site if you are changing caching plugins or Nginx configuration.

When to clear caches manually vs let them expire

Let caches expire naturally when:

  • You are only changing content (new blog posts, price changes) and your plugin auto purges related pages.

Clear manually when:

  • You change themes, page builders or core layout.
  • You alter Nginx cache rules or PHP-FPM settings.
  • Customers report seeing outdated content after updates.

Planning for traffic spikes: pre-warming caches and filtering abusive bots before PHP

Before a campaign or sale:

  • Pre-warm key pages (home, top categories/products) using your cache plugin’s preload feature or a simple crawler script.
  • Shorten microcache TTL slightly during volatile content changes.

Filtering abusive bots is as important as caching. G7Cloud’s bot protection within the G7 Acceleration Network filters non human and abusive requests before they reach your VPS, which helps maintain consistent response times and avoids PHP-FPM overload during spikes.

When it is time to move from home-grown caching to a managed WordPress or VDS platform

Signs you may be better off on a managed platform include:

  • Frequent firefighting of 502/504 errors during promotions.
  • Needing complex edge rules for WooCommerce that you are not comfortable maintaining.
  • Lacking time to monitor PHP-FPM, Redis and Nginx logs regularly.

In those cases, exploring managed WordPress hosting if you prefer caching and stack tuning handled for you or a tuned Virtual dedicated servers designed for WordPress and WooCommerce can free you to focus on the site rather than the stack.

Summary: A Simple, Robust Caching Pattern You Can Reuse

Checklist of key Nginx, PHP-FPM and plugin settings

  • Nginx serves static assets directly with long-lived cache headers.
  • Optional microcaching for anonymous traffic, bypassing cookies for logins and WooCommerce.
  • PHP-FPM using dynamic process management with sensible pm.max_children and timeouts.
  • WordPress cache plugin storing page cache on disk, not duplicating Nginx compression or browser cache.
  • Redis or Memcached object cache for WooCommerce or heavy plugins when RAM allows.
  • Clear rules for never caching carts, checkouts, account pages and logged in users.

How to adapt this pattern for additional sites or a multi-site server

When you host additional sites:

  • Create a separate Nginx server block per domain, possibly with its own microcache zone.
  • Use separate PHP-FPM pools for particularly heavy sites so one cannot starve others of workers.
  • Consider central Redis for object caching but monitor memory usage as you add sites.

Where to get help if you would rather somebody else maintain this stack

Not everyone wants to tune Nginx, PHP-FPM and Redis by hand. If you would rather focus on content and trading, managed platforms that bundle caching, acceleration networks and tuned PHP/database settings can remove much of the complexity.

If that sounds appealing, it is worth exploring managed WordPress hosting if you prefer caching and stack tuning handled for you or a G7 Acceleration Network backed VDS. You can still keep control of your WordPress site while letting a specialist platform handle caching, bad bot filtering and media optimisation in a consistent way.

Table of Contents

G7 Acceleration Network

The G7 Acceleration Network boosts your website’s speed, security, and performance. With advanced full page caching, dynamic image optimization, and built-in PCI compliance, your site will load faster, handle more traffic, and stay secure. 

WordPress Hosting

Trusted by some of the worlds largest WooCommerce and WordPress sites, there’s a reason thousands of businesses are switching to G7

Related Articles