Setting up https/spdy communication for your website with nginx (another how I do it article)

An article, posted almost 5 years ago filed in , , , , , , , & .

In case you do something with user accounts on your website, you definitely want to make sure you’re using https. In general it protects the user’s privacy, also when just reading content on your website. The only thing that can be seen by a middleman is that the person is viewing something at your server, the rest is all encrypted. And since Google has started to rank https-websites higher it has even become a SEO technique :) ). This article explains you how to serve your pages over https.

Update: a better option exists nowadays for non-domain validated certificates: Let’s encrypt!

While the path to your server from someones desktop could be considered relatively ok in the past (harder to tap, putting a lot of trust in everything from the ISP to the internet exchanges and everything else in between), things have changed now. With unencrypted public WiFi-networks everywhere that can be relatively easy to tap, you’re more or less required to offer your visitors some level of privacy. Setting up HTTPS isn’t that hard to set up, and this posts explains how.

Setting up https/spdy communication for your website with nginx

Birds on wire. A public domain photo by Ansel Adams: Birds on wire, evening, Manzanar War Relocation Center, Owens Valley, California, 1943

So let’s get started. SSH to your server and generate a key (make sure you’re root). This key should stay private, and only your server should have access to it.

cd /etc/ssl
openssl genrsa 2048 > domainname.key

Based on this key, we can generate a certificate signing request (CSR), which allows us to obtain a certificate. A certificate is used by the browser to establish certainty about whether it is dealing with the correct server. Certificate Authorities check this in a more or less extensive way. Since both the certificate (indirectly through the CRT) and the data sent by the server to the browser have been generated with the same key.

openssl req -new -key domainname.key > domainname.key.csr

Fill in everything as good as possible, but we want to use these certificates for identifying domains, so it is very important that you fill in the common name with the FQDN, e.g. example.com.

You don’t necessarily need a password for the certificate request and not all parties accept CSR’s with a password.

Now you take the CSR to a certificate authority1. It probably involves some authentication steps, but how that works is beyond the scope of this post. The end result will be a certificate, again just a text file which I advice you to place in the same directory. So use vim or whatever to store…

vim domainname.crt

(assuming you’re still in the /etc/ssl directory). Then make sure no-one else can read it other than root:

chmod 600 domainname.*

And since we’re using nginx we need to configure nginx. I suppose you already have a site enabled, and hence we edit the code of this site.

vim /etc/nginx/sites-available/

We change the port we’re listening at to 443 (the typical port for HTTPS communications), so that the first lines read something along the lines of

listen 443 spdy;
server_name domainname www.domainname;

(yeah, we’re being a bit fancy here, in case it works with the browser, spdy is used, which is supposed to be faster than regular ssl)

Just after these lines (before the application specific lines) we write, make sure you set the paths to the certificates correctly:

ssl on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_certificate /etc/ssl/domainname.crt;
ssl_certificate_key /etc/ssl/domainname.key;

And since I typically don’t want duplicate content on both domainnames, we make sure the redirect is also fixed to forward to the https version (to prevent dual redirects).

if ($http_host = www.domainname) {
    rewrite ^/(.*) https://domainname.com/$1 permanent;
}

Next you maybe want to force SSL upon your user. So what I typically do (also to remove the www prefix etc) (you can place this bit at the end of the same file):

server {
    listen 80;
    server_name domainname www.domainname;
    rewrite ^/(.*) https://domainname/$1 permanent;
}

And finally, you may want to force Rails application to use SSL by setting the option config.force_ssl in your production environment (config/environments/production.rb) to true by uncommenting the by default commented line config config.force_ssl = true. That’s it.

1A free CA authority is StartSSL. Unlike what the interface of this website may suggest to you, their certificate is recognized by almost all browsers. But do make sure you also use their intermediate certificate that is used to sign the free certificates. How do I ‘use’ it, well simple: make sure you include the missing certificate in the certificate chain to your domainname.crt file. A way to get the full chain is to use Firefox’s export functionality when you click on the more info when inspecting the certificates. You can export the entire chain as a PEM file which is the way certificates are also used in NGINX. Just replace your single certificate with this file that contains all three certificates. If you’re able to recognize the StartSSL master certificate, you may delete that part, since that should be the known certificate to all parties involved.

Op de hoogte blijven?

Maandelijks maak ik een selectie artikelen en zorg ik voor wat extra context bij de meer technische stukken. Schrijf je hieronder in:

Mailfrequentie = 1x per maand. Je privacy wordt serieus genomen: de mailinglijst bestaat alleen op onze servers.