How to: Move your NginX website to HTTPs / SSL
It comes at no surprise that a lot of people are looking into moving their sites to HTTPs due to recent events: Google’s decision to give ranking points to sites that use SSL / HTTPs and eavesdropping by governments world wide. There are a number of considerations before taking this step, specially for people who have not yet deployed HTTPs / SSL on their web servers.
There are a number of things you need to start doing and fixing in order to have a functional site that performs well. Because most sites were not thought to use SSL to begin with, you’ll find that there might be problems when accessing your site from https instead of http. Below are a few tips to consider although it is not an exhaustive list:
- Internal links: If you are using WordPress you will find a lot of the links you have not only do they include http:// but also the domain name. This is a problem for two reasons: 1) you are hard coding the transport (in this case http) so even if you use a different transport it will force the browser to take the hard coded one and 2) You are hard coding your site’s URL. Imagine you change your domain name… now you have to change all your URLs. For these reasons I generally recommend people use relative URLs (they start with / vs the transport or domain name).
- Infrastructure concerns: Make sure your CDN supports SSL as well as any other part of your infrastructure (reverse proxies, firewalls, etc). Consider using SPDY when using SSL for added performance benefits. I really like using http://spdycheck.org/ to check for SPDY readiness. It lets you know if you have deployed SPDY and other tips to get the most out of it. We will go over the checklist for this in a minute
- NginX specific configuration: We will cover the required configuration needed to address the implementation of an SSL site as well as performance considerations.
So let’s get to it!
I. Use SSL cache
As you can imagine hosting a site using SSL requires additional work on the CPU. We need to make sure we don’t saturate the CPU otherwise our site will be loading much slower. For example, I once tried using a 16k bit certificate… my CPU would die depending on the number of requests it had to handle. For that reason I’ve joined the 99% of people in using a 2k bit certificate for my site. For that same reason we need to turn on SSL session cache on NginX to save on CPU resources:
II. Use the right cyphers
This was also a surprise to me, but you can configure the cyphers NginX uses. This has two major impacts: 1) Certain cyphers are weak or vulnerabilities have been discovered. Pretty much using them does not guarantee much security or worse case, compromises the security of your entire site. 2) Certain cyphers are more CPU intensive than others. Surely you want to be helpful for the poor guy who uses that strange CPU intensive cypher but you’re just asking for trouble down the road. I wrote an article on CloudFlare recommended configuration here: How to: Improve SSL performance on NginX which you can also refer to as well as this article: Hardening Your Web Server’s SSL Ciphers.
Below is the recommended configuration as of the date of publishing of this post:
III. SPDY readiness
So now we are ready to use SPDY! We’ll go step by step through some recommended configurations:
a) Enable SSL with SPDY on the default port 443
listen 443 spdy ssl;
b) Use a valid X.509 Certificate
As long as you are using a valid certificate from a public key certificate authority you’re more likely than not fine.
c) Server Hello Contains NPN Extension
If you are using NginX you’re probably fine. Make sure you are running the latest version.
d) Enable HTTP Fallback
All this means is that your site is also available via HTTP just in case
listen 80 default_server;
listen 443 default_server spdy ssl;
e)HTTP Redirects to HTTPs / SSL / SPDY
If a visitor arrives via HTTP, have your webserver redirect them to the HTTPs version of your site. If you have SPDY enabled they will probably have a faster loading experience.
listen 80 default_server;
server_name cloudingenium.com *.cloudingenium.com;
return 301 https://$host$request_uri;
f) Use HTTP Strict Transport Security (HSTS)
All this does is indicate your client that for future requests for your site it should use SSL. I set up the max age to one day as I am starting to test site wide SSL deployment. If you feel very comfortable with this I have observed most people use a max age of one year. Be as it may the important thing is to enable it and like cache use a reasonable time in case you are forced to go back to a non-SSL site.
# This forces every request after this one to be over HTTPS for one day
add_header Strict-Transport-Security “max-age=86400; includeSubdomains”;
Don’t forget that the includeSubdomains should only be used if you are deploying Strict Transport Security to your subdomains as well. You can remove it if you don’t want your subdomains to use HSTS.
UPDATE: SSLLabs recommends using at least 180 days for your HSTS. So you should use 15552000 for max age once your done testing and find the performance of your site acceptable.
g) Enable OCSP Stapling
If you are not sure what OCSP Stapling is, I recommend reading the CloudFlare article: OCSP Stapling: How CloudFlare Just Made SSL 30% Faster. Pretty much what this does is remove a large portion of the SSL overhead by doing some work on your server. This is good as your visitors will enjoy a faster experience on your site.
First you need to make sure your certificate includes the entire certificate chain. I’ll look up a previous post I had on how to concatenate certificates to achieve this (pretty much you have your certificate and attach to it the certificates of each public certification authority above it.)
Here is the code needed on NginX:
ssl_stapling on;ssl_stapling_verify on;resolver 188.8.131.52 184.108.40.206 valid=300s;resolver_timeout 10s;
Do keep in mind we are using Google’s resolvers for this. You can use other DNS resolvers if you prefer.
Here is a sample report from SPDYCheck.org:
Strict-Transport-Security: max-age=86400; includeSubdomainswhich tells the web browser to always use SSL to access this website for the next 1 days.