Incorrect redirect protocol when behind a reverse proxy

Our nginx server is running on Heroku, which proxies SSL. This mostly
works fine, but nginx has one problem with it: since it thinks the
protocol
is http, any redirects (such as trailing-slash redirects) go to http
instead of https.

The usual fix for this is X-Forwarded-Proto, but nginx doesn’t support
that
yet, and I haven’t found any way to configure it, eg. a configuration
directive to override the protocol. Nginx seems to decide whether
redirects should go to http or https entirely based on whether the
connection has an SSL context associated (ngx_http_header_filter), so it
doesn’t look like there’s any way to affect this in configuration.

Is there any workaround?

On 24 Jul 2013 23:03, “Glenn M.” [email protected] wrote:

Our nginx server is running on Heroku, which proxies SSL.

What does this mean? Do you see SSL traffic, or do you mean heroku
terminates the ssl leaving you with http connections only?

This mostly works fine, but nginx has one problem with it: since it
thinks the protocol is http, any redirects (such as trailing-slash
redirects) go to http instead of https.

Show us some config that generates these redirects.

The usual fix for this is X-Forwarded-Proto, but nginx doesn’t support
that yet

That doesn’t make sense to me. What is there to support? You can just
write
your redirect directives using X-F-P instead of hard coding the scheme.

and I haven’t found any way to configure it, eg. a configuration
directive to override the protocol.
Nginx seems to decide whether redirects should go to http or https
entirely based on whether the connection has an SSL context associated
(ngx_http_header_filter), so it doesn’t look like there’s any way to
affect
this in configuration.

You’ve gone into the code far too early IMHO. There’s usually a way to
change nginx’s behaviour in config.

Is there any workaround?

Do all requests have x-f-p? 100%? Then just change your redirects to
reference it.

J

On Thu, Jul 25, 2013 at 5:11 AM, Jonathan M.
[email protected]wrote:

What does this mean? Do you see SSL traffic, or do you mean heroku
terminates the ssl leaving you with http connections only?

Heroku handles SSL, and nginx sees only HTTP traffic.

write your redirect directives using X-F-P instead of hard coding the
scheme.

I’m not hardcoding anything. Nginx is generating its own redirects.
The
case I’m seeing currently is ngx_http_static_module redirecting to add a
trailing slashes to URLs.

You’ve gone into the code far too early IMHO. There’s usually a way to
change nginx’s behaviour in config.

I’ve gone into the code precisely to find out how to do that, since the
documentation wasn’t helping. I was surprised to discover that the
protocol seems to be hardcoded.

Do all requests have x-f-p? 100%? Then just change your redirects to
reference it.

I don’t have any redirects. Nginx is doing this on its own.

On Thu, Jul 25, 2013 at 10:53 AM, Jonathan M.
<[email protected]

wrote:

On my phone’s browser, searching for that module name doesn’t bring me
anything useful I’m afraid. Are you just serving local files off disk?

src/http/modules/ngx_http_static_module.c. This is where the
trailing-slash redirects originate.

I bet you have redirects configured somewhere, or a backend is
generating them :wink:

Please post your entire config.

I don’t. It happens with a minimal configuration.

events { }
http {
server {
listen 10000;
root “data”;
}
}

mkdir -p data/test/, and then accessing “http://localhost:10000/test
redirects to “http://localhost:10000/test/”.

On 25 Jul 2013 15:43, “Glenn M.” [email protected] wrote:

On Thu, Jul 25, 2013 at 5:11 AM, Jonathan M. <
[email protected]> wrote:

What does this mean? Do you see SSL traffic, or do you mean heroku
terminates the ssl leaving you with http connections only?

Heroku handles SSL, and nginx sees only HTTP traffic.

This mostly works fine, but nginx has one problem with it: since it
thinks the protocol is http, any redirects (such as trailing-slash
redirects) go to http instead of https.

Show us some config that generates these redirects.

The usual fix for this is X-Forwarded-Proto, but nginx doesn’t support
that yet

That doesn’t make sense to me. What is there to support? You can just
write your redirect directives using X-F-P instead of hard coding the
scheme.

I’m not hardcoding anything. Nginx is generating its own redirects. The
case I’m seeing currently is ngx_http_static_module redirecting to add a
trailing slashes to URLs

On my phone’s browser, searching for that module name doesn’t bring me
anything useful I’m afraid. Are you just serving local files off disk?

I bet you have redirects configured somewhere, or a backend is
generating
them :wink:

Please post your entire config.

You’ve gone into the code far too early IMHO. There’s usually a way to
change nginx’s behaviour in config.

I’ve gone into the code precisely to find out how to do that, since the
documentation wasn’t helping. I was surprised to discover that the
protocol seems to be hardcoded.

Do all requests have x-f-p? 100%? Then just change your redirects to
reference it.

I don’t have any redirects. Nginx is doing this on its own.

In response to what class of request? What’s common across them?

J

On 25 July 2013 17:14, Glenn M. [email protected] wrote:

them :wink:
}
}

mkdir -p data/test/, and then accessing “http://localhost:10000/test
redirects to “http://localhost:10000/test/”.

I’ve just got to a box and can ACK that. I can make that stop with a
correctly configured try_files, which I would always choose to have
set up, myself. That may not be a solution for you however.

Here’s a way I’ve just tested (on 1.4.2) that forces the
trailing-slash redirects to incorporate a random HTTP header (“foo”,
here) as their scheme:

include your boilerplate as per previous email

location / {
location ~ “^(.*)[^/]$” {
rewrite ^ $http_foo://$http_host$uri/ permanent;
}
}

Or, supposing you have certain URIs which can end in
not-a-trailing-slash: (also tested on 1.4.2)

location / {
if (-d $document_root$uri) {
rewrite ^ $http_foo://$http_host$uri/ permanent;
}
}

I suppose the question is then: what other classes of automatic
redirects do you find yourself hitting, and can you deterministically
isolate their URIs using either a location{} or if{}, so that you can
pre-empt the auto redirect in order to incorporate the
X-forwarded-proto header?

HTH,
J

Jonathan M.
Oxford, London, UK
http://www.jpluscplusm.com/contact.html

On Thu, Jul 25, 2013 at 1:41 PM, Jonathan M.
[email protected]wrote:

location ~ “^(.*)[^/]$” {
}
}

I suppose the question is then: what other classes of automatic
redirects do you find yourself hitting, and can you deterministically
isolate their URIs using either a location{} or if{}, so that you can
pre-empt the auto redirect in order to incorporate the
X-forwarded-proto header?

Thanks, I’ll give these approaches a try. I don’t know where else this
might happen, though. Hopefully at some point I’ll be able to say
something like “override_protocol $http_x_forwarded_proto;” to tell
nginx
which protocol it’s really receiving a request on, since SSL
“offloading”
is fairly common these days
(Load Balancer - Amazon Elastic Load Balancer (ELB) - AWS,
etc).