Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force requests over https in Express/Node

I have a Express.js (v 2.5.8) (node v0.6.12) server running on port 3100. It is front ended by Nginx, which proxies both http and https requests to port 3100.

I want to force certain urls over https. Here's an example (app is my Express server):

app.get('/applyNow', ensureSec, secure.showApplication );

ensureSec is the function that I'm trying to use to check if connection is over ssl:

function ensureSec(req, res, next) {
    if (req.session.ssl == true) { 
        return next(); 
    } else {
        req.session.ssl = true;
        res.redirect('https://' + url.parse(req.headers.referer).host +
        url.parse(req.url).pathname);
    }
}

The redirect works but node (after it times out) throws an error saying `Cannot GET /applyNow

What's the proper way of redirect to ssl?

like image 767
rob_hicks Avatar asked Mar 15 '12 11:03

rob_hicks


3 Answers

As I understand it, you are using nginx to negotiate SSL and proxying both http and https requests to your Express app. I would opt to solve this in nginx instead, if possible, but if nginx can't know which paths should be protected (i.e. only available through https) or you want to do this in your express app for some other reason, here is some information:

You should get the X-Forwarded-Proto from nginx, set to https only when the original protocol was https. Here's how you do this in nginx:

proxy_set_header X-Forwarded-Proto https;

I would also forward the Host header:

proxy_set_header Host $http_host;

In your express app, check for that, or redirect to the host in the headers and the requested path (express parses that to req.path so you don't have to):

function ensureSec(req, res, next) {
    if (req.headers['x-forwarded-proto'] == 'https') { 
        return next(); 
    } else {
        res.redirect('https://' + req.headers.host + req.path);
    }
}
like image 100
Linus Thiel Avatar answered Sep 19 '22 10:09

Linus Thiel


You can configure ssl port on your nginx server and proxy requests to node.js like other requests.

http://nginx.org/en/docs/http/configuring_https_servers.html

No need to change node.js app. Just configure 443 port on nginx with your certificates and proxy requests to node.js app.

like image 44
Vadim Baryshev Avatar answered Sep 21 '22 10:09

Vadim Baryshev


To add to what Peter Lyons has said, express mandates that you run only one server on a port. If you try to run two http servers on one port, it'll throw an EADDRINUSE error.

like image 35
almypal Avatar answered Sep 21 '22 10:09

almypal