Download the PHP package alengo/sulu-bunny-cdn-bundle without Composer
On this page you can find all versions of the php package alengo/sulu-bunny-cdn-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download alengo/sulu-bunny-cdn-bundle
More information about alengo/sulu-bunny-cdn-bundle
Files in alengo/sulu-bunny-cdn-bundle
Package sulu-bunny-cdn-bundle
Short Description bunny.net CDN integration for Sulu/Symfony: tag-based edge cache invalidation (CDN-Tag header + wildcard purge) wired into FOS HttpCache.
License MIT
Homepage https://github.com/alengodev/SuluBunnyCdnBundle
Informations about the package sulu-bunny-cdn-bundle
AlengoBunnyCdnBundle
bunny.net CDN integration for Sulu/Symfony websites: tag-based edge cache invalidation wired into FOS HttpCache. On every Sulu publish, both the local HttpCache kernel and the bunny.net pull zone are purged — content updates go live worldwide in seconds instead of waiting for the TTL.
Architecture
Two cache layers, both invalidated on every publish:
- Mirrors the
X-Cache-Tagsresponse header (FOS TagListener / Sulu) into bunny.net'sCDN-Tagheader (BunnyCdnTagSubscriber), hashing each tag to 12 chars (xxh128) to fit bunny.net's hard 1024-byte header limit (~78 tags per response instead of ~27 raw UUIDs). - Registers a
BunnyProxyClient(FOS proxy client: tags, URLs, full clear) plus aMultiplexerClientthat forwards every invalidation to the local Symfony HttpCache kernel client and bunny.net. - Prepends
fos_http_cache.cache_manager.custom_proxy_client, so Sulu'sCacheManagerpurges bunny.net on publish — no project wiring needed.
The bunny.net single-tag pitfall
bunny.net stores the whole CDN-Tag header value as ONE tag — it does not
split at commas or any other separator, and its purge API answers 204 even
when nothing matches. Exact-match tag purges are therefore silent no-ops.
This bundle uses the working pattern (same as the Drupal bunny_cdn module):
the header is written as a space-separated list with : … : guards
(CDN-Tag: : a1b2c3d4e5f6 0f9e8d7c6b5a :), and purges use a wildcard pattern
({"CacheTag": "* a1b2c3d4e5f6 *"}) that matches the space-bounded tag inside
the stored value.
1. Installation
The credentials default to env placeholders — set them in .env.local
(never commit them):
The env vars must be set wherever the bundle is enabled — FOS flushes the invalidation queue on
console.terminate, so the proxy client is instantiated by every console command.
All options:
Requires the FOS symfony proxy client (or adjust additional_proxy_clients):
2. Create the pull zone (bunny.net dashboard)
CDN → Add Pull Zone
| Setting | Value |
|---|---|
| Name | e.g. example (becomes example.b-cdn.net) |
| Origin Type | Origin URL |
| Origin URL | https://origin.example.com — the host that reaches the web server WITHOUT the CDN. Must be https:// — with http:// the origin's force-SSL redirect (301 to the origin host!) gets cached and served to visitors. |
| Pricing Zones | For GDPR-sensitive sites: enable Europe only |
Under Hostnames:
- add the public domain (e.g.
www.example.com) as custom hostname - enable Free SSL (Let's Encrypt) and Force SSL
3. Caching settings of the pull zone
Caching → General:
- Cache Expiration Time:
Respect Origin Cache-Control. Sulu sendss-maxageaccording to the template cache lifetime; with working tag purges the TTL can be raised later without losing freshness. - Query String Sort: enable.
- Query String Vary: "Vary by Query String Parameters" with a whitelist
of the parameters that actually matter (e.g.
q,page, form params) — keepsutm_*,gclid& co. from fragmenting the edge cache. - Strip Response Cookies: DISABLE! bunny.net strips
Set-Cookiefrom ALL responses — including uncached POSTs, not just cache hits. The admin login never receives its session cookie and every subsequent request fails with 401. Cached personalized responses are prevented by the session-bypass edge rule (§4) and the origin'sprivate/no-cache. - Perma-Cache: keep disabled — tag purging does not work with it.
- Stale Cache: "While Origin Offline" is a sensible resilience option; keep "While Updating" OFF, otherwise the first visitor after a purge is served the old version once.
4. Edge rules (mandatory!)
bunny.net does not include cookies in the cache key. Personalized or logged-in requests must therefore BYPASS the edge cache (the origin kernel cache handles them correctly). Create these rules (Pull Zone → Edge Rules → Add Edge Rule):
Rule "SessionBypass" — logged-in users:
- Action:
Override Cache Time→0 - Condition:
Request Header→ headerCookie→ pattern*SULUSESSID*(adjust to your session cookie name)
Rule "AdminNoCache" — never cache the admin:
- Action:
Override Cache Time→0 - Condition:
Request URL→ matches →*/admin* - Needed even though the origin sends
private: bare redirects (e.g. Apache's/admin→/admin/) carry no Cache-Control and DO get cached.
Additional bypass rules for any personalization cookies your site uses
(same action, conditions Request Header: Cookie with *cookie_name*
patterns, "Match Any").
⚠ Cookie condition pitfall: do NOT use the Cookie Value condition type
with pattern * — it also matches requests WITHOUT the cookie, the rule then
applies to ALL requests and the whole zone becomes BYPASS (nothing is
cached anymore). Use Request Header: Cookie with a substring pattern — a
missing header never matches a substring.
Edge rules always need at least one condition. For rules that should
apply to every request, use Request URL → matches → *.
CDN-Tag stays visible to browsers: response headers starting with
CDN- cannot be set/cleared via edge rules ("Header names starting with
CDN- are not allowed"). The header only contains 12-char hashes and is
useful for debugging — leave it.
5. Host handling & origin lockdown
If the origin vhost only serves the origin hostname (and answers the public
host with 421 Misdirected Request):
- Forward Host Header: keep DISABLED (default) — bunny.net sends the host from the Origin URL. Forwarding the public host does NOT work (421).
-
So the app still generates public URLs, present the public host to the app in the origin's
.htaccess: -
Origin lockdown: edge rule
Add Request Header(acts on requests to the origin only) →X-Origin-Verify: <secret>, conditionRequest URLmatches*; the.htaccessrejects requests without it:Do not commit the secret. Save the edge rule BEFORE arming the
.htaccess, or you lock bunny.net out. Rotating = change both places.
6. DNS
Point the public domain as CNAME to <zone>.b-cdn.net (only after SSL
for the hostname is provisioned). The origin must stay directly reachable
under its own hostname (A record, own vhost with TLS).
7. Verify
cdn-cache legend: MISS/EXPIRED/HIT = normal caching, BYPASS = an
override-cache-time-0 rule matched. MISS after a purge = entry was gone;
EXPIRED = regular TTL refetch.
⚠ Verifying purges: a 204 from the API proves nothing (bunny.net
returns 204 even for non-matching tags), and a "successful purge" observed
after the entry's TTL has expired is just the regular refetch. Always check
cdn-cachedat WITHIN the TTL of the entry.
Publish test: change + publish a page in the admin → the next request to the live URL must return the new content within seconds.
8. Operations & limits
- Publish invalidates both layers automatically (tag-based).
- Full flush:
bin/console fos:httpcache:clearor the dashboard's "Purge Cache". Note: Symfony'scache:cleardoes NOT purge HTTP caches. - 401 "Unauthorized" from caching proxy on publish/console commands:
BUNNY_API_KEYis missing/wrong — it must be the ACCOUNT API key, not a pull-zone key. Test:curl -H "AccessKey: $KEY" https://api.bunny.net/pullzone. invalidateDomain()(BAN/regex) is not supported by bunny.net and is a no-op.- The
CDN-Tagheader is limited to 1024 bytes (~78 hashed tags); overflow tags are dropped cleanly — affected pages refresh via the regular TTL. - Wildcard purges are rate-limited by bunny.net (burst ~20, ~0.5/s refill); mass publishes may drop some purges — affected pages heal via the TTL.
All versions of sulu-bunny-cdn-bundle with dependencies
friendsofsymfony/http-cache Version ^3.0
friendsofsymfony/http-cache-bundle Version ^3.0
symfony/config Version ^7.2
symfony/dependency-injection Version ^7.2
symfony/event-dispatcher Version ^7.2
symfony/http-foundation Version ^7.2
symfony/http-kernel Version ^7.2