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!

2
  • 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...) Apr 26, 2013 at 0:56
  • Interesting, I'll look into that. Why do you think I shouldn't get rid of www?
    – jwerre
    Apr 26, 2013 at 2:54

3 Answers 3

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.

0
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

4
  • 5
    Should definitely use return over rewrite. Upvoted. May 27, 2016 at 15:08
  • 5
    You can use $host instead of $server_name
    – Yossi
    Mar 7, 2018 at 20:12
  • does not work with server_name _; so one should use $host variable as @Yossi suggested. Jun 20, 2019 at 15:22
  • I wonder can we use $scheme here?
    – hiveer
    Feb 19, 2021 at 4:37
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.

2
  • I guess that would explain why $server_protocol always returns HTTP
    – jwerre
    Apr 26, 2013 at 16:43
  • So you answered why this is happening... any suggestions on how to fix?
    – jwerre
    Apr 26, 2013 at 16:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .