A couple days ago I received a very welcome e-mail from the Let's Encrypt Closed Beta Invite Program. If you do not know what it is, get yourself informed, because this will be a market changer! In the e-mail was stated that my wish list of requested domains are whitelisted now. This means I can install the SSL[1] certificates and make my website available via HTTPS, or better enforce all HTTP[1:1] traffic through HTTPS[1:2]! Setting encryption in place.
Let me try to guide you in how to set it up. I will transform this blog into a secure setup.

Current situation

In the sites-available (symbolic linked in the sites-enabled) configuration folder of Nginx. There is now one file called 'mynameisvolkert.com'. This contains the following setup (stripped down to the core)

server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name .mynameisvolkert.com;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header HOST $http_host;
    proxy_set_header X-NginX-Proxy true;
    proxy_pass http://127.0.0.1:1223;
    proxy_redirect off;
  }
}

This is perfect to let Nginx be a reverse proxy and just redirect all HTTP traffic to the NodeJS server. In the current situation all SSL config was commented out. As you can see in the config there is one domains and this one has a wildcard, the ".";

  1. .mynameisvolkert.com

In real-life you can request my blog via these 2 url's. Keep in mind you need to request for all 2 a SSL certificate.

  1. mynameisvolkert.com
  2. www.mynameisvolkert.com

Installation

Login to your server, install Git and run the following commands:

$ git clone https://github.com/letsencrypt/letsencrypt
$ cd letsencrypt

Important checks, before you can continue!

  • Firstly; Stop all services that are running on port 80 (e.g. nginx)
$ sudo service nginx stop
  • Secondly; Domains that you are trying to register are able to be resolved. To verify this type;
$ dig -t ANY mynameisvolkert.com

The dig command should give results back, else the domain is not resolvable.

  • Thirdly; Do not register domains that are not whitelisted in the email you received.

To install and run the client you to run the following script. We need to set the rsa-key-size parameter, because we're going to apply a RSA 4096 bit key size. This is necessary to receive an A grade level. Common these days is RSA 2048. By default you don't have to set this parameter.

./letsencrypt-auto --agree-dev-preview --server https://acme-v01.api.letsencrypt.org/directory auth --rsa-key-size 4096

This will show the following screen, where you need to fill in all domains you try to register at once. In my case;

PS: This script needs to be executed every 90 days, because this is the lifespan of the certificates and after that period you simply need to renew them with running the same script. No other changes required.

The letsencrypt script put the .pem[1:3] files in this folder: /etc/letsencrypt/live/your-domain-name/. In the mean time you can temporarily start Nginx to serve the website(s) again until we're fully done.

$ sudo service nginx start

The next thing we need to do is bring the Diffie-Helman strength a level higher. Remember we asked for a RSA 4096 bit key size with the generation of certificates. To get started we will need to generate new dhparams[1:4] using OpenSSL[1:5] with the following command

BTW one, before starting this command you should be warned this is going to take a while to finish. - really long. It took my VPS with one core and 1GB of RAM more then 2 hours. Just create a background process for it and you can continue doing other stuff.

BTW two, that doing this will limit backwards compatibility with older browsers / system e.g. Internet Explorer 6/Windows XP.

$ nohup openssl dhparam -out /etc/ssl/private/dhparams_4096.pem 4096 &

When the script is finished, you will need to update your base Nginx config to use the new dhparams.

$ cd /etc/nginx/
$ sudo nano nginx.conf

Add and replace the following lines (Leave the rest of the config in place):

http {
  ##
  # SSL Settings
  ##
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_dhparam /etc/ssl/private/dhparams_4096.pem;
}

Now it's time to change the Nginx site configuration so that the domain is enabling SSL only, but before that I should tell you something about HTST[1:6]. Once the browser picks up on the HTTPS header, it will store the response and from that moment on, it only will communicate with the host using a secure transport layer for the duration of 'max-age' set in the header. To be fully HSTS compliant a host should only issue a HSTS header over a secure transport layer. This is because an attacker can maliciously strip out or inject a HSTS header into insecure traffic. For that reason, a browser should also disregard any HSTS headers received via HTTP, so technically it shouldn't matter if you do issue it over HTTP. Still, it's best to do it right. In your Nginx server block you need to add a new response header.

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

The 'max-age' values specifies how long, in seconds, you want the client to treat you as a HSTS host. The value is for one year and each time the client visits my site and receives the header, the timer is reset back to a year. Assuming your browser is HSTS compliant, after the first page load over HTTPS, you will no longer be able to communicate with me via HTTP, the browser will prevent it. The 'includeSubdomains' directive is fairly self explanatory.

HSTS, coupled with server side redirection from HTTP to HTTPS, offers a more robust implementation of SSL as the browser is now aware that you expect secure comms. If a Man In the Middle tries to strip out SSL from your communications by acting as a proxy, your browser will refuse the connection because it is expecting HTTPS and not HTTP. It's now time to edit the site configuration:

$ cd /etc/nginx/sites-available
$ sudo nano mynameisvolkert.com

The first & original server {} code block needs to be copied and should contain only the configuration which is shown below. This piece says, that all traffic requested hover HTTP is redirected to HTTPS and a permanently moved header is set. The second server {} code block is for the SSL configuration and contains more configuration then is shown. This should of course stay. Fill in your new configuration:

server {
  # http configuration
  #
  listen 80;
  listen [::]:80;
  server_name www.mynameisvolkert.nl mynameisvolkert.nl;
  return 301 https://$server_name$request_uri;
}

server {
  # SSL configuration
  #
  listen 443 ssl;
  listen [::]:443 ssl;

  # SSL certificate
  #
  ssl_certificate /etc/letsencrypt/live/your-domain-name/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/your-domain-name/privkey.pem;

  # HTST Header
  #
  add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

}

Save the configuration, test it! & then restart Nginx:

$ sudo nginx -t
$ sudo service nginx restart

We can test our work by browsing to "http://www.mynameisvolkert.com" and you should be redirected to https://ww... If you are using Google Chrome you should see a green slot before the url[1:7].

Last thing todo is to verify if we configured our SSL correctly with SSL labs

https://www.ssllabs.com/ssltest/

and YESSSS Whoeii!! Success!!!!

Print screen from https://www.ssllabs.com/ssltest/analyze.html?d=paapster.nl&s=149.210.178.217

PS: If you're happy with the result don't forget to donate a small amount to the Let's Encrypt Foundation for their great work so far!


  1. url = Uniform Resource Locator (commonly informally referred to as a web address, although the term is not defined identically[1]) is a reference to a web resource that specifies its location on a computer network and a mechanism for retrieving it ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎