Redirecting to HTTPS in Node.js on Azure Websites

If you’ve got a node.js website running in Azure Websites, you get SSL by default, or if you bring your own domain name, you can easily set up SSL with your own certificate.

The default behaviour is that the website serves both HTTP and HTTPS requests, but what if you want to switch users automatically over to HTTPS (i.e. disable HTTP).

The normal approach when using express.js is to use some middleware which detects the protocol and redirects accordingly. Like this:

// this doesn't work in Azure Websites
function requireHTTPS(req, res, next) {
    if (!req.secure) {
        return res.redirect('https://' + req.get('host') + req.url);
    }
    next();
}

app.use(requireHTTPS);

req.secure is just a shorthand for checking the protocol of the incoming request. However, in Azure websites your server is fronted by a web server running ARR, which does the SSL termination. This means the request you see will always be HTTP. The above code samples creates a redirect loop as the middleware continues to redirect to HTTPS, as it keeps seeing HTTP.

Fortunately ARR adds some additional headers to the request. These are:

cookie: ARRAffinity=71111a2979a8796b0cc6860d7f98cb7519aaea861cc96f15896edbb25a259064
host: XYZ.azurewebsites.net
max-forwards: 10
x-liveupgrade: 1
x-arr-log-id: 7cffa211-21f6-42c2-8b7d-e9eacac8adc8
disguised-host: XYZ.azurewebsites.net
x-site-deployment-id: XYZ
x-original-url: /url
x-forwarded-for: 212.69.41.154:4219
x-arr-ssl: 2048|128|DC=com, DC=microsoft, DC=corp, DC=redmond, CN=MSIT Machine Auth CA 2|C=US, S=WA, L=Redmond, O=Microsoft, OU=OrganizationName, CN=*.azurewebsites.net 

The x-arr-ssl header is only added for HTTPS requests, so we can use this header to determine whether it’s a HTTP or HTTPS request.

function requireHTTPS(req, res, next) {
    if (!req.get('x-arr-ssl')) {
        return res.redirect('https://' + req.get('host') + req.url);
    }
    next();
}

app.use(requireHTTPS);

You could go one better, and only do the upgrade if you’re running in Azure, which means you can run your site in plain HTTP in your local environment:

function requireHTTPS(req, res, next) {
    if (req.get('x-site-deployment-id') && !req.get('x-arr-ssl')) {
        return res.redirect('https://' + req.get('host') + req.url);
    }
    next();
}

app.use(requireHTTPS);
Advertisements