Speeding Up Apache And Drupal With Varnish

8th June 2014

Varnish is a web application accelerator that provides an easy speed increase to most web applications and Drupal is no exception. It works by creating a reverse proxy service that sits in front of your web server and caches traffic that comes through it. When the page is requested, Varnish forwards the request to the web server to complete the request, the response that comes back from the web server is then cached by Varnish. This means that the next request to the same page is served by Varnish and not the web server, which results in a large speed increase.

The upshot of using Varnish with an application like Drupal is that when a request is made there is no hit to the web server (and thus PHP) and no hit to the database. Varnish works best with Drupal with anonymous traffic, as authenticated traffic requires cookies and custom HTML. Even so, you can see massive speed increases for any anonymous traffic on the site.

Varnish can be configured to run as a stand alone machine in front of a bunch of Apache nodes or as a front end to a single Apache server.

There are a few steps to getting Varnish up and running with Drupal on Apache, which starts with installing Apache.

Install And Configure Apache

To install Apache on Ubuntu use the following apt-get command.

sudo apt-get install apache2 apache2-mpm-prefork apache2-utils

Once installed you need to change the port that Apache listens to. This is because Varnish will be configured to listen on port 80 and act as a proxy to an internal port that you designate. The usual approach here is to use port 8080 as this is normal alternative HTTP port and so won't clash with anything else.

To change the port that Apache listens to just open up the file /etc/apache2/ports.conf and change the 'Listen' directive to 8080.

Listen 8080

It's probably a good idea to prevent access to port 8080 from the outside world. Although this isn't a large security breach it is bad practice to allow your users to bypass your Varnish server. This can be done via an Apache configuration option or via firewall rules.

Once done just restart Apache for the change to be picked up. This command will do this on most Linux boxes.

sudo service apache2 restart

With Apache up and running it is now time to install and configure Varnish.

Install And Configure Varnish

To install Varnish on Ubuntu just run the following apt-get command.

sudo apt-get install varnish

Once installed you will find the following three files that are important to the running of Varnish.

  • /etc/default/varnish - This is a shell script fragment that is used by /etc/init.d/varnish to run Varnish with various options.
  • /etc/varnish/default.vcl - This is a file that is used to control how Varnish acts with different requests. This is for things like how Varnish treats cookies and what paths should be excluded from being cached. The location of this file is set in the /etc/default/varnish file.
  • /etc/varnish/secret - This is a file that is used as a way of securely allowing administrative access to the Varnish cache. Again, the location of this file is set in the /etc/default/varnish file.

The /etc/varnish/default file just needs to create the variables DAEMON_OPTS, NFILES and MEMLOCK, which are picked up by the /etc/init.d/varnish script. The /etc/varnish/default file is essentially a wrapper around running Varnish on the command line using the varnishd command.

The DAEOMON_OPTS variable controls the various aspects of how Varnish works including what port Varnish should listen on and so is the most important part of this file to understand. Any options added to this variable are passed directly to the varnishd service. The following options can be included in the DAEMON_OPTS variable to control how Varnish runs.

  • -a - The port that Varnish should listen to for incoming traffic.
  • -T - The location and port of the administration interface.
  • -f - The location of the Varnish configuration file, normally stored at /etc/varnish/default.vcl.
  • -S - The location of the Varnish secret file, normally stored at /etc/varnish/secret.
  • -s - This sets the options for the location and size of the Varnish cache.
  • -w - Configure the minimum, maximum and timeout length of the thread pool.
  • -p - Set one of a number tuneable parameters. This can be used multiple times to set multiple parameters.

For more information on the available command line parameters see the official documentation on the varnishd command.

The following is a simple example of the /etc/default/varnish file that sets up some default values. This is normally used as a basic setup of Varnish on a machine that has limited resources.

  1. # Should we start varnishd at boot? Set to "no" to disable.
  2. START=yes
  3.  
  4. # Maximum number of open files (for ulimit -n)
  5. NFILES=131072
  6.  
  7. # Maximum locked memory size (for ulimit -l)
  8. # Used for locking the shared memory log in memory. If you increase log size,
  9. # you need to increase this number as well
  10. MEMLOCK=82000
  11.  
  12. # Default varnish instance name is the local nodename. Can be overridden with
  13. # the -n switch, to have more instances on a single server.
  14. INSTANCE=$(uname -n)
  15.  
  16. DAEMON_OPTS="-a :80 \
  17. -T localhost:6082 \
  18. -f /etc/varnish/default.vcl \
  19. -S /etc/varnish/secret \
  20. -s malloc,256m"

This sets up Varnish to have the following options:

  • Line 2 - Sets the START variable to 'yes' to make Varnish start when the server reboots.
  • Line 5 - Sets the NFILES variable to be 131072. This controls how many files Varnish can have open at once. The command ulimit -n ${NFILES:-131072} is run in the init.d file when Varnish is started.
  • Line 10 - Sets the MEMLOCK variable to be 82000. This controls how the users soft limit for the maximum size that may be locked into memory. The command ulimit -l ${MEMLOCK:-82000} is ran in the init.d file when Varnish is started.
  • Line 14 - Sets the INSTANCE variable to be the output of 'uname -n'. This is used when Varnish is configured to be part of a node cluster, which we won't be using in this case.
  • Line 16 - Sets the DAEMON_OPTS variable to have the following options:
    • Set the port number to 80 from anywhere with the -a flag.
    • Set the administration port to be 6082 on the local machine with the -T flag.
    • Set the Varnish configuration file to be /etc/varnish/default.vcl with the -f flag.
    • Set the secret file location to be /etc/varnish/secret with the -S flag.
    • Set Varnish to store the cache in memory and make that memory 256m with the -s flag.

The following is a different setup of Varnish that tweaks some of the other available parameters. This setup is designed for a host with more resources.

  1. # Should we start varnishd at boot? Set to "no" to disable.
  2. START=yes
  3.  
  4. # Maximum number of open files (for ulimit -n)
  5. NFILES=131072
  6.  
  7. # Maximum locked memory size (for ulimit -l)
  8. # Used for locking the shared memory log in memory. If you increase log size,
  9. # you need to increase this number as well
  10. MEMLOCK=82000
  11.  
  12. # Default varnish instance name is the local nodename. Can be overridden with
  13. # the -n switch, to have more instances on a single server.
  14. INSTANCE=$(uname -n)
  15.  
  16. # The minimum number of worker threads to start
  17. VARNISH_MIN_THREADS=400
  18.  
  19. # The Maximum number of worker threads to start
  20. VARNISH_MAX_THREADS=4000
  21.  
  22. # Idle timeout for worker threads
  23. VARNISH_THREAD_TIMEOUT=120
  24.  
  25. DAEMON_OPTS="-a :80 \
  26. -T localhost:6082 \
  27. -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
  28. -p thread_pool_add_delay=2 \
  29. -p thread_pools=2 \
  30. -p session_linger=50 \
  31. -p sess_workspace=262144 \
  32. -f /etc/varnish/default.vcl \
  33. -S /etc/varnish/secret \
  34. -s malloc, 1024m"

Going line by line the following options are being set.

  • Line 2 - Sets the START variable to 'yes' to make Varnish start when the server reboots.
  • Line 5 - Sets the NFILES variable to be 131072. This controls how many files Varnish can have open at once. The command ulimit -n ${NFILES:-131072} is run in the init.d file when Varnish is started.
  • Line 10 - Sets the MEMLOCK variable to be 82000. This controls how the users soft limit for the maximum size that may be locked into memory. The command ulimit -l ${MEMLOCK:-82000} is ran in the init.d file when Varnish is started.
  • Line 14 - Sets the INSTANCE variable to be the output of 'uname -n'. This is used when Varnish is configured to be part of a node cluster, which we won't be using in this case.
  • Line 17 - Sets a variable called VARNISH_MIN_THREADS that stores the minimum number of worker threads that Varnish will start.
  • Line 20 - Sets a variable called VARNISH_MAX_THREADS that stores the maximum number of worker threads that Varnish will start.
  • Line 23 - Sets a variable called VARNISH_THREAD_TIMEOUT that stores the idle timeout for worker threads.
  • Line 25 - Sets the DAEMON_OPTS variable to have the following options:
    • Set the port number to 80 from anywhere with the -a flag.
    • Set the administration port to be 6082 on the local machine with the -T flag.
    • Configures the maximum and minimum number of worker threads that Varnish will start with the -w flag.
    • Sets a number of extra options using the -p flag. This includes setting the number of thread pools to 2 and slightly decreasing the amount of time that should elapse before a session is revoked.
    • Set the Varnish configuration file to be /etc/varnish/default.vcl with the -f flag.
    • Set the secret file location to be /etc/varnish/secret with the -S flag.
    • Set Varnish to store the cache in memory and make that memory 256m with the -s flag.

Next, we need to edit the default.vcl file to tell Varnish how to treat both incoming and outgoing requests. The default.vcl file uses a language called Varnish Configuration Language which Varnish converts into binary code that is executed when requests arrive. This is perhaps the most complex part of a Varnish setup, especially when taking Drupal into consideration as we need to do things like exclude certain pages and inspect cookies. This file contains a number of setup groups and sub routines. Any sub routines that you define here will override the default implementations that Varnish has for them.

The first thing we configure in this file is the backend integration. When we setup Apache in the previous step we made Apache listen on port 8080 for incoming requests so it is this port that we tell Varnish to use when asking for page caches. The following will configure and initialise a default backend listener on the local machine.

  1. backend default {
  2. .host = "127.0.0.1";
  3. .port = "8080";
  4. }

One thing that you should be careful of with Drupal is long page load times, especially when rebuilding the cache or doing other complex things. For this reason it is best to include some additional parameters to increase the time that Varnish will wait for a response from the web server. Without these timeout parameters in place you might see random Varnish errors appearing when Drupal takes too long to respond. Here is the modified default backend listener.

  1. backend default {
  2. .host = "127.0.0.1";
  3. .port = "8080";
  4. .connect_timeout = 2s;
  5. .first_byte_timeout = 30s;
  6. .between_bytes_timeout = 10s;
  7. }

The vcl_recv sub routine contains the main bulk of the Varnish configuration logic. This is the first subroutine to be fired when Varnish is sent a request. This controls how Varnish deals with cookies and which URL's should be included or excluded from the cache mechanisms. This is quite a long sub routine, but it is well documented, and essentially defines the following actions.

  • What to do in the event of a backend failure.
  • Set up forwarding of the IP address of the user to the server in a proxy header.
  • What URLs to skip when storing cache objects.
  • Optionally prevent access to certain restricted pages.
  • Set up compression handling for the request.
  • Don't cache downloadable files like PDF or Word Documents.
  • Remove cookies that Drupal doesn't need to know about.
  1. sub vcl_recv {
  2. # Use anonymous, cached pages if all backends are down.
  3. if (!req.backend.healthy) {
  4. unset req.http.Cookie;
  5. }
  6.  
  7. # Allow the backend to serve up stale content if it is responding slowly.
  8. set req.grace = 6h;
  9.  
  10. # Pipe these paths directly to Apache for streaming.
  11. if (req.url ~ "^/admin/content/backup_migrate/export") {
  12. return (pipe);
  13. }
  14.  
  15. # Set up the X-Forwarded-for header with the client IP address.
  16. if (req.restarts == 0) {
  17. if (req.http.x-forwarded-for) {
  18. set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
  19. }
  20. else {
  21. set req.http.X-Forwarded-For = client.ip;
  22. }
  23. }
  24.  
  25. # Do not cache these paths.
  26. if (req.url ~ "^/status\.php$" ||
  27. req.url ~ "^/update\.php" ||
  28. req.url ~ "^/install\.php" ||
  29. req.url ~ "^/batch/.*$" ||
  30. req.url ~ "^/admin" ||
  31. req.url ~ "^/admin/.*$" ||
  32. req.url ~ "^/user" ||
  33. req.url ~ "^/user/.*$" ||
  34. req.url ~ "^/users/.*$" ||
  35. req.url ~ "^/info/.*$" ||
  36. req.url ~ "^/flag/.*$" ||
  37. req.url ~ "^.*/ajax/.*$" ||
  38. req.url ~ "^.*/ahah/.*$") {
  39. return (pass);
  40. }
  41.  
  42. # Do not allow outside access to cron.php or install.php.
  43. #if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ internal) {
  44. # Have Varnish throw the error directly.
  45. # error 404 "Page not found.";
  46. # Use a custom error page that you've defined in Drupal at the path "404".
  47. # set req.url = "/404";
  48. #}
  49.  
  50. # Handle compression correctly. Different browsers send different
  51. # "Accept-Encoding" headers, even though they mostly all support the same
  52. # compression mechanisms. By consolidating these compression headers into
  53. # a consistent format, we can reduce the size of the cache and get more hits.=
  54. # @see: http:// varnish.projects.linpro.no/wiki/FAQ/Compression
  55. if (req.http.Accept-Encoding) {
  56. if (req.http.Accept-Encoding ~ "gzip") {
  57. # If the browser supports it, we'll use gzip.
  58. set req.http.Accept-Encoding = "gzip";
  59. }
  60. else if (req.http.Accept-Encoding ~ "deflate") {
  61. # Next, try deflate if it is supported.
  62. set req.http.Accept-Encoding = "deflate";
  63. }
  64. else {
  65. # Unknown algorithm. Remove it and send unencoded.
  66. unset req.http.Accept-Encoding;
  67. }
  68. }
  69.  
  70. # Always cache the following file types for all users. This list of extensions
  71. # appears twice, once here and again in vcl_fetch so make sure you edit both
  72. # and keep them equal.
  73. if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
  74. unset req.http.Cookie;
  75. }
  76.  
  77. # Remove all cookies that Drupal doesn't need to know about. We explicitly
  78. # list the ones that Drupal does need, the SESS and NO_CACHE. If, after
  79. # running this code we find that either of these two cookies remains, we
  80. # will pass as the page cannot be cached.
  81. if (req.http.Cookie) {
  82. # 1. Append a semi-colon to the front of the cookie string.
  83. # 2. Remove all spaces that appear after semi-colons.
  84. # 3. Match the cookies we want to keep, adding the space we removed
  85. # previously back. (\1) is first matching group in the regsuball.
  86. # 4. Remove all other cookies, identifying them by the fact that they have
  87. # no space after the preceding semi-colon.
  88. # 5. Remove all spaces and semi-colons from the beginning and end of the
  89. # cookie string.
  90. set req.http.Cookie = ";" + req.http.Cookie;
  91. set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
  92. set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
  93. set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
  94. set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
  95.  
  96. if (req.http.Cookie == "") {
  97. # If there are no remaining cookies, remove the cookie header. If there
  98. # aren't any cookie headers, Varnish's default behavior will be to cache
  99. # the page.
  100. unset req.http.Cookie;
  101. }
  102. else {
  103. # If there is any cookies left (a session or NO_CACHE cookie), do not
  104. # cache the page. Pass it on to Apache directly.
  105. return (pass);
  106. }
  107. }
  108. }

The vcl_deliver sub routine is used to tweak the response to the client before being issued by Varnish. The most common use for this sub routine is to control what HTTP headers will be present in the response. The following is a typical example of the vcl_deliver sub routine.

  1. sub vcl_deliver {
  2. # Remove some security specific common headers.
  3. remove resp.http.Via;
  4. remove resp.http.X-Whatever;
  5. remove resp.http.X-Powered-By;
  6. remove resp.http.X-Generator;
  7. remove resp.http.X-Varnish;
  8. remove resp.http.X-Drupal-Cache;
  9. remove resp.http.Server;
  10.  
  11. if (obj.hits > 0) {
  12. set resp.http.X-Varnish-Cache = "HIT";
  13. }
  14. else {
  15. set resp.http.X-Varnish-Cache = "MISS";
  16. }
  17. }

The first part of this removes some of the typical HTTP headers that reveal quite a bit about the server and architecture. This is generally considered a bad thing (mainly as it makes targeted attacks much easier) and so they should be removed. These are headers like Server, which shows what web server is being used (usually generated by Apache) and X-Generator, which is generated by Drupal.

The second part of this sub routine involves setting a 'HIT' or a 'MISS' to show if Varnish returned a cached page or not. This is useful in making sure things are working correctly or diagnosing any problems with the Varnish cache control.

The vcl_fetch sub routine controls how Varnish treats documents that have successfully been retrieved from the backend. The beresp variable is available here and can be used to tweak the cache settings before the retrieved document is returned.

The bottom of the sub routine adds support for ban lurker. This is a Varnish process that runs through the cache and bans various cache objects. A ban is a quick way of invalidating the cache without having to remove the object from the cache itself. When the object is next fetched from the cache it is evaluated to see if it has been banned. If it has then the new version of the page is requested, stored, and served.

  1. sub vcl_fetch {
  2. # We need this to cache 404s, 301s, 500s. Otherwise, depending on backend but
  3. # definitely in Drupal's case these responses are not cacheable by default.
  4. if (beresp.status == 404 || beresp.status == 301 || beresp.status == 500) {
  5. set beresp.ttl = 10m;
  6. }
  7.  
  8. # Don't allow static files to set cookies.
  9. # (?i) denotes case insensitive in PCRE (perl compatible regular expressions).
  10. # This list of extensions appears twice, once here and again in vcl_recv so
  11. # make sure you edit both and keep them equal.
  12. if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
  13. unset beresp.http.Set-Cookie;
  14. }
  15.  
  16. # Allow items to be stale if needed.
  17. set beresp.grace = 6h;
  18.  
  19. # Allow for Ban Lurker support.
  20. set beresp.http.x-url = req.url;
  21. set beresp.http.x-host = req.http.host;
  22. }

In the event of a complete failure the vcl_error sub routine is called. This is used to return a HTML error page to the user, telling them that there has been a problem with the page they tried to reach, which then redirects the user to the home page. Without this in place Varnish will issue a default 'guru meditation' page.

The first part of vcl_error is an optional section that can be uncommented to allow redirection to another domain in case of the failure of the backend server. This can be useful to enable if you want to show the user a nice error page instead of the Varnish issued version, but the site will need to be configured separately. Enabling this also prevents the site redirecting to itself continuously when the underlying site has a problem.

  1. sub vcl_error {
  2. # Redirect to some other URL in the case of a homepage failure.
  3. #if (req.url ~ "^/?$") {
  4. # set obj.status = 302;
  5. # set obj.http.Location = "http://backup.example.com/";
  6. #}
  7.  
  8. # Otherwise redirect to the homepage, which will likely be in the cache.
  9. set obj.http.Content-Type = "text/html; charset=utf-8";
  10. synthetic {"
  11.  
  12.  
  13. <title>Page Unavailable</title><style>
  14. <!--/*--><![CDATA[/* ><!--*/
  15.  
  16. body { background: #303030; text-align: center; color: white; }
  17. #page { border: 1px solid #CCC; width: 500px; margin: 100px auto 0; padding: 30px; background: #323232; }
  18. a, a:link, a:visited { color: #CCC; }
  19. .error { color: #222; }
  20.  
  21. /*--><!]]>*/
  22. </style><div id="page">
  23. <h1 class="title">Page Unavailable</h1>
  24. <p>The page you requested is temporarily unavailable.</p>
  25. <p>We're redirecting you to the <a href="/">homepage</a> in 5 seconds.</p>
  26. <div class="error">(Error "} + obj.status + " " + obj.response + {")</div>
  27. </div>
  28.  
  29.  
  30. "};
  31. return (deliver);
  32. }

The default.vcl that the above samples create is largely taken from work done by FourKitchens and Lullabot to generate a Drupal specific Varnish configuration file. This has been tweaked a little and has been in use in a few production environments for a few months without any problems.

Rather than paste the entire file here I have created a Git repo and placed the default.vcl file there. Feel free to download it and use on your own projects.

For more information about the VCL file take a look at the VCL documentation on the Varnish site.

When setting up the Varnish runtime you can use the -S flag to stipulate the location of a secret file. In the examples above we set this to be at the location /etc/varnish/secret. This is a file that is used as a way of securely allowing administrative access to the Varnish cache. It isn't a required part of setting up Varnish but it helps to lock the system down and so it's a good idea to include it. When a system tries to access the Varnish administration interface it is asked to authenticate. The authentication is sending the contents of the secret file, which Varnish then compares to the actual contents before allowing the connection in.

The contents of a typical Varnish secret file are as follows, but this is generated by Varnish on install.

04788b22-e179-4579-aac7-f3541fb40391

When you have added your own VCL file and set up your Varnish runtime then you need to restart the service in order for these changes to be picked up. This is done with the service command.

sudo service varnish restart

Note that on some Linux systems this might be varnishd.

When you visit your site you should load as it would a normal page request. To see if Varnish has been a part of the request process you need to look at the headers returned from the service. If you see a X-Varnish-Cache header then Varnish is running. It will either have the value of HIT or MISS.

As a quick aside, to inspect the headers being returned from a web request use the curl command with the -I flag.

  1. $ curl -I http://www.varnish.com/
  2. HTTP/1.1 200 OK
  3. Server: Apache/2.2.27 (Unix)
  4. Etag: "1402232119-0"
  5. Cache-Control: public, max-age=0
  6. Last-Modified: Sun, 08 Jun 2014 12:55:19 +0000
  7. Expires: Sun, 11 Mar 1984 12:00:00 GMT
  8. Content-Type: text/html; charset=utf-8
  9. Accept-Ranges: bytes
  10. Date: Sun, 08 Jun 2014 13:09:33 GMT
  11. Age: 0
  12. Vary: Cookie,Accept-Encoding
  13. X-Varnish-Cache: MISS

Configure Drupal

With all this now in place you still need to configure Drupal to communicate with Varnish. If you don't do this then Varnish will assume that every page will miss the cache and so your Varnish cache won't really be running as a cache at all.

To get Drupal to communicate with Varnish you need to install the Varnish HTTP Accelerator Integration module. Once the module is enabled you need to go to the configuration page at /admin/config/development/varnish and set up the Varnish options.

    Flush page cache on cron? - I normally set this to 'Disabled' so that Varnish is in charge of the cache. When this is enabled you find that cron runs can frequently empty out the entire Drupal cache, rather than it being done on a page by page basis.
  • Varnish version - This tutorial is about installing and configuring Varnish 3. As of now Varnish 4 has been released, but the Drupal module doesn't support this version yet.
  • Varnish Control Terminal - This is the location of the Varnish administration interface. This was set when we edited the /etc/default/varnish file and used the -T flag to tell Varnish on which port to setup the interface. As the /etc/default/varnish file sets this to localhost:6082 (which is the default value) you can set the value in Drupal to the same.
  • Varnish Control Key - This is the value contained within the Varnish secret file.
  • Varnish connection timeout (milliseconds) - Setting this to '100' is fine for a locally installed Varnish server. If you have an external Varnish cache then you might want set this value to be slightly higher.
  • Varnish Cache Clearing - This controls what kind of cache clearing should be enabled. The default here is to use Drupal's default cache mechanisms, but you can also install the Expire module to select a different cache clearing system. Setting this to None will allow pages to persist for the full max-age setting.
  • Varnish ban type - This selects the type of Varnish ban that is to be used to invalidate objects in the cache. This can be set to Normal or Ban Lurker, which we created support for in our Varnish VCL file.
  • Status - If everything has been set up correctly then you should have a notice at the bottom of the page saying 'Varnish running'.

With the module enabled and configured you still need to tell Drupal to treat Varnish as a cache backend. This is done by setting a couple of values in your settings.php file.

  1. // Add Varnish as the page cache handler.
  2. $conf['cache_backends'] = array('sites/all/modules/contrib/varnish/varnish.cache.inc');
  3. // Drupal 7 does not cache pages when we invoke hooks during bootstrap. This needs
  4. // to be disabled.
  5. $conf['page_cache_invoke_hooks'] = FALSE;

If you are using the Expire module then you also need to include the following config option. This sets up a new cache bin for Varnish that can be cleared if needed.

$conf['cache_class_external_varnish_page'] = 'VarnishCache';

If you aren't using the Expire module then you need to include the following option. This replaces the default page cache with Varnish.

$conf['cache_class_cache_page'] = 'VarnishCache';

You might notice that your pages are still not being cached, and there are two reasons for this. The first thing to realise about Drupal and Varnish is that authenticated traffic bypasses the Varnish cache, so if you are logged in then you won't be able to 'hit' the cached versions of pages. If anonymous users are still not seeing the cached versions of pages then you need to enable caching for anonymous users. Go to the performance page in Drupal (located at /admin/config/development/performance) and turn on the option 'Cache pages for anonymous users'. You should now start seeing Varnish cached pages being issued.

Double check things are working by looking at the headers being returned. If the X-Varnish-Cache header says 'HIT' then the Varnish cache was used. You should also see a big speed improvement after the caches have warmed up.

You can also double check that your Varnish/Drupal integration is working correctly by looking at the site Is Varnish Working. This looks to see if the correct headers were generated by your setup and will give you hints on what to look for and change if they weren't.

Apache RPAF Module

One thing you might notice is that although everything here works as a cache system you won't be able to see the IP addresses of your visitors. All of the Apache logs and any IP addresses found within PHP via the $_SERVER['REMOTE_ADDR'] variable will appear to be from 127.0.0.1. This is because the request is coming from the Varnish server and not the end user. The IP address of the user is added to the request headers sent by Varnish and will be in the X-Forwarded-For header. This is a non-standard header and so the user’s IP address is missing from just about everything.

There are many solutions to this, but I have found that the most stable is to use an Apache module called Reverse Proxy Add Forward (also known as RPAF). To install this use the following apt-get command.

sudo apt-get install libapache2-mod-rpaf

If the module isn't already enabled you can enable it with the following command.

sudo a2enmod rpaf

All that is left to do is to edit the RPAF configuration file at /etc/apache2/mods-enabled/rpaf.conf. This file contains a few different options, but essentially all you need to have is the following:

  1. RPAFenable On
  2. RPAFsethostname On
  3. RPAFproxy_ips 127.0.0.1 192.168. 10.0.0.
  4. RPAFheader X-Forwarded-For
The configuration options set here are as follows:
OptionValueNotes
RPAFenableOnShould this module be enabled? To turn off just set this value to 'Off'.
RPAFproxy_ips127.0.0.1 192.168. 10.0.0. - What IP addresses to adjust requests for.
RPAFheaderX-Forwarded-For - The header to use for the real IP address.

There are one or two other options available here, but I have found that they aren't fully supported on all platforms. Don’t try and solve this IP address problem by getting Varnish to pass the user’s IP address as the request IP address as you won’t be able to lock down the Apache port listener to just local traffic.

With this config file in place you need to restart Apache for the change to be loaded. You should instantly see a difference in your Apache access logs and within the Drupal watchdog logs.

If you are using Centos then most of the previous steps will be pretty much the same. (aside from some of the default the file locations). The install of RPAF is slightly different and requires grabbing the precompiled version from github and installing using Yum. The following command will do this.

sudo yum localinstall http://y-ken.github.com/package/centos/6/x86_64/mod_rpaf-fork-0.6-5.el6.x86_64.rpm

Finally, Varnish is a really good way of speeding up a Drupal site, but it isn't a plug and play solution for every situation. You should read through the VCL file and understand everything that it is doing, and any implications that this might have on your site. It’s important to realise that if you run a login only site or an ecommerce site then Varnish will probably only work for a small percentage of your users. It is possible to allow Varnish to work with authenticated traffic but you’ll need to look into something called Edge Side Includes (EDI) so that you can poke holes into your Varnish cache layer to display customised user content.

Comments

Permalink
Hey :) Thanks for the info! I'm getting a VCC-compiler error: Symbol not foun: 'req.backend.healthy' (Exepected type BOOL); Trying to find the answer. Did you ever experienced that?

Mark (Fri, 04/29/2016 - 15:29)

Add new comment

The content of this field is kept private and will not be shown publicly.