Need SSL state to be visible behind a double nginx proxy

Nick Pearson nick.pearson at gmail.com
Thu Oct 30 07:12:10 MSK 2008


Hi Rob,
Thank you very much for the suggestions.  The first one isn't really an
option due to the caching that the CMS does (not, that is, without some
serious rework regarding how the cached files are written and deleted).
 However, your second solution has a lot of promise.  I do have one question
on it, though.

Because of the caching, each site that runs on my CMS has its own nginx
config file, each with two server directives -- one for http and one for
https.  Using your solution, this would remain the same, except that instead
of listening for port 443, the https server directive would listen on some
other port.  My initial tests show that I can use this for one server
directive (the http one):

    server_name: www.domain.com;

and this for the other (the https one):

    server_name: www.domain.com:1234;

I can't find any documentation or examples that say whether specifying a
port with the host name in a server_name directive is valid.  I'll need to
do some more testing to be sure it works as I believe it does.  Do you know
if this usage of host:port is valid for server_name?  If so, then I believe
your second solution will solve my problem.  Thanks!

Nick


On Wed, Oct 29, 2008 at 7:26 PM, Rob Schultz <rschultz7 at gmail.com> wrote:

> Hi Nick,
>      Why don't you simplify your setup. You can have your Rails App running
> on your big server without needing nginx on it at all. All you do is open up
> the rails instances to allow access from your nginx frontends and then proxy
> the requests to it. Instead of having to proxy to nginx and then proxying
> again.
>
>      Or the other option you can do is on your nginx server that proxy's to
> your rails app. Have 2 server directives that listen on two different ports.
> Then when non-ssl traffic comes into your frontend server and redirect it to
> server 1, which has your standard proxy_pass. Then on your frontends have
> your ssl portion of the server redirect to the 2nd server port on the
> backend that sets the  X_FORWARDED_PROTO to https manually.
>
> Rob
>
> On Wed, Oct 29, 2008 at 3:14 PM, Nick Pearson <nick.pearson at gmail.com>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
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://nginx.org/pipermail/nginx/attachments/20081029/8f92d0f5/attachment.html>


More information about the nginx mailing list