Time to update to Varnish 6?

I’ve been using ‘varnish’ for ages for caching webcontent (e.g. wordpress sites). Then I needed https support (cue Apache or haproxy) …. then I needed http 2.0 support ….

I’ve finally bothered upgrading off Varnish 3 to Varnish 6, and adding in ‘hitch’ (and http/2.0 / h2 support).

Random configuration snippets … this is from using Debian.

Hitch (v1.4.x)

Install via .deb via packagecloud

Test config with ‘hitch -t /etc/hitch/hitch.conf’

# /etc/hitch/hitch.conf : 

# listen on port 443, forward with the proxy protocol to localhost:81 (varnish)

frontend = {
    host = "*"
    port = "443"
}

backend = "[127.0.0.1]:81"


ocsp-dir = "/var/lib/hitch-ocsp"

ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
prefer-server-ciphers = on
tls-protos = TLSv1.2 TLSv1.3
alpn-protos = "h2, http/1.1"
workers = 2
backlog = 100
keepalive = 3600
chroot = ""
user = "hitch"
group = "hitch"
syslog = on
syslog-facility = "daemon"
daemon = on
write-ip = off
write-proxy-v2 = on
proxy-proxy = off
sni-nomatch-abort = off

tcp-fastopen = on

pem-file = "/etc/hitch/ssl/foo.com.pem"
pem-file = "/etc/hitch/ssl/bar.org.pem"

You’ll need to use e.g. certbot to generate your SSL .pem files. Concatenate the key, certificate and, if necessary, any intermediate into a .pem file.

( cat foo.com.key foo.com.crt > foo.com.pem )

Varnish 6

Install from packagecloud

Systemd service file needs to be a bit like this – the only important bit is “-p feature=+http” and “-a localhost:81:PROXY” (which makes it listen as a backend for hitch).
After editing/creating, don’t forget : “systemctl daemon-reload”.

(If you’re not using systemd, there’s /etc/default/varnish that’ll need editing).

# /etc/systemd/system/varnish.service
[Unit]
Description=Varnish Cache, a high-performance HTTP accelerator
After=network-online.target nss-lookup.target

[Service]
Type=forking
KillMode=process

# Maximum number of open files (for ulimit -n)
LimitNOFILE=131072

# Locked shared memory - should suffice to lock the shared memory log
# (varnishd -l argument)
# Default log size is 80MB vsl + 1M vsm + header -> 82MB
# unit is bytes
LimitMEMLOCK=85983232

# Enable this to avoid "fork failed" on reload.
TasksMax=infinity

# Maximum size of the corefile.
LimitCORE=infinity

ExecStart=/usr/sbin/varnishd \
          -a :80 \
          -a localhost:81,PROXY \
          -p feature=+http2 \
          -f /etc/varnish/default.vcl \
          -s malloc,256m
ExecReload=/usr/sbin/varnishreload

[Install]
WantedBy=multi-user.target

Then finally, varnish’s config :

#  /etc/varnish/default.vcl
vcl 4.1;
import std;
import proxy;


backend foo {
    .host = "1.2.3.4";
    .port = "80";
}
backend bar {
    .host = "4.3.2.1";
    .port = "8001";
}

sub vcl_recv {

    if ( req.http.host ~ "foo.com" ) {
        set req.backend_hint = foo;
        set req.http.Host = "foo.com";
    }

    # www.bar.org and bar.org should get caught in this
    if ( req.http.host ~ "bar.org" ) {
        set req.backend_hint = bar;
        set req.http.Host = "www.bar.org";
    }

    if(proxy.is_ssl() || std.port(local.ip) == 81) {
	std.log("https ... " + req.http.host + "/" + req.url);
	set req.http.X-Forwarded-Proto = "https"
    }

    /* Always cache images and multimedia - the regexp below should cope with e.g. foo.css?ver=12 
       but not result in foo.php?blah=foo.css being cached - i.e. the .css has to come before a ? if one is present */
    if (req.method == "GET" && req.url ~ "^[^\?]+\.(js|css|gif|png|jpg|jpeg|gif|png|tiff|tif|svg|swf|ico|m4a|ogg|mov|avi|wmv|woff)") { 
	std.log("Removing cookie, and trying to retrieve from cache " + req.url);
        unset req.http.Cookie;
        return(hash);
    }

    std.log("trying : URL " + req.url + " with " + req.http.Host);
 
     # fall through to default vcl - https://www.varnish-software.com/wiki/content/tutorials/varnish/builtin_vcl.html
}
 


sub vcl_backend_response {
     # besresp - backend response.
     set beresp.http.X-Via= "varnish on web01";
     set beresp.http.Server= "Varnish/Apache";
     unset beresp.http.Via;
     unset beresp.http.X-Varnish;


     if (bereq.method == "GET") {
	if (bereq.url ~ "^[^\?]+\.(js|css|gif|png|jpg|jpeg|gif|png|tiff|tif|svg|swf|ico|m4a|ogg|mov|avi|wmv|woff)") { 
	     std.log("ZZZ Long lasting, cachable yummy stuff found - image/css/js etc, caching for ages ");
	     set beresp.ttl = 36000s;
	     set beresp.http.Cache-Control = "public; max-age: 36000s";
	     unset beresp.http.Expires;
	     unset beresp.http.Pragma;
	     unset beresp.http.ETag;
	     unset beresp.http.Set-Cookie;
	}
   }

   if (beresp.http.Content-Type && beresp.http.Content-Type ~ "video") { 
	set beresp.do_stream = true;
   }

    return (deliver);
}

# 
sub vcl_deliver {
    set resp.http.Server = "Varnish";
    set resp.http.X-Varnish-Hits = "Hit - " + obj.hits;
    unset resp.http.ETag;
    unset resp.http.X-Powered-By;
    unset resp.http.Via;
    unset resp.http.X-Via;
    unset resp.http.X-Varnish;
    return (deliver);
}


sub vcl_hash {
    if(req.http.X-Forwarded-Proto) {
	hash_data(req.http.X-Forwarded-Proto);
    }
	# https://varnish-cache.org/docs/4.1/users-guide/vcl-hashing.html
	# fall through to default thing with req.http.host etc
}

And finally … if you’re running Apache on the ‘backend’ you need to use something like mod_rpaf or mod_remoteip so it realises it needs to use the X-Forwarded-For header for the IP address.

If you’re using mod_rpaf (which seems to handle https) you can do :

# after 'a2enmd rpaf'
# e.g. /etc/apache2/mods-enabled/rpaf.conf
<IfModule rpaf_module>
    RPAFenable On

    RPAFsethostname On
    # ip address varnish requests come from
    RPAFproxy_ips 89.16.169.138

    # the header it can find the 'real' client ip addr in
    RPAFheader X-Forwarded-For
</IfModule>

<IfModule setenvif_module>
   # if X-Forwarded-Proto == http, set HTTPS=on
    SetEnvIf X-Forwarded-Proto https HTTPS=on
</IfModule>

Leave a comment

Your email address will not be published. Required fields are marked *