Moving my HTTP website to HTTPS using LetsEncrypt, HAProxy and Docker

George Jose
George’s thoughts
5 min readFeb 27, 2017

(The latest version of this post can be viewed at https://georgejose.com/moving-website-from-http-to-https/)

I’ve had a personal website hosted on an AWS EC2 instance with a domain purchased from Namecheap for a while now. My previous setup involved an express server serving a static directory, and running on port 80 on an AWS EC2 instance. I recently changed this up to instead use HTTPS and decided to write a post explaining how you can do so too!

What is HTTPS?

HTTPS builds upon the Hyper Text Transfer Protocol (HTTP) by adding encryption between the web-server and the user’s browser. Chrome, Safari and several other browsers show a lock icon (🔒) in the address bar when viewing a website served over HTTPS.

Chrome address bar when visiting a page secured over HTTPS

There are several advantages to using HTTPS:

  • Encryption between the browser and the server means a third party in the middle cannot see data being exchanged, ensuring privacy and security.
  • HTTPS also protects the integrity of your website by preventing service providers from modifying its contents (ever come across public hotspots that try to inject ads into webpages?).
  • HTTPS is the future and is required in order to enable certain modern web browser features such as camera / microphone access, progressive web apps that run offline, service workers etc.
  • Better search engine optimization (SEO). Search engines such as Google rank pages secured over HTTPS higher than pages that are not.

You can read more about why you should use https at https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https.

Technologies used

To set this up, I made use of a few technologies:

  • Docker
    Docker is a really cool piece of technology that enables you to create ‘containers’. Containers can contain applications along with anything else it needs to run — an OS, libraries, software dependencies, runtimes etc. Think of it as a very lightweight VM. Since all dependencies for an application are contained within the container, the application is guaranteed to run consistently on any host machine that can run Docker itself. You can read more about docker at their official website — https://www.docker.com/what-docker.
Docker
  • HAProxy
    HAProxy, or High Availability Proxy is a really popular load balancer and reverse-proxy application. In our setup, we’ll use this as a layer to proxy all requests received over HTTPS over to our web server serving static files. We’ll also set it up to redirect all HTTP traffic to HTTPS.
  • Let’s Encrypt
    Let’s Encrypt is a free, open Certificate Authority (CA) that can issue SSL certificates. We’ll use this service to generate a free SSL certificate.
Let’s Encrypt

Setup

This is what my setup looked like when I started

  • An Ubuntu 16.04 AWS EC2 server that I can SSH into.
  • A domain I bought from namecheap, configured to point to my AWS server.
  • A static express server serving HTML, CSS, JS.

Let’s go ahead and create two folders on our server to house files for our website and haproxy:

Docker

Let’s use the official docker install script to set up docker on our remote server. SSH in and enter the following commands to install docker.

Alternatively, you can also follow instructions at https://docs.docker.com/engine/installation/linux/ubuntu/.

Website

Create the following directory structure in order to keep things tidy. If you already have a website to serve, place it inside the publicfolder.

I used an npm package called http-server to serve my files. To set it up, simply include it in package.json and run npm install.

Running npm start and navigating to http://domain.com:3000 should now render our index.html page.

The next step is to tell docker how to build and run our application. We do this by editing the Dockerfile. You can read more about Dockerfiles at https://docs.docker.com/engine/reference/builder/.

Let’s try building and running this in docker by running the following commands:

🎉 If everything worked, you should now be able to view your website at http://domain.com (or http://localhost if you’re running it on your local machine).

Let’s Encrypt

Let’s now go ahead and request our SSL certificate using Let’s Encrypt. DigitalOcean has a fantastic guide on how to do this, do check it out if this section is not clear. Ensure that you already own a domain, and that the domain’s A Record is set to your server’s DNS. If you haven’t done this already, refer to your domain name provider’s documentation. SSH into your server and run the command to download the letsencrypt client.

In order to obtain an SSL certificate, we need to prove that we own the domain we are getting the certificate for. letsencrypt lets you do this by automatically placing a secret file in a specified folder which we will serve over the internet on our domain.

Let’s have two SSH terminals open. On one of them, let’s runhttp-server serve a folder we’ll call ssl.

Let’s use the other terminal to run the letsencrypt client.

You’ll be asked to provide an email address and to agree to terms and conditions. If everything worked, you’ll be greeted with a message that provides the location of your certificate.

👍 Congratulations, you now have an SSL certificate!

HAProxy

The final piece is to set up HAProxy. To keep things simple, we’ll use the official haproxy docker image to do this.

Let’s create the following folder structure:

Update Dockerfile to the following:

The haproxy.cfg file should look something like this:

Let’s test it out in docker by running:

Navigating to https://domain.com should now show you your website! Trying to access http://domain.com instead should automatically redirect you to https://domain.com.

Finishing up

Now that we have everything set up, we can run docker containers on our server in the background using the -d flag. This way our docker containers remain running even after we terminate our SSH session. In order to ensure our application is restarted with the host machine is restarted, or if it crashes due to an error, we’ll also use the --restart flag to specify restart behavior.

🎉 Congratulations! You now have a website served over HTTPS!

If you run into issues setting all this up, feel free to leave a comment, or check out my personal-website and haproxy set up on github.

--

--

George Jose
George’s thoughts

Senior Consultant @ Deloitte Digital. Mechatronics Engineer. Love all things Engineering, Tech & Web. https://georgejose.com