HTTP Caching with Varnish

& Caching eZ Websites



Web Summer Camp, September 1st, 2017


© David Buchmann, Hrvoje Knežević

Step 1

apt-get install varnish
            

Step 1

apt-get install varnish
            

Step 2

service apache2 restart
service varnish restart
            

Step 3

What could possibly go wrong?

httpstatusdogs.com

Overview




HTTP Refresher

What is a reverse proxy again?

HTTP is simple

GET /path

HTTP/1.1 200 OK
Content-Type: text/html

<html>...</html>
            

HTTP verbs

HTTP response codes

twitter.com/stevelosh/status/372740571749572610

Tools and helpers

                wget -Sq --spider ezvarnish.websc/solutions/expiration.php
                curl -o /dev/null -sD - ezvarnish.websc/solutions/expiration.php
            



HTTP Cache Control

Cache control headers

HTTP 1.1, RFC 2616, Sections 13.2 and 13.3

Cache Expiration

Cache-Control: s-maxage=3600, max-age=900
Expires: Thu, 15 May 2014 08:00:00 GMT
            
  1. s-maxage
  2. max-age
  3. Expires (HTTP 1.0 - avoid!)
  4. Default to default_ttl if nothing specified

Prepare for the Exercises

cd /var/www/html/summercamp/ezvarnish
git pull
sudo ./installation/enable-varnish.sh
            

Hands on: Cache headers

curl -sD - ezvarnish.websc/noinfo.php
curl -sD - ezvarnish.websc/exercises/expiration.php
            

Cache validation (I)

ETag: 82901821233
            
If-None-Match: 82901821233

304 Not Modified
            

Hands on: Etag

curl -sD - ezvarnish.websc/exercises/etag.php
curl -H "If-None-Match: abc" -sD - ezvarnish.websc/exercises/etag.php
            

Cache validation (II)

Last-Modified: Tue, 13 May 2014 08:13:20 GMT
            
If-Modified-Since: Tue, 13 May 2014 08:13:20 GMT

304 Not Modified
            

Hands on: If-Modified-Since

curl -sD - ezvarnish.websc/exercises/last-modified.php
curl -H "If-Modified-Since: {previous timestamp}" -sD - ezvarnish.websc/exercises/last-modified.php
            











There are dog images too, but I won’t show the 304 one.

Validation: ETag or Last-Modified

Know your tools

Do not cache

Cache-Control: s-maxage=0, private, no-cache
            

www.varnish-cache.org/trac/browser/bin/varnishd/default.vcl?rev=3.0 (Varnish 3)
www.varnish-cache.org/trac/browser/bin/varnishd/builtin.vcl?rev=4.0 (Varnish 4)

Hands on: Do not cache

curl -sD - ezvarnish.websc/exercises/nocache.php
            

Default Varnish behaviour

Hands on: Cookie

curl -sD - ezvarnish.websc/cookie.php
curl -H "Cookie: x" -sD - ezvarnish.websc/solutions/expiration.php
            

Keep variants apart

Content depending on request headers

GET /resource
Accept: application/json
            
GET /resource
Accept: text/xml
            
Vary: Accept
            

Hands on: Content negotiation

curl -sD - ezvarnish.websc/exercises/content-negotiation.php
curl -H "Accept: application/json" -sD - ezvarnish.websc/exercises/content-negotiation.php
            

FOSHttpCacheBundle

# app/config/config.yml
fos_http_cache:
  cache_control:
    rules:
      # only match login.example.com
      -
        match:
          host: ^login.example.com$
        headers:
          cache_control: { s_maxage: 0 }
          vary: [Accept-Encoding, Accept-Language]
        

FOSHttpCacheBundle

# match all actions of a specific controller
-
  match:
    attributes: 
      _controller: ^AcmeBundle:Default:.* 
  headers:
    cache_control: 
      public: true
      max_age: 15
      s_maxage: 30
    last_modified: "-1 hour"
  

Let’s look into Varnish

Warning!


Varnish does what you tell it


Think carefully and test thoroughly

Varnish Configuration Language

Restart Varnish

Pro Tip: varnishadm

VCL: Debug hit or miss, TTL

sub vcl_backend_response {
    set beresp.http.X-TTL = beresp.ttl;
}

sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
}
            

VCL: Two applications

backend default {
    .host = "127.0.0.1";
    .port = "8888";
}
backend legacy {
    .host = "127.0.0.1";
    .port = "8888";
}
sub vcl_recv {
    if (req.url ~ "^/archive/") {
        set req.backend_hint = legacy;
    } else {
        set req.backend_hint = default;
    }
}
            

VCL: Remove cookies

sub vcl_recv {
    if (req.http.Cookie) {
        if (req.url ~ "^/cache") {
            remove req.http.Cookie;
        }
    }
}
curl -H "Cookie: x" -sD - ezvarnish.websc/solutions/expiration.php
            

Bad Practice: This is leaking knowledge about URLs to Varnish config

VCL can do a lot of things


But first make your application behave correctly!

Take-Aways




Caching and Sessions

Strategies when working with sessions

VCL: Remove all but session cookie

sub vcl_recv {
    set req.http.cookie = ";" + req.http.cookie;
    set req.http.cookie = regsuball(req.http.cookie, "; +", ";");
    set req.http.cookie = regsuball(req.http.cookie, ";(PHPSESSID)=", "; \1=");
    set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", "");
    set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", "");
    if (req.http.Cookie == "") {
        remove req.http.Cookie;
    }
}
            

varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies #RemovingallBUTsomecookies

User Context


Group based caching

Demo: User Context

# config/varnish/common.vcl
include "fos_custom_ttl.vcl";
include "user_context.vcl";
            
sudo service varnish restart
            
ezvarnish.websc/user-context/ (with your browser)

HTTP caching in eZ

Outlook: There is more than caching

Prepare for the next workshops

cd /var/www/html/summercamp/ezvarnish
sudo ./installation/disable-varnish.sh
            


Questions / Input / Feedback ?


Twitter: @dbu