varnish/varnish-bundle
A PHP bundle for integrating the Varnish HTTP accelerator with your application, with configuration for reverse-proxy setup, cache purging, and ban requests so dynamic pages can be served quickly from Varnish while staying fresh.
composer require varnish/varnish-bundle
app/AppKernel.php:
new Varnish\VarnishBundle(),
(Confirm the exact namespace from the bundle's VarnishBundle.php — the repo name suggests Timewasted\VarnishBundle or similar.)app/config/config.yml. Because documentation is thin, the authoritative source is DependencyInjection/Configuration.php:
varnish:
servers:
- host: 127.0.0.1
port: 6081
DependencyInjection/Configuration.php — the real, supported config keys.Resources/config/services*.xml — the actual client service ID (varnish, varnish.client, etc.).Command/ — any shipped console commands (purge/ban/cache-clear style).Tests/ — the fastest way to see intended API usage.$varnish = $this->get('varnish'); // verify service id
$varnish->purge('http://example.com/foo');
Wrap this in a kernel.request-independent service so you don't scatter get() calls throughout controllers.Centralize invalidation behind your own service. Don't call the bundle client from controllers. Define a CacheInvalidator that wraps the client, adds URL normalization, and fans out to every configured server. This makes the bundle swappable (you will likely need to swap it) and unit-testable.
Doctrine listener for entity-driven purge. The classic pattern: postPersist/postUpdate/postRemove on content entities, then purge the affected URL(s). Use postUpdate + a value object, not raw entity state, so you don't accidentally trigger purges inside transactions or in preUpdate.
Ban regex for bulk/related invalidation. When one edit touches many URLs (e.g. a tag page, an RSS feed, a homepage), purge per URL doesn't scale. Issue a single ban expression instead:
$varnish->ban('obj.http.X-Cache-Tags ~ "blog-42"'); // or equivalent API
Then emit a matching X-Cache-Tags header from Symfony so Varnish can match on it.
Console command for deployments. Wrap purge/ban in a Symfony command and call it from your deploy pipeline immediately after cache:warmup and before traffic is shifted. Idempotent, exit-code driven, safe to re-run.
Coordinate with Symfony's own cache layers. If you use HttpCache/ESI, Varnish sits in front of it. Decide explicitly which layer owns which URL, otherwise you'll purge Varnish and still serve stale ESI fragments from behind it (or vice versa). The common setup: Symfony app cache for internal fragments, Varnish for full-page.
Multi-node fan-out. Configure every Varnish node; loop in the invalidator and log per-node failures so a single dead node doesn't abort the whole purge set.
Environment separation. Keep Varnish servers out of config.yml defaults and into config_dev.yml/config_prod.yml — local dev commonly has no Varnish, and you don't want failing purges in development.
6081, and it is not the cache port (80). Check ACLs, firewalls, and Varnish's -T flag. This is the single most common "it does nothing" cause.purge matches one URL exactly; ban matches a pattern against all cached objects and stays in the ban list until its objects age out. Bans are cheap to issue but expensive on huge caches — enable the ban lurker and keep ban lists short.Accept-Encoding variants, query-string order, and http vs https all create distinct cache entries. Purge exactly what was cached; if you're not sure, capture the real request URL from varnishlog and match that.acl purge { ... } plus if (req.method == "PURGE") blocks restricted to your app servers — otherwise you've built a remote cache-flush endpoint for anyone.?, ., +, and : are regex-active. A naive ban("req.url == " . $url) will silently match the wrong (or no) objects.200 from the admin socket even when nothing matched. Verify with varnishadm "ban.list" and varnishlog -g request -q 'ReqMethod eq "PURGE"' rather than trusting the client's return value.telnet localhost 6081 → ping; then varnishadm "ban.list"; then confirm the VCL branch; then confirm the app emits the headers your ban matches on.How can I help you explore Laravel packages today?