diff --git a/cookbook/cache/varnish.rst b/cookbook/cache/varnish.rst index 8be11c7f098..de4ba0f3f8a 100644 --- a/cookbook/cache/varnish.rst +++ b/cookbook/cache/varnish.rst @@ -7,27 +7,102 @@ How to Use Varnish to Speed up my Website Because Symfony's cache uses the standard HTTP cache headers, the :ref:`symfony-gateway-cache` can easily be replaced with any other reverse proxy. `Varnish`_ is a powerful, open-source, HTTP accelerator capable of serving -cached content quickly and including support for :ref:`Edge Side Includes `. +cached content fast and including support for :ref:`Edge Side Includes `. -Trusting Reverse Proxies ------------------------- +.. index:: + single: Varnish; configuration + +Make Symfony Trust the Reverse Proxy +------------------------------------ For ESI to work correctly and for the :ref:`X-FORWARDED ` headers to be used, you need to configure Varnish as a :doc:`trusted proxy `. -.. index:: - single: Varnish; configuration +.. _varnish-x-forwarded-headers: + +Routing and X-FORWARDED Headers +------------------------------- + +To ensure that the Symfony Router generates URLs correctly with Varnish, +a ``X-Forwarded-Port`` header must be present for Symfony to use the +correct port number. + +This port depends on your setup. Lets say that external connections come in +on the default HTTP port 80. For HTTPS connections, there is another proxy +(as Varnish does not do HTTPS itself) on the default HTTPS port 443 that +handles the SSL termination and forwards the requests as HTTP requests to +Varnish with a ``X-Forwarded-Proto`` header. In this case, you need to add +the following configuration snippet: + +.. code-block:: varnish4 + + sub vcl_recv { + if (req.http.X-Forwarded-Proto == "https" ) { + set req.http.X-Forwarded-Port = "443"; + } else { + set req.http.X-Forwarded-Port = "80"; + } + } + +.. note:: + + Remember to configure :ref:`framework.trusted_proxies ` + in the Symfony configuration so that Varnish is seen as a trusted proxy + and the ``X-Forwarded-*`` headers are used. + + Varnish automatically forwards the IP as ``X-Forwarded-For`` and leaves + the ``X-Forwarded-Proto`` header in the request. If you do not configure + Varnish as trusted proxy, Symfony will see all requests as coming through + insecure HTTP connections from the Varnish host instead of the real client. -Configuration -------------- +If the ``X-Forwarded-Port`` header is not set correctly, Symfony will append +the port where the PHP application is running when generating absolute URLs, +e.g. ``http://example.com:8080/my/path``. -As seen previously, Symfony is smart enough to detect whether it talks to a -reverse proxy that understands ESI or not. It works out of the box when you -use the Symfony reverse proxy, but you need a special configuration to make -it work with Varnish. Thankfully, Symfony relies on yet another standard -written by Akamai (`Edge Architecture`_), so the configuration tips in this -chapter can be useful even if you don't use Symfony. +Ensure Consistent Caching Behaviour +----------------------------------- + +Varnish uses the cache headers sent by your application to determine how +to cache content. However, versions prior to Varnish 4 did not respect +``Cache-Control: no-cache``. To ensure consistent behaviour, use the following +configuration if you are still using Varnish 3: + +.. configuration-block:: + + .. code-block:: varnish3 + + sub vcl_fetch { + /* By default, Varnish3 ignores Cache-Control: no-cache and private + https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control + */ + if (beresp.http.Cache-Control ~ "no-cache" || + beresp.http.Cache-Control ~ "private" + ) { + return (hit_for_pass); + } + } + + .. code-block:: varnish2 + + sub vcl_fetch { + // By default, Varnish2 ignores Pragma: nocache and Cache-Control: no-cache and private + if (beresp.http.Cache-Control ~ "no-cache" || + beresp.http.Cache-Control ~ "private" + ) { + return (hit_for_pass); + } + } + +Enable Edge Side Includes (ESI) +------------------------------- + +As explained in the :ref:`Edge Side Includes section`, +Symfony detects whether it talks to a reverse proxy that understands ESI or +not. When you use the Symfony reverse proxy, you don't need to do anything. +But to make Varnish instead of Symfony resolve the ESI tags, you need some +configuration in Varnish. Symfony uses the ``Surrogate-Capability`` header +from the `Edge Architecture`_ described by Akamai. .. note:: @@ -58,22 +133,12 @@ Symfony adds automatically: .. code-block:: varnish4 - /* (https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.html#req-not-available-in-vcl-backend-response) */ sub vcl_backend_response { // Check for ESI acknowledgement and remove Surrogate-Control header if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; set beresp.do_esi = true; } - /* By default Varnish ignores Pragma: nocache - (https://www.varnish-cache.org/docs/4.0/users-guide/increasing-your-hitrate.html#cache-control) - so in order avoid caching it has to be done explicitly */ - if (beresp.http.Pragma ~ "no-cache") { - // https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.html#hit-for-pass-objects-are-created-using-beresp-uncacheable - set beresp.uncacheable = true; - set beresp.ttl = 120s; - return (deliver); - } } .. code-block:: varnish3 @@ -84,14 +149,6 @@ Symfony adds automatically: unset beresp.http.Surrogate-Control; set beresp.do_esi = true; } - /* By default Varnish ignores Cache-Control: nocache - (https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control), - so in order avoid caching it has to be done explicitly */ - if (beresp.http.Pragma ~ "no-cache" || - beresp.http.Cache-Control ~ "no-cache" || - beresp.http.Cache-Control ~ "private") { - return (hit_for_pass); - } } .. code-block:: varnish2 @@ -102,13 +159,6 @@ Symfony adds automatically: unset beresp.http.Surrogate-Control; esi; } - /* By default Varnish ignores Cache-Control: nocache - so in order avoid caching it has to be done explicitly */ - if (beresp.http.Pragma ~ "no-cache" || - beresp.http.Cache-Control ~ "no-cache" || - beresp.http.Cache-Control ~ "private") { - return (hit_for_pass); - } } .. caution:: @@ -117,6 +167,12 @@ Symfony adds automatically: (read `GZIP and Varnish`_). If you're not using Varnish 3.0, put a web server in front of Varnish to perform the compression. +.. tip:: + + If you followed the advice about ensuring a consistent caching + behaviour, those vcl functions already exist. Just append the code + to the end of the function, they won't interfere with each other. + .. index:: single: Varnish; Invalidation @@ -134,139 +190,8 @@ proxy before it has expired, it adds complexity to your caching setup. invalidation by helping you to organize your caching and invalidation setup. -Varnish can be configured to accept a special HTTP ``PURGE`` method -that will invalidate the cache for a given resource: - -.. code-block:: varnish4 - - /* - Connect to the backend server - on the local machine on port 8080 - */ - backend default { - .host = "127.0.0.1"; - .port = "8080"; - } - - sub vcl_recv { - /* - Varnish default behavior doesn't support PURGE. - Match the PURGE request and immediately do a cache lookup, - otherwise Varnish will directly pipe the request to the backend - and bypass the cache - */ - if (req.request == "PURGE") { - return(lookup); - } - } - - sub vcl_hit { - // Match PURGE request - if (req.request == "PURGE") { - // Force object expiration for Varnish < 3.0 - set obj.ttl = 0s; - // Do an actual purge for Varnish >= 3.0 - // purge; - error 200 "Purged"; - } - } - - sub vcl_miss { - /* - Match the PURGE request and - indicate the request wasn't stored in cache. - */ - if (req.request == "PURGE") { - error 404 "Not purged"; - } - } - -.. caution:: - - You must protect the ``PURGE`` HTTP method somehow to avoid random people - purging your cached data. You can do this by setting up an access list: - - .. code-block:: varnish4 - - /* - Connect to the backend server - on the local machine on port 8080 - */ - backend default { - .host = "127.0.0.1"; - .port = "8080"; - } - - // ACL's can contain IP's, subnets and hostnames - acl purge { - "localhost"; - "192.168.55.0"/24; - } - - sub vcl_recv { - // Match PURGE request to avoid cache bypassing - if (req.request == "PURGE") { - // Match client IP to the ACL - if (!client.ip ~ purge) { - // Deny access - error 405 "Not allowed."; - } - // Perform a cache lookup - return(lookup); - } - } - - sub vcl_hit { - // Match PURGE request - if (req.request == "PURGE") { - // Force object expiration for Varnish < 3.0 - set obj.ttl = 0s; - // Do an actual purge for Varnish >= 3.0 - // purge; - error 200 "Purged"; - } - } - - sub vcl_miss { - // Match PURGE request - if (req.request == "PURGE") { - // Indicate that the object isn't stored in cache - error 404 "Not purged"; - } - } - -.. _varnish-x-forwarded-headers: - -Routing and X-FORWARDED Headers -------------------------------- - -To ensure that the Symfony Router generates URLs correctly with Varnish, -proper ```X-Forwarded``` headers must be added so that Symfony is aware of -the original port number of the request. Exactly how this is done depends -on your setup. As a simple example, Varnish and your web server are on the -same machine and that Varnish is listening on one port (e.g. 80) and Apache -on another (e.g. 8080). In this situation, Varnish should add the ``X-Forwarded-Port`` -header so that the Symfony application knows that the original port number -is 80 and not 8080. - -If this header weren't set properly, Symfony may append ``8080`` when generating -absolute URLs: - -.. code-block:: varnish4 - - sub vcl_recv { - if (req.http.X-Forwarded-Proto == "https" ) { - set req.http.X-Forwarded-Port = "443"; - } else { - set req.http.X-Forwarded-Port = "80"; - } - } - -.. note:: - - Remember to configure :ref:`framework.trusted_proxies ` - in the Symfony configuration so that Varnish is seen as a trusted proxy - and the ``X-Forwarded-`` headers are used. + The documentation of the `FOSHttpCacheBundle`_ explains how to configure + Varnish and other reverse proxies for cache invalidation. .. _`Varnish`: https://www.varnish-cache.org .. _`Edge Architecture`: http://www.w3.org/TR/edge-arch