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>