Skip to content

Varnish

Danila Vershinin edited this page Dec 5, 2025 · 8 revisions

Varnish

Varnish Cache is a web application accelerator also known as a caching HTTP reverse proxy. You install it in front of any server that speaks HTTP and configure it to cache the contents. Varnish Cache is really, really fast. It typically speeds up delivery with a factor of 300 - 1000x, depending on your architecture.

Configuration

This plugin enables your WordPress site to communicate with Varnish to dynamically empty the cache for any and all updated content. It does not install nor manage your Varnish configuration.

The Sample VCLs are provided with no support.

Cache Tags / Surrogate Keys (BETA)

Starting with Proxy Cache Purge 5.4.0, the plugin includes an optional Cache Tags / Surrogate Keys purge mode. When enabled in WordPress, the plugin:

  • Adds cache‑tag headers to responses (for example, tagging content by post ID, post type, terms, etc.) via an X-Cache-Tags response header.
  • Issues PURGE requests with X-Purge-Method: tags and batched X-Cache-Tags-Pattern values (a pipe‑separated pattern such as tag-a|tag-b|tag-c) instead of purging many individual URLs.

This relies on standard Varnish ban() logic that matches against the X-Cache-Tags header.

To use this with Varnish you should:

  • Allow PURGE from trusted IPs only (for example, your WordPress backend or CI).
  • In vcl_recv, handle PURGE requests that carry X-Purge-Method: tags and X-Cache-Tags-Pattern by issuing a ban() on objects whose X-Cache-Tags header matches the pattern.
  • Optionally advertise support to WordPress via the Edge Architecture Surrogate-Capability header using a tag‑style token (for example, tags/1 or cache-tags/1).

A minimal example using the same approach as the test VCL is:

sub vcl_recv {
    if (req.method == "PURGE") {
        if (!(client.ip ~ purge)) {
            return (synth(405, "PURGE not allowed"));
        }

        # Tag-based purge: match any object whose X-Cache-Tags header
        # matches the provided pattern. The plugin automatically batches
        # tags into safe-length patterns like "tag-a|tag-b|tag-c".
        if (req.http.X-Purge-Method == "tags" && req.http.X-Cache-Tags-Pattern) {
            ban("obj.http.X-Cache-Tags ~ " + req.http.X-Cache-Tags-Pattern);
            return (synth(200, "Banned by tags pattern"));
        }

        # Existing URL / regex purge handling...
    }
}

sub vcl_backend_fetch {
    # Advertise tag capability back to WordPress as per Edge Architecture:
    #   Surrogate-Capability: vhp="Surrogate/1.0 tags/1"
    set bereq.http.Surrogate-Capability = "vhp=Surrogate/1.0 tags/1";
}

The plugin will only let you enable Cache Tags from the WordPress settings screen if your cache advertises support via standard Surrogate-Capability headers (for example:
Surrogate-Capability: vhp="Surrogate/1.0 tags/1"), or if you explicitly opt‑in via the VHP_VARNISH_TAGS define in wp-config.php. Other tag‑style tokens such as cache-tags/1 are also recognised.

Background purging and cron

On high‑traffic or large sites you may not want WordPress to send potentially hundreds of PURGE requests directly from an admin request that just published or updated content. Instead, Proxy Cache Purge can collect those purge operations into a small queue and let WordPress cron process them in the background.

The queue is enabled when:

  • DISABLE_WP_CRON is defined as true (typical when you run a real system cron that calls wp-cron.php), and
  • the internal vhp_purge_use_cron filter resolves to true (by default this mirrors DISABLE_WP_CRON, but hosts can override it).

In this mode:

  • Post updates and other purge‑triggering events still compute the same set of URLs and/or cache tags as in synchronous mode.
  • Instead of immediately sending PURGE requests, the plugin stores:
    • a single full flag (for whole‑site purges),
    • a deduplicated list of URLs, and
    • a deduplicated list of cache tags (when Cache Tags are enabled), in a per‑site option.
  • A dedicated cron hook (vhp_process_purge_queue) periodically drains that queue, sending the actual PURGE requests (either X-Purge-Method: default/regex or X-Purge-Method: tags with batched X-Cache-Tags-Pattern headers).

This has a couple of important implications for Varnish/NGINX operators:

  • You still see the same PURGE patterns on the wire as in synchronous mode; they may simply arrive in bursts when cron runs instead of during the editor’s page load.
  • Whole‑site purges are collapsed: if many granular invalidations accumulate before cron runs, the plugin will flip the queue to a single full purge (/.* with X-Purge-Method: regex) instead of spamming many individual URLs.
  • The WordPress Site Health screen will warn you if the queue becomes very large or very old, which is often a sign that cron is not running.

For operational control, the plugin exposes a few hooks:

  • vhp_purge_use_cron – force cron‑mode on or off, regardless of DISABLE_WP_CRON (useful for managed platforms).
  • vhp_purge_queue_before_save – adjust or inspect the queue before it is persisted (for example to coalesce URLs or inject your own invalidations).
  • vhp_purge_queue_after_process – receive a summary of each queue run (counts, duration, whether it was a full purge) for logging/monitoring.
  • vhp_purge_bypass_cron_for_request – opt specific purge calls back into synchronous behaviour even when cron‑mode is enabled (for example for a critical deployment script that must wait for cache to be clear).

If you are using WP‑CLI to manage your stack, you can also interact with the queue directly:

  • wp varnish queue status – show whether cron‑mode is active, whether a full purge is queued, and how many URLs/tags are pending.
  • wp varnish queue process – run the queue processor immediately (for example in a deployment pipeline).
  • wp varnish queue clear – drop any queued work without sending PURGE requests.

These commands are particularly useful in combination with a system cron that runs WordPress cron on a schedule, for example:

*/5 * * * * wp cron event run --due-now --path=/var/www/html >/dev/null 2>&1
*/5 * * * * wp varnish queue process --path=/var/www/html >/dev/null 2>&1

Purging

To purge a URL means to empty the cache for that page. It is also sometimes called 'banning'

To manually purge a page: curl -X PURGE https://example.com

To purge wildcard: curl -X PURGE https://example.com/.*

If you're using a proxy (like Cloudflare or Sucuri), you'll need some variant of this: curl -X PURGE "https://123.45.67.89/" -H "host:www.example.com"

503: Guru Mediation

You've probably seen that error at least once. A 503 error means that the web server trying to be reached is unavailable - this could be because it is overloaded, down for maintenance, or not fully functional for another reason.

The primary issues (and their causes) are as follows:

  • Backend fetch failed -- Memory issues
  • Service unavailable -- Apache and/or MySQL

In the case of memory related issues, the best bet is to disable as many plugins as possible. If that doesn't help, try swapping them to the default theme.

Always make sure themes and plugins are updated! This can be tricky with non WordPress.org hosted code, so you'll need to be on the ball. If your theme or plugin hasn't been updated in a couple years, it's likely the cause.

If you need to open a ticket with your webhost, please include the XID value on the page. They can use that to debug.

Debuggging

If you want to test if Varnish is working, go to Tools -> Varnish Status for a very simple test.

If you're command line savvy, you can monitor the interactions between the plugin and Varnish. This can help you understand what's not working quite right, but it can very confusing.

Command line tools require you to log in as the user account who runs Varnish, as of version 6.0. If you cannot access the following commands, open a ticket with your webhost for assistance.

If you have the XID from the error, you can use that to find the specific log entry:

$ varnishlog -d -q "vxid == 123456"

From that, look for the value for FetchError:

- FetchError backend default: fail errno 110 (Connection timed out)

If you don't have the XID, you will need to find the relevant log entries in varnishlog to give you a clue. Since varnishlog logs a lot of data it might be hard to track the entries down. You can set varnishlog to log all your 503 errors by issuing the following command:

$ varnishlog -q 'RespStatus == 503' -g request

If the error happened just a short time ago the transaction might still be in the shared memory log segment. To get varnishlog to process the whole shared memory log just add the ‘-d’ parameter:

$ varnishlog -d -q 'RespStatus == 503' -g request

Please see the vsl-query and varnishlog man pages for elaborations on further filtering capabilities and explanation of the various options.

Viewing Requests

To see every request made to varnish, use this: varnishncsa -F "%m %U"

A full Varnish flush looks like this: PURGE /.*

Clone this wiki locally