I've been working on a couple of submodules adding support for Varnish including ESI. Currently form-tokens, form-build-ids (necessary for ajax forms), tabs and local actions, and polls can be delivered either via Ajax or ESI. I'm planning some more features but it would be great if I first could get some more feedback on the current implementation.

The relevant modules are:

Authcache Personalization API
Common code for ESI as well as AJax. Includes a custom front controller, therefore it is not necessary anymore to include authcache_ajax.inc as a cache_backend
Authcache ESI
Support personalization via ESI requests
Authcache Varnish
Varnish support including required VCL code

Also look at the Authcache Poll module to get a feel how the API is working.

Comments

socialnicheguru’s picture

does authcache esi work with the drupal.org/project/esi module?
does authcache varnish work with the varnish module?

znerol’s picture

does authcache esi work with the drupal.org/project/esi module?

I do not know.

does authcache varnish work with the varnish module?

Yes. The varnish module actually should be installed in order to place bans after content was altered on the site.

socialnicheguru’s picture

Category: task » bug

do I need to set a backend when I use authcache_esi ?
Do I use it instead of authcache_ajax?

znerol’s picture

Category: bug » task

do I need to set a backend when I use authcache_esi ?

If you just want to look at the page source in order to see whether the proper ESI-tags were set, you do not need to switch the cache backend. However if you want to do anything useful with ESI you need to connect through an ESI-enabled reverse proxy server (varnish) to your site. When you do that, you need to make sure that your drupal site is configured correctly for operating behind a reverse proxy server. Look for the respective section in your settings.php. Also you should enable authcache_varnish and follow the installation instructions contained in the README.txt of the module.

Also if you run everything on your local machine, make sure that you do not use the same ip address for connecting to varnish like you use for the connection between varnish and the web server. An easy way to solve this problem is to setup an IP alias on some interface and use that to connect to varnish.

Do I use it instead of authcache_ajax?

The modules authcache_ajax and authcache_esi provide two different personalization methods. Common code for personalization resides in authcache_p13n. Both modules (Ajax and ESI) can coexist. However at the moment ESI is preferred over Ajax. This means that when authcache_esi is present, form-tokens (and all the stuff I mentioned in the issue description) are injected using ESI-tags instead of Ajax-calls.

socialnicheguru’s picture

so authcache_esi and authcache_varnish or authcache_ajax

znerol’s picture

so authcache_esi and authcache_varnish or authcache_ajax

You can use all three together. For some modules authcache_ajax is still a requirement, even if you enable authcache_esi. For example authcache_forum only provides personalization via ajax but not via ESI.

znerol’s picture

For example authcache_forum only provides personalization via ajax but not via ESI.

This is not the case anymore with the latest 2.x-dev. Personalization now works independently from the method used for markup substitution.

vinmassaro’s picture

@znerol: thank you for adding Varnish support to Authcache. I'm having some trouble following the setup for it though. It's not clear when/how to use portions of the included VCL examples and what to incorporate into my already existing Varnish VCL. If you could provide more detailed setup instructions, it would be very helpful. FWIW, this is our current VCL. Thanks!

znerol’s picture

@vinmassaro: Authcache requires its own VCL. Please take a look at modules/authcache_varnish/vcl.

vinmassaro’s picture

@znerol: yes, I see a number of different VCL files and it's unclear what order to add these, etc. More detailed instructions would be great and I could even write a patch to explain this better for others. We have an existing VCL as I mentioned that is used for many sites (vhosts) right now, and have to add Authcache Varnish for a single site on that host. Can you explain how to best incorporate these files into my existing VCL above, or are you saying to combine them and load them conditionally for just this site? Thanks.

znerol’s picture

Add them in alphabetic order (the leading numbers are on purpose). XX_authcache-debug.vcl is optional.

The basics are explained in a blog-post by Josh Waihi, especially the trick for fetching and caching the authcache key:
http://joshwaihi.com/content/authenticated-page-caching-varnish-drupal

My version is designed such that it does not require returns especially from within vcl_recv. This is important for vcl_recv because the X-Forwarded-For header is added from within the default.vcl. However the default vcl_recv passes all requests to the backend when cookies are present, therefore I implemented a workaround: Cookies are backed up into req.http.X-Cookie-Backup from within vcl_recv and restored from within vcl_hash.

ESI processing is turned on selectively, i.e. the backend (Drupal+authcache) is indicating via a response header whether there are ESI tags in a response. Similarly, authcache only adds ESI tags when an appropriate request header is set. Otherwise it will fallback to Ajax-tags (if available).

I propose that you start with the authcache VCL and then add the bits from your own version step by step.

vinmassaro’s picture

@znerol: Ok, I first tried adding the Authcache logic to my existing VCL and then decided to just start with the Authcache Varnish VCL bits to see how it behaved. Here is the VCL I have loaded, and it's a compilation of the VCL files included with the module, except for the ESI bits: https://gist.github.com/vinmassaro/e01d902aa08d62f36c17

I am using the latest Authcache 7.x-2.x. I have enabled these modules:

  • Authcache
  • Authcache Debug
  • Authcache Varnish
  • Authcache Personalization API
  • Authcache Form
  • Authcache Menu
  • Authcache Search

I added a cache hit/miss header from my original VCL so I could see if Varnish is returning from cache. When logging in with a role set up with Authcache, it does seem to cache and return from Varnish correctly (based on the X-Varnish-Cache and X-Varnish-Hits headers I set), but the Authcache Debug block always displays Cache Status: "Miss", with no reason listed. I'm getting an X-Varnish-Cache: HIT header and X-Varnish-Cache-Hits value greater than 1, so I know the page is being returned from Varnish. Until I added these headers to display, I didn't think it was working based on the output from the Authcache Debug block. Do you see any misconfiguration or could this be a bug in Authcache Debug?

znerol’s picture

Authcache Debug block always displays Cache Status: "Miss", with no reason listed. I'm getting an X-Varnish-Cache: HIT header and X-Varnish-Cache-Hits value greater than 1, so I know the page is being returned from Varnish. Until I added these headers to display, I didn't think it was working based on the output from the Authcache Debug block. Do you see any misconfiguration or could this be a bug in Authcache Debug?

That could very well be a bug in Authcache Debug.

Btw. Do you think it would be more user-friendly when the VCL would be in a single file?

vinmassaro’s picture

authcache_debug.js checks for the cache_render cookie:

    // If cache_render cookie is set, we did hit the page cache.
    if ($.cookie("cache_render") && $.cookie("cache_render") != "get") {
      cacheRenderTime = $.cookie("cache_render");
      info['Cache Status'] = 'HIT';

      if (cacheRenderTime == 'hit') {
        alertColor = 'green';
        cacheRenderTime = '?';
      }
      else if (cacheRenderTime < 30) {
        alertColor = 'green';
      }
      else if (cacheRenderTime < 100) {
        alertColor = 'orange';
      }
      else if (cacheRenderTime > 100) {
        alertColor = 'red';
      }
    }

Where/how is this cookie set? Does it need to be accounted for in the VCL?

I thought the VCL was easier to digest once I had all of them together in one file. Here is a patch that combines them into one file and adjusts the README a little bit.

znerol’s picture

Thanks for your suggestions and the patch. Looking around the web I realized that it is common practice to simply copy over at least vcl_recv when customization is necessary. I also realized that it is not common to split up the caching-policy into multiple files.

In commit 4cb09f4 the vcl is brought together into one file, the cookie-tunneling code is removed and also all but one request variable.

Do you think that this is easier for people to adapt/deploy? Should we introduce more optional (commented) snippets of things one might use (e.g. the static file stuff from fourkitchens or PURGE-support?)

vinmassaro’s picture

I'm away this weekend but will take a look and give some feedback in a few days. Thanks!

vinmassaro’s picture

Yes, I think this was easier to adapt as one file. If you are using Varnish already and adding Authcache support, you most likely already have an existing VCL. I think Drupal 7 Varnish 3 VCLs are already available on the internet as good examples of where to start, so it's easier to see the Authcache Varnish logic in one file and integrate the pieces into an existing VCL.

I tested the latest dev release with the updated VCL and the responses are working correctly. I am getting cached responses back from Varnish based on the X-Varnish-Cache and X-Varnish headers. Here is how I am testing:

  1. Give two users (User A and User B) the role 'staff'. Enable authcache for the 'staff' role.
  2. In Firefox, log in with User A. Visit /test-page.
  3. In Safari, log in with User B. Visit /test-page.
  4. Examine headers in both browsers. If the second value of the X-Varnish header matches for both users, authcache_varnish is working correctly. I also check that X-Varnish-Hits is greater than 1 and for an X-Varnish-Cache: HIT header. I am setting these extra headers in vcl_deliver based on my existing VCL.

The authcache_debug block still seems to be broken, since I never get a green status and Cache Status: HIT, just yellow and Cache Status: MISS. Based on this from example.vcl:

sub vcl_deliver {
  if (obj.hits > 0 && req.http.Cookie ~ "(^|;)\s*cache_render=get\s*($|;)" && resp.http.X-Generator ~ "Drupal") {
    set resp.http.Set-Cookie = "cache_render=hit; Path=/";
  }
}

It appears that cache_render=get cookie never gets set from authcache_debug.js to set cache_render=hit.

vinmassaro’s picture

Do you think it makes sense to have the authcache_varnish module set a persistent header that we can detect inside vcl_recv, to wrap some of this logic in? Something like X-Authcache-Varnish: enabled if the authcache_varnish module is enabled?

As I mentioned earlier, I'm trying to integrate this into an existing VCL that sits in front of a few hundred sites on university Drupal infrastructure. This configuration is set up to cache requests for anonymous users. If I want to to add support for authcache that will be used on just 1 site, it doesn't make sense to do this for all sites NOT using authcache_varnish, right?

  if (req.restarts == 0) {
    // Retrieve the authcache-key from /authcache-varnish-get-key before each
    // request. Upon vcl_deliver the authcacke-key is copied over to the
    // X-Authcache-Key request header and the request is restarted.
    unset req.http.X-Authcache-Key;
    set req.http.X-Original-URL = req.url;
    set req.url = "/authcache-varnish-get-key";
    set req.http.X-Authcache-Get-Key = "sent";
  }

It looks like I can also restore caching for anonymous users (and authcache_varnish still works correctly for enabled roles) by commenting out:

sub vcl_fetch {
  // Do not cache a response when X-Authcache-Key is empty or missing on the
  // *request*.
  if (!req.http.X-Authcache-Key && req.http.X-Authcache-Get-Key == "done") {
    set beresp.ttl = 0s;
  }
}
znerol’s picture

I'm trying to integrate this into an existing VCL that sits in front of a few hundred sites on university Drupal infrastructure. This configuration is set up to cache requests for anonymous users. If I want to to add support for authcache that will be used on just 1 site, it doesn't make sense to do this for all sites NOT using authcache_varnish, right?

Oh, hm. It would probably be easier (and safer) to use two separate varnish instances in that case. One for the authcache enabled site and the other one for the rest.

It looks like I can also restore caching for anonymous users (and authcache_varnish still works correctly for enabled roles) by commenting out:

You should not need to comment out anything. Authcache Varnish should work for anonymous traffic too. The callback /authcache-varnish-get-key is supposed to return $base_root when accessed by an anonymous user. Though it might be feasible to turn off key-retrieval for anonymous users like this:

if (req.http.Cookie ~ "(SESS[a-z0-9]+)") {
  // key retrieval-block here
}

This technique could be extended to the whole VCL. Perhaps you could place the following snipped into vcl_recv:

if (req.restarts == 0)
  if (req.http.Cookie ~ "(SESS[a-z0-9]+)" /* && some additional checks like e.g. the domain */) {
    set req.http.X-Authcache-Enable = '1';
  }
  else {
    unset req.http.X-Authcache-Enable;
  }
}

Then you can wrap all the authcache bits throughout the whole VCL into if (req.http.X-Authcache-Enable) blocks.

vinmassaro’s picture

You should not need to comment out anything. Authcache Varnish should work for anonymous traffic too. The callback /authcache-varnish-get-key is supposed to return $base_root when accessed by an anonymous user.

I should clarify: Authcache Varnish works for anonymous traffic with the included VCL IF you enable caching for the anonymous role via the module. I wanted anonymous caching to continue to work on other sites that are NOT using Authcache. All sites use the Varnish module and set $conf['cache'] = 1, so they are set up to cache for anonymous users automatically. I would prefer to not maintain separate VCLs and conditional loading logic. My hope was to add the Authcache VCL bits so that it would work for both cases, whether a site has Authcache enabled or not.

I think the 2nd snippet in #19 would work for sites using Authcache, but would apply to all other sites where a user has logged in and you aren't using Authcache. All of the Varnish 3 VCLs for Drupal that I've seen strip out all but the session cookie and bypass Varnish when logged in.

Any ideas about how to fix authcache_debug for authcache_varnish? I can open a separate issue if you want. Thanks!

znerol’s picture

Ok, I think I've got the VCL working also for non-authcache enabled backends. The logic works as follows:

  1. Always attempt key-retrieval when a session cookie is on the request
  2. Otherwise skip key-retrieval phase (anonymous users)
  3. Only prevent caching from vcl_fetch when key-retrieval was attempted but no key was returned

Now we have four cases:

Vanilla Drupal, Anonymous User
No call to /authcache-varnish-get-key, no authcache-related actions in vcl_recv
Vanilla Drupal, Authenticated User
Call to /authcache-varnish-get-key results in 404. Result of key-retrieval is forcibly cached for 10 minutes, while result of original page request is excluded from cache (hit_for_pass).
Drupal + Authcache Varnish, Anonymous User
No call to /authcache-varnish-get-key, no authcache-related actions in vcl_recv
Drupal + Authcache Varnish, Authenticated User
Call to /authcache-varnish-get-key results in 200. Result of key-retrieval is forcibly cached for 10 minutes, while result of original page is subject to the cache policy (e.g. ttl set by the backend via $conf['page_cache_maximum_age']).

The whole thing does not bloat the VCL too much.

Commits:

Any ideas about how to fix authcache_debug for authcache_varnish? I can open a separate issue if you want. Thanks!

Please open a separate issue. The browser cache might interfere with the cache-indicator. Also I suspect that there are race conditions in the debug widget.

vinmassaro’s picture

I'm going to test this out later today and will follow up with a separate issue if authcache_debug is still not working.

This is an important requirement of a project we're working on, so I appreciate the fast response and help with this!

znerol’s picture

Ok, another update: 18e1562. I think I'm close now.

The behavior is now like in #21 but with the additional option to conditionally turn off key-retrieval (See Example 3 in the vcl_recv). If you set req.http.X-Authcache-Get-Key = "skip" somewhere before the key-retrieval logic kicks in, authcache will not attempt to fetch the key from the backend and just falls back to the default behavior (never cache when cookies are present on the request).

Please note that I removed the drupal_uid and drupal_user cookies in the following commit (8cf78dc). If cookie-filtering VCL is in place, the authcache backend tried to recreate them on every request. Varnish will not cache any responses with a Set-Cookie header.

vinmassaro’s picture

Thanks, I tested the latest dev release and it seems to be working correctly for me aside for the authcache_debug. I opened a separate issue for that. I'll follow up if I run into anything else. Thanks again!

znerol’s picture

I did a new version with even more comments. Also there is a test-suite now inside authcache_varnish/test, which can be used to run tests against the VCL (using varnishtest).

vinmassaro’s picture

I just noticed an issue that must have been going on but I had not noticed before. We use CAS to authenticate into our sites and what I am seeing is that when a user with the administrator role logs in at /cas, it is returning back a cached, anonymous user home page. When a role that has authcache enabled logs in, it returns them a cached version correctly for their role. I have authcache enabled for the anonymous role, as well as a few special roles.

I tried adding cas and cas* to the authcache page exclusions but it didn't help. I created a Drupal core user with the administrator role, and when I log in at /user, it works fine and logs me in as an administrator since I can see the admin toolbar, etc. When I test it on a site that doesn't use Authcache at all, logging as an administrator with CAS works fine. In vcl_recv, /cas.*$ is part of the custom pass rules. Any ideas?

vinmassaro’s picture

FWIW, if I disable anonymous caching in Authcache and I log in to CAS as an admin, it works.

znerol’s picture

Are you sure that this is a VCL problem? If not it would be better to handle that in a separate issue.

vinmassaro’s picture

I'm not entirely sure what is causing it, to be honest. I'll open up a separate issue.

vinmassaro’s picture

I noticed that when I added $conf['reverse_proxy_addresses'], I was getting redirect loops when trying to log in with CAS. I updated to the latest Authcache dev and loaded the Authcache example.vcl and selectively commented portions in vcl_recv until I narrowed down the problem. Commenting out the entire 'BEGIN default.vcl' block fixes the problem and allows me to log into CAS. Should this block be in the middle of vcl_recv?

znerol’s picture

Should this block be in the middle of vcl_recv?

Definitely yes, it must remain there. My test-setup is as follows (varnish and httpd on localhost):

  • IP alias on any network interface (e.g. 10.0.0.2/24 on eth0)
  • Add reverse proxy settings to sites/10.0.0.2/settings.php:
    $conf['reverse_proxy'] = TRUE;
    $conf['reverse_proxy_addresses'] = array('127.0.0.1');
  • Ensure that web server listens at least on 127.0.0.1
  • Ensure that varnish listens at least on 10.0.0.2 and connects the backend on 127.0.0.1
  • Access your site via 10.0.0.2 (and not via 127.0.0.1 or localhost)

For the Drupal reverse proxy configuration to work correctly, it is essential that the client IP is not the same as the reverse proxy IP. Otherwise ip_address() will return NULL and that might cause random problems.

Side note: On Mac OS X you can simply add a second IP Address to an existing interface using the Network System Preferences. See this answer on stackexchange or this video on youtube (skip to 2:20). On Windows it works a little bit less awkward.

vinmassaro’s picture

Ah, that must be my problem then. I have MAMP/Apache running 127.0.0.1:8080, Varnish started at 127.0.0.1:6082 and listening on 127.0.0.1:80. My client IP is obviously 127.0.0.1. I just followed your instructions and think I have this working again. Spent way too long on this tonight, thanks!

vinmassaro’s picture

I have MAMP/Apache now at 127.0.0.1:8080, Varnish at 10.0.0.1:80 connecting to my backend at 127.0.0.1:8080, and added an additional IP to my wireless device. Also have an entry in /etc/hosts for 10.0.0.1 d7. I keep getting the MAMP start page at 10.0.0.1 as if my vhost isn't working. Does this configuration sound right? Also, wouldn't $conf['reverse_proxy_addresses'] need to contain 10.0.0.1, not 127.0.0.1 since the reverse proxy is now at 10.0.0.1?

znerol’s picture

Check the following things:

  • Verify that you have NameVirtualHost * somewhere in your apache config
  • Verify that your virtual-host directives are on the right port (i.e. <VirtualHost *:8080>)
  • Verify that you have ServerName d7 in the right virtual host directive
  • If you use http://d7/as the address in your browser , ensure that you have the reverse proxy settings in sites/d7/settings.php.

Concerning the reverse proxy address. If you tell varnish to connect to the backend at 127.0.0.1, drupal "sees" the connection coming from 127.0.0.1. If you tell varnish to use 10.0.0.1 to connect to the backend, drupal would see 10.0.0.1 as the remote address.

znerol’s picture

Issue summary: View changes

Fix URL to VCL

znerol’s picture

Issue summary: View changes
Status: Active » Fixed

Given that there is a complete executable test-suite for the VCL (how cool is varnishtest) and that meanwhile all sub modules automatically provide support for both Ajax and ESI, I'm tempted to mark this fixed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.