Varnish Installation and Setup Guide

lutish

Administrator
Staff member
Standard Pass
Allvarnish - Setup Guide

Full-page caching for XenForo 2.3. The add-on writes the VCL and sends the invalidations; installing Varnish and terminating TLS are yours.

Code:
visitor -> Cloudflare -> Varnish -> nginx/Apache + PHP^            ^BAN on change   must have NO cache

One fact drives every setting below: the BAN only reaches Varnish. Cloudflare's copy and the browser's copy can only expire, so their lifetime must be short and must never be overridden.


1. Varnish

Install

  1. php cmd.php xf:addon-install Lutish/Allvarnish
  2. ACP > Options > [Lutish] All Varnish - save once to write the defaults.
  3. ACP > Tools > Allvarnish VCL - press the button, copy the output to /etc/varnish/default.vcl.
  4. systemctl reload varnish
The port check that decides everything

Code:
ss -lntp | grep ':80 '

Varnish must own port 80. If nginx owns it and Varnish sits on 6081 with nothing pointing at it, nothing is cached and the add-on looks inert. This is the most common installation failure.

Settings that must match reality

SettingMust equal
Varnish HTTP addressthe -a port of varnishd (where BANs are sent)
Backend addressyour origin listener (e.g. 127.0.0.1:8080), never the CLI port 6082, never the public port

The three lifetimes

SettingDefaultMeaning
Content page lifetime604800How long a thread/resource page lives inside Varnish. Refreshed by BAN, so long is correct.
List page lifetime300Forum lists, What's New, resource index. Never BANed, so they just expire.
Downstream max-age300The Cache-Control sent to Cloudflare and the browser. This is the guest staleness ceiling.

Changing them is save -> generate VCL -> replace the file -> reload -> Clear Varnish cache.

Never cache these paths is baked into the generated file, not read at runtime - editing the list requires a new VCL. The same four steps as above.


2. Cloudflare

Cloudflare holds its own copy that no BAN reaches. Four things decide whether the site stays correct.

2.1 Browser Cache TTL - the one everybody misses

Speed > Optimization > Browser Cache TTL -> Respect Existing Headers

The default is 4 hours, and Cloudflare uses whichever is higher between that and the origin's max-age. With the add-on sending max-age=300, a 4-hour setting still tells every browser to keep the page for 4 hours. Nothing else in this guide matters if this is wrong.

2.2 Cache level / Cache Everything

Speed > Caching > Cache Level

  • Standard only caches static extensions, so XenForo HTML is never cached at the edge. Safe, but every guest page view still crosses to your origin - which is the latency you installed the cache to remove.
  • Aggressive, or a Cache Rule with Cache Everything, caches HTML too. This is what you want, provided 2.1 and 2.3 are correct.
2.3 Never override Edge TTL on HTML

No Edge TTL override in a Cache Rule, no Edge Cache TTL in a Page Rule, on any expression that matches HTML. An override replaces the origin max-age, and the BAN can then never reach that copy. A long TTL for images/css is fine and unrelated.

2.4 Rule order

Rules run top to bottom, first match wins:

  • []/allvarnish/ or /admin.php -> Bypass cache[]static ext, /data/, /js/, /styles/, /cover.php without member cookie -> Cache everything, Edge+Browser TTL = origin
  • everything else -> Cache everything, Edge+Browser TTL = origin

Rule 1 is mandatory. /allvarnish/ hands out the guest CSRF token; if it is cached, every guest gets someone else's token and every form and AJAX call fails with Security error occurred. /admin.php is listed because the zone-level Cache Level still applies to anything no rule matches.

Never append or (not starts_with(path,"/allvarnish/")) to make a rule cover everything. The expression becomes unconditionally true and silently disables every other condition in it, including the /cover.php cookie guard.


3. nginx / Apache

The server behind Varnish must not cache. This is the hardest fault to diagnose because everything else looks right: the add-on can only invalidate Varnish, so a cache between Varnish and PHP serves the same stale page until it expires on its own.

nginx - in the server block Varnish forwards to:
Code:
proxy_cache off;fastcgi_cache off;
fastcgi_cache is the one that bites PHP-FPM setups; proxy_cache off alone is not enough.

Apache - do not enable mod_cache. If it is loaded:
Code:
CacheDisable /

Also check for a panel-level page cache (LiteSpeed Cache, a CDN plugin, an optimiser) - identical symptom.


4. Verify

Straight at Varnish, bypassing both downstream layers (use the port varnishd -a listens on - usually 80, sometimes 6081):
Code:
curl -sI -H 'Host: example.com' http://127.0.0.1:80/ | grep -i cache-control
[HEADING=2]expect: cache-control: public, max-age=300[/HEADING]
curl -sI -H 'Host: example.com' http://127.0.0.1:80/threads/some-title.123/ | grep -i cache-control
[HEADING=2]expect: cache-control: public, max-age=300[/HEADING]

Through Cloudflare:
Code:
curl -sI https://example.com/ | grep -iE 'cache-control|cf-cache-status'
[HEADING=2]expect: max-age=300 and cf-cache-status: HIT[/HEADING]

max-age=604800 means the old VCL is still answering: the file was replaced but Varnish was not reloaded, or a second varnishd is running. Check ps -eo args | grep varnishd before trusting the port number.

cf-cache-status: DYNAMIC on a page that should be cached means the origin sent private, no-cache - the request took the pass path, which happens whenever the browser carries a session or user cookie. Use a private window with a clean cookie jar to test.

x-xf-cache-status is XenForo's own PageCache header. It is stored inside the Varnish object and appears on real hits too, so never use it to judge the cache. cache-control is the only reliable signal.

Activity:
Code:
varnishstat -1 | grep -E 'cache_hit|cache_miss'

Real test: post a reply, wait 5 minutes, reload in a private window. The reply must be there - and must have been visible to a logged-in member immediately.


5. Mistakes, by frequency

MistakeSymptomFix
Browser Cache TTL left at 4 hoursguests stale for hours, members fine2.1
fastcgi_cache / mod_cache still onpages never update for guests3
Aggressive without 2.1/2.3same, at the edge2.1 + 2.3, or go back to Standard
Edge TTL override on HTMLmax-age ignored, BANs look dead2.3
/allvarnish/ not bypassedSecurity error occurred on AJAX2.4
New VCL deployed, Cloudflare not purgedold pages persistPurge Everything once
Exclusion list edited, VCL not regeneratednew paths still cachedregenerate + reload + Clear
Web server still owns port 80nothing cached1

Clear Varnish cache clears Varnish only. It sends a BAN from PHP, which never passes through Cloudflare. After a template or style change, expect guests to see it within ~10 minutes (two 300s downstream layers), not instantly.


6. Limits

  • []No Cloudflare purge. Downstream copies expire by max-age only - that is why section 2 exists.[]Whole documents only. No ESI, no partial caching.[]Exclusion list is baked into the VCL, not a runtime setting.[]Logged-in users are never cached. Deliberate: a cached page carries someone else's CSRF token.
  • Before rebuilding, delete any _output/ folder in the add-on directory or XenForo imports data from there and drops entries missing from it.

Uninstall: point Varnish back at the web server first, then remove the add-on. Removing it while Varnish still fronts the site leaves a proxy with a stale config and no invalidation.
 
Last edited:
Back
Top