What I wanted to do

To begin with, let me lay down what this article is about and what it is not.

Here is a web server setup that I want to use with HTTPS -

| OS | Ubuntu 16.04.1 |
| Proxy Server | Nginx |
| Web App | NodeJS (Express) |

I have this url shortener running on port 4000,
and hence my nginx config looks like this -

server {
    listen 80;
    server_name cb.lk;

    location / {
        proxy_pass http://127.0.0.1:4000/;
    }
}

What my requirements were -

  • Generate an SSL certificate for the domain cb.lk
  • Make the SSL work with my site, if viewed over https

I am concerned with the most basic functionality, of just having an SSL certificate
and a working HTTPS connection.
I am not concerned with adding enhanced security features much, and the setup I
am going to describe below, still has many holes to plug. (But anyway there are
way too many security holes, other than my transport layer, so I do not really care).

Generating an SSL certificate for free

Letsencrypt (Stylised as Let's Encrypt) is a non-profit
Certification Authority. They are doing good work for the community, and you should
donate to them ,
to help them continue, if you can.

To generate a letsencrypt certificate, you can simple install it using apt-get in Ubuntu
(It's already there in xenial packages).

sudo apt install letsencrypt

After that we will generate a few files that letsencrypt checks to see if you really own the server or not.
Now, you need to perform this step from a folder that is (or can emulate) the webroot of your website.
In my case, it is a NodeJS app, so I do not have a docroot per se. So here's what I do; I will run this command
(NOTE: Do not actually run it right now)

letsencrypt certonly --webroot -w . -d cb.lk -d www.cb.lk
  • -w : signifies your webroot (using the root of my project)
  • -d : signifies domain, and I add both cb.lk and www.cb.lk

After this, you'll see a folder .well-known getting generated where you ran the command.

BUT WAIT, before I run this command, I need to make sure this folder that will get generated,
will be available over my server. So, what I do is this -

In my NodeJS app's express configuration I have to add this line, so the
.well-known folder gets statically served.

app.use('/.well-known', express.static(__dirname + "/.well-known"));

Then I restart my nodejs webapp, and then I actually run the command I showed earlier -

letsencrypt certonly --webroot -w . -d cb.lk -d www.cb.lk

Configure

Now my certificate is generated, but the following tasks are left.

  • Use cb.lk over port 443, with ssl
  • Add the path of the ssl certificate in nginx config

So first, I create a new file /etc/nginx/snippets/ssl-cb.lk.conf
The contents of that file are -

ssl_certificate /etc/letsencrypt/live/cb.lk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cb.lk/privkey.pem;

(Replace cb.lk with your site's domain record ofcourse)

And then edit the nginx config /etc/nginx/sites-available/cblk.conf to this

server {
    listen 80;
    listen 443 ssl http2;
    server_name cb.lk;

    include snippets/ssl-cb.lk.conf;

    location / {
        proxy_pass http://127.0.0.1:4000/;
    }
}

Check syntax of nginx configs with sudo nginx -t
If all good, restart nginx

sudo service nginx restart

And there you go. Both http://cb.lk/admin and https://cb.lk/admin are active