Fast HTTPS using Pound, Varnish, LetsEncrypt and Pagespeed

Making https fast

Let’s Encrypt is a great initiative allowing anyone to easily generate and install SSL certificates so that traffic can be securely served over https.

As well as gaining the benefits of secure traffic, by using https we're also setting ourselves up to benefit from HTTP/2, which will allow a number of performance benefits, but is only available over https.

However, generating and installing SSL certificates using Let’s Encrypt doesn't inherently make our site faster, and actually adds some overhead in terms of extra negotiation between the client and the server, as well as requiring the client to check with the certificate authorities to determine whether a certificate has been revoked (at least until we configure the server to take over this task using OCSP stapling.)

Below, we'll look at how to generate and install SSL certificates with Let’s Encrypt, and then how to configure our site so that we can still make use of Varnish and the Pagespeed Module to optimise our site performance.

We're assuming here that you've already got a site up and running using Varnish, and Apache/Nginx, serving http traffic on port 80.

Let’s Encrypt

Let’s Encrypt is now in public beta, meaning that it's available for anyone to use, though you'll need to be aware of the rate-limiting to prevent abuse of the service, the most relevant parts of which are:

Names/Certificate is the limit on how many domain names you can include in a single certificate. This is currently limited to 100 names, or websites, per certificate issued.

Certificates/Domain you could run into through repeated re-issuance. This limit measures certificates issued for a given combination of Public Suffix + Domain (a "registered domain"). This is limited to 5 certificates per domain per week.

To install and use Let’s Encrypt, we'll do the following (presuming you're running Ubunutu or Debian):

Note that we stop our webservers before running letsencrypt, as it needs to use ports 80 and 443 for communication with the certificate authorities.

We're also using --agree-tos to automatically agree to the terms of service, and --email to provide our email so that letsencrypt can create our account. We actually use Ansible configuration management scripts for provisioning our webservers and so need these scripts to run automatically, but in the interests of simplicity, we're not showing that here.

Letsencrypt can include a number of domains on a given certificate (currently up to a 100), though it can't produce wildcard certificates, and we use the -d option above to specify each domain.

Note also that we're using the certonly function; letsencrypt can automatically update webserver configuration files to use the newly generated certificate, but in our case we're going to use Pound to handle https, and our webservers will therefore only be dealing with http traffic.

Letsencypt certificates are currently valid for 90 days, and in the interests of making life easier for ourselves, we'll set up a cron job to automatically attempt to renew the certificate on a weekly basis. Our bash script, /usr/local/letsencrypt/letsencrypt-auto-renew.sh, is as follows:

Would I be able to write a better stand-alone SSL proxy process than the many which already exists ?

Probably not, unless I also write my own SSL implementation library, including support for hardware crypto engines and the works.

That is not one of the things I dreamt about doing as a kid and if I dream about it now I call it a nightmare.

So, if we want to use https, we have to use another service in front of Varnish to proxy https traffic as http to and from Varnish.

If you are using Varnish to directly cache traffic on port 80, your /etc/default/varnish would probably have a line that looks like:

DAEMON_OPTS="-a :80 \

However, as we'll now use Pound to receive traffic in front of Varnish, we'll ensure that Varnish is receiving traffic on its default port of 6081:

DAEMON_OPTS="-a :6081 \

Enter Pound

Pound is a great project, and works very nicely in front of Varnish as reverse proxy, accepting http and/or https traffic as configured, and passing it through to Varnish as http.

In order to be able to disable the SSLv3 protocol to cope with the POODLE vulnerability, we'll need to use Pound 2.7f, as outlined here. Currently, the standard Ubuntu repositories only make Pound 2.6 available.

Note that, in order to avoid the POODLE vulnerability, we're disabling the SSLv3 protocol, and not just the SSLv3 cipher. There appears to be some confusion, with some thinking that disabling the SSLv3 cipher is enough to avoid POODLE, but that's not the case.

Our Ciphers is a list of reasonably modern ciphers, ordered from most-secure to least-secure:

We don't provide support for ciphers such as RC4, as this is considered too weak. This means people using Internet Explorer 6 won't be able to access our site, but that's not really a problem these days.

Pagespeed module

We've now got pound enforcing that all traffic is https, and working nicely with Varnish, which continues to cache our site content.

We've not had to make any changes to our Apache or Nginx site vhost configs, as they're still seeing traffic as http.

Google's Pagespeed Module for Apache and Nginx is a great drop-in webserver module for speeding up our site by making a number of on-the-fly optimisations. It's a topic in itself, and it's worth reading through the documentation to understand how it works and how it can benefit you.

sudo dpkg -i mod-pagespeed-*.deb
sudo apt-get -f install

This results in the Pagespeed module being installed, and since we're using Apache, we'll find the Pagespeed configuration at /etc/apache2/mods-enabled/pagespeed.conf.

We'll want to make the following changes in /etc/apache2/mods-enabled/pagespeed.conf:

As Pagespeed is seeing all traffic coming from Varnish as http, it will normally serve any optimisations accordingly as http. However, this will cause Mixed content warnings in our browser, as http assets are being served on an https site.

Using ModPagespeedRespectXForwardedProto on ensures that Pagespeed checks for the X-Forwarded-Proto: https header added by Pound, and serves any associated optimisations as https.

Summary

We've glossed over a few things above, as it's presumed that you've already installed and are using Varnish and a web-server such as Apache or Nginx to serve traffic on port 80.