13
- February
2017
Posted By : Sunny Srinidhi
Secure your web app with free and valid SSL (Nginx, Ubuntu, Let’s Encrypt)

HTTPS is now the standard. If you are an online service provider, getting an SSL certificate for your web app is a no-brainer. If you want your users to trust you, you need to get yourself one of those. Even otherwise, to secure the data you hold, it is important to provide the basic security that the HTTPS protocol provides. If you are not sure what it is, you can check out this Wikipedia page. This is a technical topic, and if you are coming here to learn how to secure your web app with an SSL certificate, it is better if you know your way around a computer and your cloud machine (you’ll be doing everything in a terminal window, so knowing how to use one is important as well).

Ideally, you need to buy an SSL certificate from the very many providers out there. You can actually create your own certificate as well, but it wouldn’t be trusted by everyone. But there’s an easy, legal, legitimate, and valid way to get a free SSL certificate which is as good as a certificate you’d buy. But anything free would have a catch, you’d think. The only big drawback I see here is that the certificate is valid only for 90 day, you’ll have to renew it after that. But you can automate that as well, as we’ll see later in this post.

I have tested this on Ubuntu 16.04 and Nginx on an AWS micro instance, with two different web apps. This blog is one of them. So you can see it’s working. The version of Nginx is not really very important, just make sure you are the latest version. Let’s get started then.

Let’s Encrypt

Remember I told you that you need to buy your certificate from a provider? Well, Let’s Encrypt is one of those, and it is relatively a new Certificate Authority (CA). These people give certificates for free so that you can secure your web servers for free. Good people Anyway, according to the research that I’ve done, they have automated the whole process of getting a certificate, downloading it, and configuring it to work on your server – only for Apache web servers. But I prefer Nginx. So it takes a bit more work to get this working than Apache would require.

Assumptions

  1. You have an Ubuntu (16.04) instance.
  2. A non-root user with sudo privileges is set up.
  3. You already have a registered domain (not necessary – you can use the public IP or the DNS provided by Amazon AWS).
  4. You can created an A Record pointing that domain to the public IP of you AWS instance.

Let’s get started

Step 1. Update apt indexes and install the letsencrypt client. To do this, execute the following commands in a terminal:

$ sudo apt update

$ sudo apt install letsencrypt

Step 2. Configure Nginx to serve the ./well-known location. Let’s Encrypt requires that you serve the ./well-known route, so that it can validate your domain. So you need to add this as a ‘location’ block in your Nginx configuration. For this, open your Nginx configuration file in a text editor of your choice. By default, the file is located at /etc/nginx/sites-available/default. Use the following command to open the file using vim:

$ sudo vim /etc/nginx/sites-available/default

Add the following inside the server block in the configuration file:

location ~ /.well-known {
    allow all;
}

Save the file and exit. Now, restart the Nginx service with the following command:

$ sudo service nginx restart

Now, try if you are able to access the ./well-known route from your browser. If there’s any error, your browser will let you know. I found that in some cases, creating the ./well-known directory in your document root helps. So if you get a 404, try doing that.

Step 3. Now let’s get the certificate. For this you need to know the document root of your project. Let’s assume for now that it’s located at /var/www/html. With this information, you can get the certificate with the following command:

$ sudo letsencrypt certonly -a webroot --webroot-path=/var/www/html -d example.com -d www.example.com

Replace example.com and www.example.com with your domain name. Once you run this command, you’ll ideally get two prompts. One to enter your domain name again, and the other to accept the terms and conditions. Complete these two; and if everything went well, you’ll get a success confirmation message on your terminal. In the confirmation message, you’ll also get the path to a fullchain.pem and privatekey.pem. Note the path to these two file, you’ll need them later.

Step 4. After this, it’s good to increase your security with a Diffie-Hellman group. Do generate a 2048 bit group, run the following command:

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Step 5. Now let’s create a config file to tell Nginx where to look for the .pem files for the certificate. We’ll do this in a new file, where we will save only the snippet required for the SSL certificates. Create a file like below:

$ sudo vim /etc/nginx/snippets/ssl-example.com.conf

Add the following lines in the file:

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Replace the paths to the .pem files with the paths you copied earlier. Save and exit.

Step 5. We’ll now have to create another similar configuration file to store the configuration for the DH group we created earlier. For this, create a file like this:

$ sudo vim /etc/nginx/snippets/ssl-params.conf

Add the following configuration to the file:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Save and close the file.

Step 6. Now you’ll have to add some more configuration to your Nginx vhost file. Let’s open it up again:

$ sudo vim /etc/nginx/sites-available/default

You can remove the lines which tell Nginx to listen to port 80. Instead of that, we’ll now be listening to port 443, because that’s where we want our HTTPS to work. You’re new configuration inside the server{} block should look like this:

listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;

Now, we have make sure that people will still be able to use the web app without having to manually add “https://” in the URL. For this, we’ll listen to port 80 (or http://) and then redirect the request to https://. For this, you’ll have to add a second server{} block in the same configuration block. You can use the following snippet for that, just replace example.com with your domain name.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

You’re all set. You just need to restart Nginx once and your new SSL certificate should now be working. Run the following command:

$ sudo service nginx restart

Step 7. Remember I told you this certificate is valid only for 90 days? Well, that means you’ll have to renew it every 90 days to make sure your server is secure. You can do this manually by running just one command, without any kind of extra configuration. But there’s a better and easy option, just setup a cron job and let the computer handle this for you. For this, open up your crontab with the following command:

$ sudo crontab -e

Now add the following at the end of the file:

30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx

DONE! You now have a valid SSL certificate for your server and it’s set to auto-renew itself every 90 days, without you having to worry about anything else.

As a bonus, you can check the rating of your SSL certificate and how secure it is by using a free tool. Go to the following URL in your browser (and remember to replace example.com with your domain name):

https://www.ssllabs.com/ssltest/analyze.html?d=example.com

Below is a screenshot of what I got for this blog.

Leave a Reply