6

I am trying to force all http requests to https requests and I am facing the problem as elastic load balancer not populating x-forwarded-proto header in the request.

This is the code I am using and it is causing redirect loop because of this. How would I fix this problem?

app.use (function (req, res, next) {
    console.log('Request headers = ' + JSON.stringify(req.headers));
    console.log('Request protocol = ' + JSON.stringify(req.protocol));
    var schema = (req.headers['x-forwarded-proto'] || '').toLowerCase();
    if (schema === 'https') {
       next();
    } else {
       res.redirect('https://' + req.headers.host + req.url);
    }
});
user883499
  • 468
  • 1
  • 7
  • 16

2 Answers2

13

It sounds like your ELB listeners might be configured for TCP instead of HTTP. Configured for TCP, it will not add X-Forwarded-Proto or X-Forwarded-For.

Michael - sqlbot
  • 169,571
  • 25
  • 353
  • 427
1

Send http and https requests to two different ports. If the request comes through on the http port, you would be safe to redirect it.

datasage
  • 19,153
  • 2
  • 48
  • 54
  • You mean two ports and then two http servers in `app.js`? Actually this is all automatically configured by the EBS and load balancers. That is the problem. – user883499 Sep 27 '13 at 13:14
  • What do you mean by automatically configured? Are you using elastic beanstalk? If you have created the load balancer, you can configure the listeners in any way you want. – datasage Sep 27 '13 at 13:16
  • Ok, i configured the listeners on different ports already. http on 80 and https on 443. How do I use this information in my `app.js`. I meant after configuring those listeners everything else is automatically done by EBS and the load balancer. – user883499 Sep 27 '13 at 13:18
  • The problem is that both https and http come to the app.js as http requests. And the https requests are interecepted and decrypted by the load balancer and it is all http after that. – user883499 Sep 27 '13 at 13:25
  • Am I missing something obvious here? – user883499 Sep 27 '13 at 13:36
  • This is my Port Configuration in the load balancer: 80 (TCP) forwarding to 8080 (TCP) , 443 (SSL, Certificate: xyzabc) forwarding to 8080 (TCP) – user883499 Sep 27 '13 at 13:49
  • Skip the forwarding on port 80, and redirect it immediately. I presume you are using some sort of web server in front of node? – datasage Sep 27 '13 at 13:53
  • Forwarding is done by EBS(load balancer) to the app instance on the port(process.env.PORT) that the express app is listening on. There is no way that I know where I can redirect it on EBS or load balancer. I did not configure any web server in front of node because that is the whole point of of EBS. To avoid all those complexities of HAProxy/nginx so on. Amirite? – user883499 Sep 27 '13 at 14:02
  • EBS means elastic block store in EC2. I think you are referring to ELB (elastic load balancer). You can forward your elb listeners to seperate ports, and put something on the http port which has the sole job of forwarding to the https port. Something like nginx that redirects every single request would work fine here. – datasage Sep 27 '13 at 14:06
  • @datasage, can you explain more about how you might do this: "You can forward your elb listeners to seperate ports, and put something on the http port which has the sole job of forwarding to the https port" - I'm a total noob to AWS and ELB but am coming across the same problem here and a solution that could be implemented in the load balancer as opposed to the web server would be very helpful – 1800 INFORMATION Mar 20 '14 at 22:14
  • 2
    @1800INFORMATION The solution needs to be implemented in both the ELB and web server. On the web server, you would define two virtual hosts listing to different ports (something like 80 and 81). The virtual host on port 80 would redirect all traffic to https which would then come to the normal site on port 81. – datasage Mar 20 '14 at 22:18