eZ Platform uses Symfony HTTP cache to manage content "view" cache with an expiration model. In addition it is extended (using FOSHttpCache) to add several advanced features. For content coming from eZ Platform itself, the following applies:
- To be able to always keep cache up to date, cache is content-aware.
This enables updates to content to trigger cache invalidation.
- Uses a custom
X-Location-Idheader, which both Symfony and Varnish proxy are able to invalidate cache on (for details see Cache purging.)
- Uses a custom
- To be able to also cache requests by logged-in users, cache is context-aware.
- Uses a custom Vary header
X-User-Hashto allow pages to vary by user rights (not by unique user, which is better served by browser cache.)
- Uses a custom Vary header
Cache and expiration configuration¶
This is how cache can be configured in
1 2 3 4 5 6 7
Cache and expiration configuration for error pages¶
You may want to set a high
default_ttl to have a high cache hit ratio on your installation.
As the system takes care of purges, the cache rarely becomes stale.
However, a few redirect and error pages are served via the ContentView system.
If you set a high
default_ttl, they could also be served from cache, which should be avoided.
You should set those specific pages to a much lower TTL.
For this you can use the FOSHttpCacheBundle matching rules feature to specify a different TTL:
1 2 3 4 5 6 7 8 9 10 11 12
Similarly, if you want to apply performance tuning to avoid crawlers affecting the setup too much, you can also set up caching of generic 404s and similar error pages in the following way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Making your controller response content-aware¶
Sometimes you need your controller's cache to be invalidated at the same time as specific content changes (i.e. ESI sub-requests with
render twig helper, for a menu for instance). To be able to do that, you need to add
X-Location-Id header to the response object:
1 2 3 4 5 6 7
Making your controller response context-aware¶
If the content you're rendering depends on a User's permissions, then you should make the response context-aware:
1 2 3 4 5 6
Smart HTTP cache clearing¶
Smart HTTP cache clearing refers to the ability to clear cache for Locations/Content that is in relation with the Content being currently cleared.
When published, any Content item usually has at least one Location, identified by its URL. Because HTTP cache is bound to URLs, if a Content item is updated (a new version is published), you want HTTP cache for all its Locations to be cleared, so the Content itself can be updated everywhere it is supposed to be displayed.
Sometimes, clearing cache for the Content item's Locations is not enough. You can, for instance, have an excerpt of it displayed in a list from the parent Location, or from within a relation. In this case, cache for the parent Location and/or the relation needs to be cleared as well (at least if ESI is not used).
Smart cache clearing mechanism¶
Smart HTTP cache clearing is an event-based mechanism. Whenever a Content item needs its cache cleared, the cache purger service sends an
ezpublish.cache_clear.content event (also identified by the
eZ\Publish\Core\MVC\Symfony\MVCEvents::CACHE_CLEAR_CONTENT constant) and passes an
eZ\Publish\Core\MVC\Symfony\Event\ContentCacheClearEvent event object. This object contains the
ContentInfo object you need to clear the cache for. Every listener for this event can add Location objects to the cache clear list.
Once the event is dispatched, the purger passes collected Location objects to the purge client, which will effectively send the cache
The event is dispatched with a dedicated event dispatcher,
By default, following Locations will be added to the cache clear list:
- All Locations assigned to a Content item (
- Parent Location of all Content item's Locations (
- Locations for Content item's relations, including reverse relations (
Implementing a custom listener¶
By design, smart HTTP cache clearing is extensible. You can implement an event listener/subscriber to the
ezpublish.cache_clear.content event and add Locations to the cache clear list.
Here's a very simple custom listener example, adding an arbitrary Location to the list.
Cache clear listener services must be tagged as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
1 2 3 4 5 6 7 8 9
The Content cache purge (invalidate) mechanism is used when publishing content from the UI or from a container-aware script This results in cache being invalidated either in the built-in Symfony reverse proxy, or on the much faster Varnish reverse proxy.
Note that if you use a non-reverse proxy that does not support purge headers,
shared content will stay in the cache for the whole duration defined by
without the possibility of clearing it.
eZ Platform returns content-related responses with an
The responses are stored together by the configured HTTP cache.
This allows you to clear (invalidate) HTTP cache representing specifically a given Content item.
On publishing the Content, a cache purger is triggered with the Content ID in question,
which in turn figures out affected Locations based on smart HTTP cache clearing logic.
The returned Location IDs are sent for purge using the selected purge type.
Symfony Proxy: Local purge type¶
By default, invalidation requests will be emulated and sent to the Symfony proxy cache store.
1 2 3
Varnish: HTTP purge type¶
With Varnish you can configure one or several servers that should be purged over HTTP.
This purge type is asynchronous, and flushed by the end of Symfony kernel-request/console cycle (during the terminate event).
Settings for purge servers can be configured per SiteAccess group or SiteAccess (in
1 2 3 4 5 6 7 8
For further information on setting up Varnish, see Using Varnish.
While purging on Content, updates are handled for you. On actions against the eZ Platform APIs, there are times you might have to purge manually.
Manually from code¶
Manual purging from code uses the service also used internally for cache clearing on content updates and takes smart HTTP cache clearing logic into account:
1 2 3
Manually by command with Symfony proxy¶
Symfony proxy stores its cache in the Symfony cache directory, so a regular
cache:clear commands will clear it:
Manually by HTTP BAN request on Varnish¶
If you use Varnish and need to purge content directly, use the following examples to see how this is done internally by the FOSPurgeClient, and in turn FOSHttpCache Varnish proxy client:
For purging all:
1 2 3
Or with given Location IDs (here 123 and 234):
1 2 3
As eZ Platform is built on top of Symfony, it uses standard HTTP cache headers. By default the Symfony reverse proxy, written in PHP, is used to handle cache, but it can be easily replaced with any other reverse proxy like Varnish.
Use of Varnish is a requirement for a Clustering setup.
Recommended VCL base files¶
For Varnish to work properly with eZ, you'll need to use one of the provided files as a basis:
Configure eZ Platform¶
Update your Virtual Host¶
You need to tell the PHP process that you are behind a Varnish proxy and not the built-in Symfony HTTP Proxy. If you use fastcgi/fpm you can pass these directly to PHP process, but in all cases you can also specify them in your web server config.
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6
Trusted proxies when using SSL offloader / loadbalancer in combination with Varnish
If your installation works behind Varnish and SSL offloader (like HAProxy), you need to add
Otherwise, you might notice incorrect schema (
http instead of
https) in the URLs for the images or other binary files
when they are rendered inline by Symfony (as used by file-based field templates), as opposed to via ESI.
Update YML configuration¶
Secondly, you need to tell eZ Platform to use an HTTP-based purge client (specifically the FosHttpCache Varnish purge client),
and specify the URL Varnish can be reached on (in
1 2 3 4 5 6 7 8 9 10
Serving Varnish through Fastly¶
To use Fastly, set
purge_server must be set to
purge_server can be set in one of the following ways:
- by adding the parameter
- by setting the
It is recommended to use either
app/config/parameters.yml or the environment variable.
As of eZ Enterprise v1.13.6 and v2.5.9, you no longer need to set
HTTPCACHE_PURGE_SERVER if you set
HTTPCACHE_PURGE_TYPE. If you set
purge_type by any other means, you will still need to set
Note that in
purge_server setting is an array while
app/config/parameters.yml and the
HTTPCACHE_PURGE_SERVER environment variable should be a string.
Fastly service ID and API token¶
You also need to provide your Fastly service ID and API token in the configuration.
The service ID can be obtained by logging in on http://fastly.com and clicking
CONFIGURE in the top menu,
Show service ID at the top left of the page.
See this Fastly guide for
instructions on how to generate a Fastly API token.
The token needs
You may specify service ID and token:
- using the
keysettings (sub elements of "fastly") in
- by setting the parameters
- by setting the environment variables
Unless you need different settings per SiteAccess it is recommended to either use
or the environment variables.
Clear the cache¶
Configuration on Platform.sh¶
If using Platform.sh, it's best to configure the Fastly credentials via Platform.sh variables. You'll also need to disable Varnish which is enabled by default in provided configuration for Platform.sh. See the Platform.sh Professional documentation for running eZ Platform Enterprise on Platform.sh. If using Platform.sh Enterprise see the Platform.sh Enterprise Documentation.
Setting Time-To-Live value for Landing Page blocks¶
Landing Page blocks are rendered using Edge Site Include which means you can set different TTL values for each Landing Page block type.
The TTL setting is available in the configuration under a
ttl key. The value has to be set in seconds:
1 2 3 4 5 6
block_type should be replaced with the actual block name, e.g.
In the example above
block_type will be cached for 10 minutes.
By default blocks are not cached (TTL = 0) for backwards compatibility reasons.
Context-aware HTTP cache¶
As it is based on Symfony, eZ Platform uses HTTP cache extended with features like content awareness. However, this cache management is only available for anonymous users due to HTTP restrictions.
It is possible to make HTTP cache vary thanks to the
Vary response header,
but this header can only be based on one of the request headers (e.g.
Thus, to make the cache vary on a specific context (for example a hash based on User Roles and Limitations),
this context must be present in the original request.
As the response can vary on a request header, the base solution is to make the kernel do a sub-request
in order to retrieve the user context hash (aka user hash).
Once the user hash has been retrieved, it's injected in the original request in the
X-User-Hash custom header,
making it possible to vary the HTTP response on this header:
1 2 3 4 5 6 7 8
FOSHttpCacheBundle's user context feature is activated by default.
Name of the user hash header is configurable in FOSHttpCacheBundle. By default eZ Platform sets it to
Note that sharing ESIs across SiteAccesses is not possible by design (see EZP-22535 for technical details).
Vary by User
Unfortunately this is not optimal as it will by default vary by all cookies, including those set by add trackers, analytics tools, recommendation services, etc. However, as long as your application backend does not need these cookies, you can solve this by stripping everything but the session cookie. Example for Varnish can be found in the default VCL examples in part dealing with User Hash, for single-server setup this can easily be accomplished in Apache or nginx as well.
HTTP cache clearing¶
As eZ Platform uses FOSHttpCacheBundle, this impacts the following features:
- HTTP cache purge
- User context hash
Varnish proxy client from the FOSHttpCache library is used for clearing eZ Platform's HTTP cache, even when using Symfony HTTP cache.
BAN request is sent to registered purge servers, containing an
This header contains all Location IDs for which objects in cache need to be cleared.
User hash generation¶
eZ Platform already interferes with the hash generation process by adding the current User's permissions and Limitations. You can also interfere in this process by implementing custom context provider(s).
X-User-Hash is generated based on the
If you need to find out the anonymous
1. Connect to your server (shh should be enough)
<your-domain.com> to your
3. Execute the following command:
curl -I -H "Accept: application/vnd.fos.user-context-hash" http://<your-domain.com>/_fos_user_context_hash
Remember that you have to send this request to the backend, not to Varnish.
You should get a result like this:
1 2 3 4 5 6 7 8
4. Restart the Varnish server.
Known limitations of the user hash generation¶
If you are using URI-based SiteAccesses matching, the default SiteAccess on the domain needs to point to the same repository, because
/_fos_user_context_hash is not SiteAccess-aware by default (see
ezpublish.default_router.non_siteaccess_aware_routes parameter). Varnish does not have knowledge about SiteAccesses, so it won't be able to get user content hash if the default SiteAccess relies on URI.
Default options for FOSHttpCacheBundle defined in eZ Platform¶
The following configuration is defined in eZ Platform by default for FOSHttpCacheBundle. You may override these settings.
1 2 3 4 5 6 7 8 9 10 11 12 13
HTTP cache tagging¶
ezplatform-http-cache enables HTTP cache tagging.
This allows you to add tags to cached content, which simplifies selective cache invalidation.
Understanding tags is the key to making the most of
- Tags form a secondary set of keys assigned to every cache item, on top of the "primary key" which is the URI
- Like an index in a database, a tag is typically used for anything relevant that represents the given cache item
- Tags are used for cache invalidation
As a practical example, you can tag every article response, and when the article Content Type is updated, you can tell Varnish that all articles should be considered stale and be updated in the background when someone requests them.
content-<content-id>- Used on anything that is affected by changes to Content, that is Content itself, Locations, and so on.
content-type-<content-type-id>- For use when the Content Type changes, affecting Content of its type.
location-<location-id>- Used for clearing all cache relevant for a given Location.
parent-<parent-location-id>- Useful for clearing all children of a parent, or in all siblings.
path-<location-id>- For operations that change the tree itself, like move, remove, etc.
relation-<content-id>- For use when updates affect their all reverse relations. Note that the system does not add this tag to responses itself, just purges if present. Response tagging using this tag is currently meant to be done inline in the template logic / views based on your decision.
Troubleshooting - Content tagged by a big number of tags (too long headers)
In case of complex Content, for instance Landing Pages with many blocks, you might get into trouble with too long response
xkey header. Because of this, necessary cache entries may not be tagged properly. You will also see
502 Headers too long errors.
If this is the case, customize the following runtime settings on your Varnish instance(s):
- http_resp_hdr_len (e.g. 32k)
- http_max_hdr (e.g. 128)
- http_resp_size (e.g. 64k)
- workspace_backend (e.g. 128k)
If you need to see these long headers in the
varnishlog adapt the vsl_reclen setting.
Response tagging process¶
For Content View¶
For Content View there is a dedicated response listener
that triggers a set of Response taggers responsible for translating info from the objects
involved in generating the view to corresponding tags as listed above.
These can be found in
For responses with X-Location-Id¶
For custom or eZ Platform controllers still using
X-Location-Id, a dedicated response listener
XLocationIdResponseSubscriber handles translating this to tags so the cache can be properly invalidated by this bundle.
This is currently marked as deprecated. For rendering content it is advised to refactor to use Content View. For other needs there is an FOS tag handler for Twig and PHP that can be used.
For custom needs with FOSHttpCache (tagging Relations and more)¶
For custom needs, including template logic for eZ Platform's Content Relations which is here used as an example, there are two ways to tag your responses.
In Twig, you can make sure a response is tagged correctly by using the following Twig operator in your template:
1 2 3 4
See Tagging from Twig Templates in FOSHttpCacheBundle doc.
In PHP, FOSHttpCache exposes the
fos_http_cache.handler.tag_handler service which enables you to add tags to a response:
See Tagging from code in FOSHttpCacheBundle doc.
Be aware that the service name and type hint will change once we move to FOSHttpCache 2.x, so in this case
you can alternatively consider adding a tag in Twig template or using
X-Location-Id for the time being.
How purge tagging is done¶
This bundle uses Repository API Slots to listen to Signals emitted on Repository operations, and depending on the operation triggers expiry on a specific tag or set of tags.
For example on Move Location Signal the following tags will be purged:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
All Slots can be found in
Response Taggers take a
ResponseConfigurator and any value object,
and add tags to the Response based on the value.
This adds the
to the Response:
ResponseCacheConfigurator configures an HTTP Response object:
makes the response public, adds tags, sets the shared max age, etc.
It is provided to
ResponseTaggers that use it to add the tags to the Response.
is configured in
view_cache and only enables cache if it is enabled in the configuration.
Delegator and Value Taggers¶
Even though they share the same API, Response Taggers are of two types, reflected by their namespace: Delegator and Value.
Delegator Taggers will extract another value, or several, from the given value, and pass it on to another tagger.
For instance, a
ContentView is covered by both the
ContentValueViewTagger and the
The first will extract the
Content from the
ContentView, and pass it to the
The second will extract the
Location, and pass it to the
While it is more efficient to use a known tagger directly, sometimes you don't know what object you want to tag with.
ResponseTagger will accept any value, and will pass it to every tagger registered with the service tag