TEQ

Tech Docs

HTTPS/SSL Implementation with Varnish Cache Nginx/Apache Stack

Varnish Cache is really, really fast. It typically speeds up delivery with a factor of 300 – 1000x, depending on your architecture. but Varnish Cache cannot deliver website over HTTPS. So here is a solution for that.

Step 1 – Install Hitch and Varnish

Hitch, is a scalable, open source network proxy designed to efficiently handle tens of thousands of connections on multicore machines. We will install and configure hitch to listen on port 443 while Varnish being the backend for the hitch.

Ubuntu Xenial

Update the package metadata and install the required packages:

sudo apt-get update sudo apt-get install hitch varnish

CentOS7 / Red Hat EL7

Install the required packages. In order to get Varnish 4.1 with added support for the PROXY protocol, we add the official Varnish repository first.

sudo yum install epel-release

sudo rpm –nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.1.el7.rpm


sudo yum install hitch varnish

Step 2 – Configure Varnish

We want Varnish to forward all challenge requests to Acmetool, and we are going to create a request matching rule in VCL that will ensure this forwarding happens.

Again open your favourite editor and edit /etc/varnish/default.vcl with the following contents:

# Forward challenge-requests to acmetool, which will listen to port 402
# when issuing lets encrypt requests

backend acmetool {
   .host = "127.0.0.1";
   .port = "402";
}

sub vcl_recv {

  if (req.url ~ "^/.well-known/acme-challenge/") {
        set req.backend_hint = acmetool;
return(pass);
    }
}

As we will be using Hitch to forward requests, we want Varnish to listen to an additional port (6086) using the PROXY protocol support that was added in Varnish 4.1. (If for some reason you do not want to run Varnish 4.1, you can skip this step, and simply change the port used for Varnish in the hitch config to 6081.)

On Ubuntu Xenial, open the file /lib/systemd/system/varnish.service add -a ‘[::1]:6086,PROXY’ to the ExecStart line. You then need to update systemd by running:

sudo systemctl daemon-reload

In CentOS7 the same option is added by editing /etc/varnish/varnish.params and ensure the DAEMON_OPTS setting includes the following: DAEMON_OPTS=”-a ‘[::1]:6086,PROXY'”

Restart Varnish so that it will listen to the new ports, and use the correct forwarding rule for the challenge requests.

sudo service varnish restart

Step 3 – Install Acmetool

We will now install the Acmetool binaries using the available APT PPA for Ubuntu, and the copr repository for CentOS7.

Ubuntu Xenial

Acmetool is published in a PPA, so we will add this and then install the package:

sudo add-apt-repository ppa:hlandau/rhea

sudo apt-get update

sudo apt-get install acmetool

CentOS7 / Red Hat EL7

Acmetool is available in a copr repository. We will get the repository file and then install the package:

sudo wget –quiet -O /etc/yum.repos.d/hlandau-acmetool-epel-7.repo ‘https://copr.fedorainfracloud.org/coprs/hlandau/acmetool/repo/epel-7/hlandau-acmetool-epel-7.repo

sudo yum install acmetool

Step 4 – Acquire the certificate

Now we will use Acmetool to acquire a certificate.

Now we have everything in place and we run the Acmetool quickstart process. It should detect that we are using Hitch and automatically set up a hook that will generate Hitch-compatible certificate-packages from certificate requests.

sudo acmetool quickstart

Answer the prompts like this to enable live certificates authenticated through challenge requests proxied through Varnish.

------------------------- Select ACME Server -----------------------
1) Let's Encrypt (Live) - I want live certificates


----------------- Select Challenge Conveyance Method ---------------
2) PROXY - I'll proxy challenge requests to an HTTP server


Review and (hopefully) accept the letsencrypt.org Terms of Service, and enter your email address.
-------------------- Install HAProxy/Hitch hooks? ------------------
Yes) Do you want to install the HAProxy/Hitch notification hook?


-------------------- Install auto-renewal cronjob? -----------------
Yes) Would you like to install a cronjob to renew certificates automatically? This is recommended.

Before we continue to requesting our certificate we need to generate a Diffie-Hellman group file (aka dhparams), used for perfect forward secrecy.

sudo openssl dhparam -out /var/lib/acme/conf/dhparams 2048

Now we can finally get our certificate:

sudo acmetool want example.com

Step 5 – Configure Hitch

Now we should have our own valid certificate, and we can use it to set up Hitch. As previously mentioned we configured Varnish to listen to an additional port (6086) where it will accept requests using the PROXY protocol.

Use your favorite editor to create the file /etc/hitch/hitch.conf and copy the following contents into it, note the required user/group settings on CentOS/RHEL.

## Basic hitch config for use with Varnish and Acmetool

# Listening
frontend = "[*]:443"
ciphers  = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"

# Send traffic to the Varnish backend using the PROXY protocol
backend        = "[::1]:6086"
write-proxy-v2 = on

# If you run Varnish 4.0 use this instead
#backend        = "[::1]:6081"
#write-proxy-v2 = off 

# List of PEM files, each with key, certificates and dhparams
pem-file = "/var/lib/acme/live/example.com/haproxy"

# Set uid/gid after binding a socket
# Uncomment these on CentOS/RHEL
#user = "hitch"
#group = "hitch"

Start Hitch with the new configuration:

sudo service hitch start

Step 6 – Set up HTTP to HTTPS Redirection

Add following code to vcl_recv of VCL file

# set x-forwarded-proto header to https if connections comes from Hitch SSL Proxy.
if (std.port(local.ip) == 6086) {
set req.http.X-Forwarded-Proto = "https";
}

# force http://example.com to https://example.com if connections comes from HTTP (Port: 80) Listener.
if ( req.http.host ~ "^(?i)example.com" && req.http.X-Forwarded-Proto !~ "(?i)https") {
set req.http.x-redir = "https://example.com" + req.url;
return(synth(301));
}

Add following code to vcl_synth of VCL file

if (resp.status == 301) {
set resp.http.Location = req.http.x-redir;
return (deliver);
}

Step 7 – Restart Varnish Cache and test

sudo service varnish restart

Access your website with HTTP, now it should be redirected to HTTPS. Contact me in case of any issues.