Force HTTPS behind Elastic Load Balancer on a NodeJS application
HTTPS is good. We all know this. So how to ensure only HTTPS traffic for your Express application that is hosted behind an Elastic Load Balancer?
HTTPS benefits
If you have not enabled HTTPS for your website yet, it is about time to do so. The benefits with HTTPS are just so incredibly good!
- Encryption for the end user
- Service worker can be enabled for most browsers, which is a must-have for Progressive Web Apps (PWA)
- Increased Google page rank
- Improved loading performance, if your webserver support HTTP2
- Cool browser label in the address bar which increases customer confidence
There are a lot of guides on how to do it, and getting a certificate is actually free if you use AWS Certifiate Manager, or other free Certificate Authorities like LetsEncrypt.
Forcing HTTPS on Express behind Elastic Load Balancer
Our stack uses Express on a NodeJS server, so this blog post is only focusing on Express. AWS have fine guides on how to redirect for other web servers, but none on Express unfortunatly.
Since Elastic Load Balancer forwards all traffic (both http and https) to the same port in our application, all the traffic internally in our application will be http. This is exactly what we want, but we must force the end user to only use https.
Elastic Load Balancer is nice enough to append an extra request header to the request (x-forwarded-proto) which tells us from which protocol the request originated from. We can use this in an Express middleware to do redirections:
function forceHttps(req, res, next) {
const xfp =
req.headers["X-Forwarded-Proto"] || req.headers["x-forwarded-proto"];
if (xfp === "http") {
res.redirect(301, `https://${hostname}${req.url}`);
} else {
next();
}
}
server.use(forceHttps);
NPM module
Since we don't want to write the middleware again and again for all our applications, we created a small NPM module that does just that.
This is how you use it:
const express = require('express');
const forceHttps = require('@crystallize/elasticloadbalancer-express-force-https');
const server = express();
server.use(forceHttps());
That's it! All your traffic will now be forwarded to https if the x-forwarded-proto=http. It will not do anything if the header is not present.