0

I've been using Varnish Cache for a few websites. However, I need advice for implementing HTTPS. I am open to alternatives to Varnish Cache. The configuration of Varnish is relatively complex, so perhaps a less advanced alternative would be better suited for my sites.

Cloudflare looks like a viable option, but from what I could see would need a business plan starting from $200/month. I might be mistaken.

Any recommendations?

sysadmin1138
  • 133,124
  • 18
  • 176
  • 300
Albert
  • 171
  • 2
  • 8

1 Answers1

2

Using HTTPS on Varnish isn't that hard. Although Varnish doesn't natively offer TLS, it facilitates TLS termination.

In 2015 Varnish released Hitch, a very powerful TLS proxy that handles terminates TLS and forwards unencrypted HTTP traffic to Varnish.

Installing Hitch

You can download the source from the Hitch website and compile it on our server. If you want to use packages to install Hitch, you can run the following command on Debian or Ubuntu:

apt-get install -y hitch

Configuring Hitch

Once you've installed Hitch, open up /etc/hitch/hitch.conf and make sure you use the following configuration:

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

backend = "[localhost]:8443"

write-proxy-protocol-v2 = on

pem-file = "/etc/hitch/certs/example.com"

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"

tls-protos = TLSv1.2 TLSv1.3

ecdh-curve = "X25519:prime256v1:secp384r1"

prefer-server-ciphers = false

Please put your certificate in /etc/hitch/certs and adjust the pem-file directive in hitch.conf.

Reconfiguring Varnish

Your Varnish runtime configuration probably contains the following listening information:

varnish -a :80

This means Varnish is listening for connections on port 80. To make sure HTTPS works, we'll add another listening port, but with a specific configuration:

varnish -a :80 -a :8443,PROXY

Make sure you reload Varnish after changing the runtime settings.

You'll notice that port 8843 is now also assigned to Varnish. It is not used for standard HTTP, but for HTTP using the PROXY protocol. PROXY protocol support was also enabled in Hitch.

This ensures the original client IP address is passed along to Varnish, regardless of the number of extra hops it has to go through. The original client IP address will be automatically stored in the X-Forwarded-For header by Varnish.

The type of traffic that is processed by port 8443 is HTTP traffic that originated from Hitch and that is in fact terminated HTTPS traffic.

Identifying HTTPS requests

Hitch is a TLS proxy, it doesn't understand HTTP. This means it cannot set the conventional X-Forwarded-Proto header to indicate what kind of traffic was terminated. Luckily we can track which port was used.

The VCL code below detects HTTP/HTTPS requests and assigns the proper X-Forwarded-Proto header.

vcl 4.0;
import std;
sub vcl_recv {
    if (std.port(local.ip) == 8443) {
        set req.http.X-Forwarded-Proto = "https";
    } else {
        set req.http.X-Forwarded-Proto = "http";
    }
}

A lot of frameworks and CMS systems leverage the X-Forwarded-Proto header to automatically build the right URL schemes. The fact that we're setting this header in VCL is very helpful.

Protocol-base cache variations

A cache stores HTTP responses, not HTTP requests. So when an object gets stored in cache, Varnish doesn't know if it came from an HTTP or an HTTPS URL. If we start caching them without extra measures, you can end up getting stuck in an infinite redirection loop if Varnish starts caching the HTTP version of an object.

To avoid this, Varnish needs to have a cache variation per protocol. You can easily instruct Varnish to do so by returning the following HTTP response header in your backend application:

Vary: X-Forwarded-Proto

If for some reason this is not possible, you can also extend the vcl_hash logic in your VCL code. In that case, please add the following snippet:

sub vcl_hash {
  hash_data(req.http.X-Forwarded-Proto);
}
Thijs Feryn
  • 1,166
  • 4
  • 5
  • Thank you for the detailed explanation. Seems the solution I'm looking for. I'm trying to combine it with letsencrypt, based on https://docs.varnish-software.com/tutorials/hitch-letsencrypt/. However I'm getting a very strange error "Mar 18 17:38:03 cache-srv1 hitch[10938]: Error in configuration file '/etc/hitch/hitch.conf', line 1: Invalid address string '{'". My config file is exactly as you specified...any idea? Thanks – Albert Mar 18 '20 at 17:39
  • I was able to fix it by specifying frontend using the "[*]:443" format. However now varnish is closing the session with " SessClose RX_JUNK". My varnish version is varnish-5.2.1 revision 67e562482 – Albert Mar 18 '20 at 17:51
  • @Albert: are Varnish & Hitch speaking the same protocol? Either both pure HTTP or both PROXY protocol? I mentioned the details about that in the answer above, please have a look and confirm. – Thijs Feryn Mar 19 '20 at 16:38
  • it seems the problem is either that or hitch is using http/2 while varnish not. Initial hitch version installed was very old 1.1.1 (ubuntu16). I did upgrade now to 1.4.6 based on https://launchpad.net/~lasse-karstensen/+archive/ubuntu/hitch however still some config options are not support. Will try to enable http/2 in varnish and see if it works – Albert Mar 19 '20 at 17:36
  • Just did enable http/2 in varnish and it's working. Thanks a lot – Albert Mar 19 '20 at 17:42
  • @Albert Good call! Forgot about that one. Glad you managed to fix it. – Thijs Feryn Mar 20 '20 at 07:35