I have followed the HTTP/2 specification process closely and I like how the new protocol improves web performance and makes old workarounds obsolete. One drawback of deploying HTTP/2 is that most browser vendors only implement it on top of TLS. Since I’ve seen a lot of broken TLS configurations lately, I thought it would be interesting to set up TLS on my private server and share the resources I used in the process.
But first things first. If you want to use TLS in a professional environment, there is no way around making yourself familiar with some basics. Do not blindly follow advice from random blogs on the internet. If you don’t know how things work on a conceptual level, you may gain a false sense of security which is worse than having no security at all.
The best introduction to TLS I know is Chapter 4 of Ilya Grigorik’s book High Performance Browser Networking which is available for free. His website istlsfastyet.com is a great resource if you’re worried about TLS performance (which you should, it needs proper optimization). You can also watch some of his videos on TLS and other web topics.
Once you understand TLS, you have to figure out how to configure your server (Nginx in my case), which is a challenge in itself as subtle mistakes can have serious consequences. Many older protocols and cipher suites are no longer considered secure and may not be used but on the other hand you may have to support old browsers. Fortunately, Mozilla provides advice for the most popular servers and a configuration generator. As input, you decide which clients you want to support (modern, intermediate, or old clients). Check your web analytics tool to find out what your visitors actually use – ancient browsers like IE6 are fortunately very rare these days.
The most important ingredient to setting up TLS is your certificate. In the past, certificates used to be expensive, but no more. The Let’s Encrypt campaign backed by Mozilla, Akamai, Cisco, and other industry heavy weights offer certificates for free. The tooling is still in beta and automation isn’t quire there yet, but it worked for me. Even if you choose to use an EV certificate instead of a DV one for production, Let’s Encrypt is still useful for experiments.
If you’re going to use TLS exclusively in the future, you can enable HSTS (HTTP Strict Transport Security) in your server which tells returning clients to connect only via HTTPS. Browsers will no longer make plain HTTP requests, no matter what the user types in the address bar. You can also put your site on a HSTS preload list which reduces the chance of session hijacking even further. As an additional advantage, it improves performance by saving the typical HTTP to HTTPS redirect.
When the basic server configuration is done, there are a few performance optimizations you should consider that can speed up the TLS handshake by saving a couple of network roundtrips.
Sometimes certificates get compromised or are revoked for some other reason. This is why browsers use OCSP (the Online Certificate Status Protocol) to check with the responsible CA whether the certificate is still valid. To avoid slowing down the handshake, use OCSP Stapling (aka the TLS status_request extension) to provide the client up-front with a signed, timestamped OCSP response.
You can also improve performance by allowing a returning client to resume an old session, commonly known as Session Resumption. The first approach is to use Session Identifiers which work similar to cookie-based web sessions. Since they have to keep server-side state, they share the same limitations when it comes to load balancing. The client may be routed to a server that doesn’t know the session ID.
Session tickets solve this problem nicely since they pass all necessary state to the client in an encrypted container. Of course, all servers in your cluster have to share the same key and that key has to be rotated regularly.
Once you have configured everything, you have to validate your setup. The most popular validator is the SSL Labs Server Test which is very comprehensive and checks for common vulnerabilities like BEAST, CRIME, Heartbleed, POODLE, or Logjam. Here’s the result from my server:
Also note the IPv6 address, one of my previous projects.
So, with TLS successfully deployed, what’s keeping me from enabling HTTP/2 on my server? Well, Nginx gained HTTP/2 support in version 1.9.5, which isn’t available from Ubuntu 14.04 repositories. Additionally, the provided version of OpenSSL doesn’t support ALPN which is needed during the TLS handshake to agree on HTTP/2. I have decided to wait for Ubuntu 16.04 LTS which is due in a few months.