Need SSL state to be visible behind a double nginx proxy

Nick Pearson nick.pearson at
Thu Oct 30 00:26:30 MSK 2008

Thanks for the suggestion.  I gave it a try, but it didn't work.  Is
there a difference between the two in the way the upstream server
handles X_FORWARDED_PROTO and X-FORWARDED_PROTO?  I'm using the
version with the underscore instead of the hyphen, and it works when
the client machine hits the back-end nginx server directly.

I know this because I hit the five-IP limit after setting up four
sites on the slice, two of which are running on the CMS app I wrote
(the other two are admin apps that use SSL).  The SSL detection in the
Rails code works fine for those first two sites, but the sites that
are proxied through another front-end nginx instance on a separate
slice are the ones where the SSL detection does not work.


On Wed, Oct 29, 2008 at 4:12 PM, Adam Zell <zellster at> wrote:
> Try: proxy_set_header X-FORWARDED_PROTO $scheme;
> Note the hyphen after 'X' instead of an underscore.
> On Wed, Oct 29, 2008 at 1:14 PM, Nick Pearson <nick.pearson at>
> wrote:
>> Hi,
>> I have what I think is an obscure problem to which I cannot find a
>> solution in the nginx docs.  Here's a summary of the problem:
>> I have a content management system that I wrote (using Rails), and it
>> hosts several sites.  Each site has SSL, and due to a policy limit by
>> my hosting provider, each virtual server ("slice") can only have five
>> external IP addresses.  This creates a problem in that the CMS that
>> was built to host lots of sites is limited to hosting only five.  My
>> solution was to set up smaller slices in front of the main server, and
>> the small slices would run nothing but nginx.  As such, the
>> "front-end" nginx instances would proxy requests to the "back-end"
>> nginx, and the "back-end" nginx would proxy requests through to the
>> Rails app server instances.
>> I saw a recent post on SSL pass-through, but this is not what I'm
>> looking for.  As the slices are on the same network at my hosting
>> provider, I don't care that the slice-to-slice communications are
>> encrypted.  This is not an issue.
>> What is an issue is that the application (and thus the Rails app
>> server instances) need to be able to determine whether a request came
>> in using SSL or not.  Because requests are proxied through two
>> instances of nginx running on separate slices, the back-end nginx
>> cannot see whether a request came in over http or https -- because
>> either way, the request arrived at the back-end nginx over http (not
>> https).  Here is a simple depiction of two requests -- one over http
>> and one over https:
>>    client ---http---> nginx ---http---> nginx ---> rails
>>    client ---https--> nginx ---http---> nginx ---> rails
>> As you can see, it is the second (back-end) nginx instance in the
>> chain that tells the Rails app server instances whether the request
>> made to nginx was over http or https.  And since all requests to the
>> second nginx instance are made over http, it passes this on to the
>> Rails app, which thinks all requests are made over http even if the
>> communication between the client and the first (front-end) nginx is
>> over https.
>> Also worth noting is that there are no SSL errors.  If the request is
>> made over http, it works.  And if the request is made over https, it
>> works.  The app server just doesn't know whether a request was made
>> over http or https.
>> I attempted to set the following on the back-end nginx:
>>    proxy_set_header  X_FORWARDED_PROTO  $scheme;
>> but not surprisingly, it doesn't work.  ($scheme is either "http" or
>> "https", taken directly from the request.)  I may have a solution to
>> the problem, but it will require some extra plumbing work in Rails to
>> make it functional.  What I am able to do is to set a custom header
>> and then read the value of that header in the Rails code.  Here is
>> what I've tried:
>>    proxy_set_header  HTTPS  on;
>> Then, in the Rails code, I can look for the HTTP_HTTPS environment
>> variable.  (nginx apparently prepends anything sent to
>> proxy_set_header with "HTTP_".)  While this solution will probably
>> work, I would prefer to have nginx pass the request scheme to the app
>> servers without having to change the internals of Rails (by rewriting
>> the request.ssl? method).
>> This could be accomplished if nginx would let me conditionally set a
>> header based on the value of another header.  I just can't figure out
>> how to read a header.  Here's what I would like to do -- keep the
>> "proxy_set_header HTTPS on;" (above) on the front-end nginx and use
>> the header on the back-end nginx -- like this:
>>    if ($HTTP_HTTPS = on) {
>>        proxy_set_header  X_FORWARDED_PROTO  https;
>>    }
>> I realize that this means that anyone could arbitrarily add this
>> header to a request and trick the Rails server into thinking the
>> request was secure when it was not, but I would solve this by setting
>> "ignore_invalid_headers on;" or similar on the front-end nginx.
>> Can anyone tell me whether it is possible to read custom headers and
>> to act on them as in my example above?  If not, I think this would be
>> a great addition.
>> Thanks in advance.
>> Nick Pearson
> --
> Adam
> zellster at

More information about the nginx mailing list