December 10, 2012

TYPO3 login state and Varnish cache

Caching is hard in complex page setups with user specific content, especially when public pages change their content once a user is logged in. TYPO3 is smart enough to deal with the login state properly and cache appropriately. Once Varnish is involved, it’s quite tricky to cache as much as possible without loosing the dynamic content. But it’s not impossible and here’s my summary how we resolved it for typo3.org.

Setup

The basic Varnish setup is more or less always the same and best described by Farbrizio Branca. On top of that we need some TypoScript parameter tweaking to get the cache-control-headers in TYPO3 straight - Daniel Pötzinger’s article covers them best. Another very handy thing which can be found in Fabrizio’s blog is the simplified flow chart for the various Varnish subroutines.Based on that all pages should be cached properly and your site should run smoothly. But in case you have a page with personalized content, you’ll have to reconsider some parts.

Problem

The event submission page on typo3.org is a good example. In case the user is not logged in (a.k.a public page), we just want to show a message which guides him to the login. If there’s a login active (a.k.a user page), we’ll show the submission form instead. In both cases we could cache the content nicely, but how would we ensure that Varnish delivers the correct content?

Solution

Ajax could be a solution, but for large sites it’s usually smarter to avoid as much JavaScript as possible. EdgeSideIncludes (ESI) are another option, but I agree with Daniel, they’re not really useful in this case and I’d rather go with Ajax than with ESI.

What we want in this scenario, is to cache the _public page _in Varnish and pass to the _user page_ generated by TYPO3 if we find that the user is logged in. But this should of course only happen on pages where this is really necessary - normal pages should just ignore the login state of the user. Therefore we need sth. to distinguish _normal_ from _login specific_ pages in Varnish. Lucky enough TYPO3 already provides a field in the pages properties which allows this distinction. Using the Login Behaviour (pages.fe_login_mode) field, you can enable and disable the user-login for specific branches and pages*. As we want to whitelist _login specific_ pages, our root page should have the default setting “Disable Login” - this will be inherited to all sub-pages. All the _login specific_ pages should have the setting “Re-Enable login”.

Once this is done, we need a way to carry that out to Varnish. We improved EXT:cacheinfo for that purpose, with that it now carries a “loginAllowedInBranch” or “noLoginAllowedInBranch” value in the “X-T3CacheInfo” header. Using all that, the Varnish VCL can be extended to make use of it like this:

sub vcl_hit {
  if (obj.http.X-T3CacheInfo ~ "loginAllowedInBranch") {
    set obj.http.Cache-Control = "private";
    if (req.http.Cookie ~ "(e_typo_user|PHPSESSID|_pk_.*)") {
      # Do not cache requests which come from a logged in user
      return (pass);
    }
  }
}

This is straight forward. For every page which allows logins, we make sure that the client does not keep them in his cache. In case we’re actually on such a page and find the related login-cookies, we pass the request along to TYPO3, otherwise we deliver the public page right away from the cache. The fact that we pass the request along to TYPO3 in some cases doesn’t mean that we’ll deliver the user page, it just indicates that we’ve to rely on TYPO3 to make the right choice based on the actual login state.

Conclusion

For me the beauty here lies in the simplicity. Once you managed to wrap your head around the flow chart and once you managed to deliver appropriate meta-data to Varnish, many more complex scenarios can be resolved equally.

As most of the typo3.org stuff, this solution came from a great team. In this case Michael Stucki and Daniel Pötzinger helped to craft the final solution - thanks guys :)


  • the naming of the field’s labels is really irritating - especially “0 - Enable login” should be “Inherit setting” as it really does not force any setting.

© tolleiv 2016 - CC BY-SA 3.0 - Powered by Hugo