14

I'm using a Rackspace load balancer which enables me to set up my ssl key/pem inside of the admin panel. Everything works fine, I can use both http and https protocols. But if I try to redirect http to https using:

server{
  listen *:80;
  server_name mydomain.com www.mydomain.com; 
  rewrite ^ https://mydomain.com$request_uri? permanent;

...I get a redirect loop. I realize I'm not listening to port 443 but that's because the load balancer handled that for me. I also tried wrapping the rewrite in if ($scheme ~* http){to no avail.

The other part of my question is that I'd like to remove www from the url, can I do this with a single rewrite? Shouldn't the above rewrite take care of this as well?

Thanks for your help!

jwerre
  • 768
  • 3
  • 12
  • 26
  • The load balancer should be sending some indication to you of whether the connection was HTTPS. Ask Rackspace. (Oh, and you probably don't want to get rid of www...) – Michael Hampton Apr 26 '13 at 00:56
  • Interesting, I'll look into that. Why do you think I shouldn't get rid of www? – jwerre Apr 26 '13 at 02:54

3 Answers3

27

By using nginx's built-in server variables $request_uri and $server_name you can do this without using regular expressions at all. Add the following to your server's location block and you're done:

if ($http_x_forwarded_proto = "http") {
    return 301 https://$server_name$request_uri;
}

This assumes your load balancer is sending the $http_x_forwarded_proto header along with the request to your backend instance(s). Other common headers include $http_x_forwarded_scheme and also just $scheme.

More information can be found in the nginx Pitfalls and Common Mistakes documentation : https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#taxing-rewrites

Luke Peterson
  • 507
  • 6
  • 14
15

sciurus is correct in that Rackspace's Cloud Load Balancers set the X-Forwarded-Proto to https when SSL is offloaded at the load balancer. In order to avoid a redirect loop in nginx, you should be able to add the following to the location section in the vhost configuration:

if ($http_x_forwarded_proto = "http") {
            rewrite  ^/(.*)$  https://mydomain.com/$1 permanent;
}

This should avoid the infinite redirect loop while redirecting non-https requests to https.

slade
  • 309
  • 1
  • 2
1

The load balancer always talks to you over http. What is happening is

  1. The browser makes a request to port 80 on the load balancer
  2. The load balancer makes a request to port 80 on your web server
  3. Your web server sends a redirect to the user
  4. The user makes a request to port 443 on the load balancer

Steps 2-4 keep repeating until the browser detect the redirect loop and gives up.

EDIT: To resolve this, only perform the rewrite when the X-Forwarded-Proto header is set to http. That header is how Rackspace's load balancer tells your web server the protocol via which it received the request.

sciurus
  • 12,678
  • 2
  • 31
  • 49