10

I'm pretty stuck with this thing for couple of hours. No way I could make it working. I tried everything I can think of and/or found online.

So, my application is pointed to ELB (web). ELB listens to 80 and 443 and sends traffic to 80 (SSL is terminated here) to member instance(s) which is nginx.

Nginx proxies app requests to another ELB (app) in front of multiple instances. These instances run puma.

Everything works fine except when I try visiting an URL (where I used force_ssl for that controller) with https scheme, I get a redirection loop.

Here is my nginx configs look like

  location @{{app_name}} {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
    proxy_pass http://{{app_name}};
    # limit_req zone=one;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
  }

(Obviously app_name gets substituted by ansible.)

Instead of $scheme, I tried hardcoding https and $proxy_add_x_forwarded_proto but none worked for me. I still get the loop.

Then I started inspecting the env in the rails and I see the following values regardless of header I set in nginx config.

"SERVER_PROTOCOL"=>"HTTP/1.1",
"HTTP_X_FORWARDED_PROTO"=>"http",
"rack.url_scheme"=>"http",

I'm not sure what I'm doing wrong. Any help appreciated! Note: I've already checked all found SO threads and none helped!

HungryCoder
  • 7,506
  • 1
  • 38
  • 51
  • Ok, I have new information. If I proxy the requests from nginx directly to one instance rather than via app ELB, I see everything is perfectly working ( `"HTTP_X_FORWARDED_PROTO"=>"https",` in rails). So, it means ELB is stripping that header. Could it be related to that fact that app ELB listens to 80 and sends to 8080 and that's why aws stripping that header? – HungryCoder Aug 25 '15 at 01:28

2 Answers2

1

I found a solution that works (though I'm not sure if it's right).

ELB Listener Settings

So if I setup TCP listener on 8080:8080 and use this from nginx's upstream settings, everything is working fine. That means web instances are connecting to app ELB on TCP 8080. I see the X-Forwarded-Proto is passed correctly.

I've also added listener to 80 as this ELB is used as cloudfront's origin which connects to 80.

HungryCoder
  • 7,506
  • 1
  • 38
  • 51
1

In case of SSL offload it makes sense to communicate via plain HTTP (80) and have rails config adjusted:

config/environments/production.rb

config.force_ssl = false

It helps to avoid a redirection loop and never use HTTPS internally between load balancer and application's Nginx server.

You also mentioned:

where I used force_ssl for that controller

Please use HTTPS everywhere on the website and redirect 80->443 on ELB layer.

Anatoly
  • 15,298
  • 5
  • 53
  • 77
  • There is no SSL communication between proxy and app servers (it's already terminated at ELB). But we need to know (from app) when user is visiting an https URL and when not. I appreciate your suggestion & post but that's not our use cases and I don't think what I'm trying to achieve which something is technically impossible! – HungryCoder Aug 26 '15 at 04:06