Varnish Cache Configuration

Full-page caching with safe, UI-managed configuration

Varnish Full-Page Cache

When Varnish is installed on your server, its card in the Services tab gets a Configure button next to Stats. It opens a full-screen dialog where you can manage the cache without ever touching a terminal: a friendly Cache Exclusions tab for day-to-day rules, and a full Raw VCL editor for everything else — both with automatic safety checks, so a typo can never take your site down.

How the cache works

Varnish sits between your web server's TLS frontend and your application:

client → Apache :80/:443 (TLS) → Varnish 127.0.0.1:6081 → Apache backend 127.0.0.1:8080 → PHP-FPM

Anonymous page views are answered straight from memory — typically 80%+ of all traffic never touches PHP or the database. POST requests, logged-in sessions and error responses are never cached.

Tab 1 — Cache Exclusions

Some pages must never be cached: shopping carts, product comparison pages, anything that stores per-visitor state in cookies. One shared cached copy of such a page means every visitor sees the same (wrong) content. The Cache Exclusions tab manages a list of URL patterns that always bypass the cache — matching requests go straight to the backend, cookies intact, and the responses are never stored.

  • Add a rule — a regex pattern plus a label documenting why it exists
  • Test a URL — paste any URL and instantly see which rule (if any) it matches, before saving
  • Purge on apply — optionally evict already-cached copies of matching URLs, so new rules take effect immediately instead of when the old copies expire

Patterns are PCRE regexes matched against the URL path + query string. They are not anchored — use ^ and $ to anchor. A few examples:

  • /compare(\?|$) — any URL ending in /compare, with or without a query string
  • ^/api/ — everything under /api/
  • \.pdf$ — URLs ending in .pdf
🔒 Your rules can't be lost by accident

Exclusion rules live in their own file (/etc/varnish/exclusions.vcl), included from the main VCL. If the include line ever goes missing — say, after a manual edit in the Raw VCL tab — it is silently re-added on the next save. To remove a rule, delete it in this tab.

Tab 2 — Edit Raw VCL

Full control over /etc/varnish/default.vcl for cache lifetimes (TTLs), grace mode, cookie handling, stateful path lists and anything else VCL can do. Every save goes through a safety pipeline:

  • Backup — a timestamped copy of the current config is kept (last 10 versions)
  • Compile test — the new VCL is compiled first; syntax errors are rejected, the exact compiler output is shown, and the previous config stays active
  • Zero-downtime reload — on success Varnish loads the new VCL without restarting and without emptying the cache
⚠️ Compiles ≠ correct

The compile test catches syntax errors, not logic errors. A VCL that compiles perfectly can still cache pages it shouldn't, or send all traffic to a dead backend. Test on a staging server when in doubt, and verify behavior after every change (see below).

First-time setup

If Varnish is installed but not yet configured for any site, the Raw VCL editor opens with a commented-out starter template instead: a step-by-step guide for wiring a site through Varnish, plus a production-tested reference VCL to uncomment and adapt. The short version:

  • 1. Point Varnish at 127.0.0.1:6081 via a systemd override
  • 2. Move the site's Apache vhost to 127.0.0.1:8080 (plain HTTP), adding mod_remoteip so your logs keep real visitor IPs, and SetEnvIf X-Forwarded-Proto "https" HTTPS=on so the application knows the original request was HTTPS
  • 3. Create a frontend vhost on ports 80/443 that keeps the TLS certificates and proxies everything to Varnish
  • 4. Uncomment and adapt the reference VCL, then Save & Apply

The template contains complete copy-paste examples for each step, including the Apache vhost snippets.

Verifying cache behavior

Every response carries an X-Cache header. Check any URL with:

curl -sI https://www.example.com/some-page | grep X-Cache
  • MISS then HIT on a second request — the page is being cached correctly
  • MISS every time — the URL is excluded or uncacheable (this is what you want for pages matched by an exclusion rule)

The Stats button on the Varnish card shows the live hit rate, memory usage and evictions — see the Services tab documentation.

💡 Real-world example

A product comparison feature stored the visitor's selection in a cookie. With full-page caching, the compare page was served as one shared copy — removing a product appeared to do nothing, because the next page load came from cache. One exclusion rule (/compare(\?|$)) fixed it in under a minute, while the rest of the site stayed fully cached.