Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Has anyone had any luck configuring Passenger and nginx with SSL? I've spent hours trying to get this configuration working as I'd like, using what few resources there are out there on the net, and I can't get any of the supposedly forwarded headers to show up in the Rails controller.

For example, with a conf file of the following (and multiple variations thereof):

server {
    listen 3000;
    server_name .example.com;
    root /Users/website/public;
    passenger_enabled on;
    rails_env development;
}

server {
    listen 3443;
    root /Users/website/public;
    rails_env development;
    passenger_enabled on;

    ssl                  on;
    #ssl_verify_client    on;                                               
    ssl_certificate      /Users/website/ssl/server.crt;
    ssl_certificate_key  /Users/website/ssl/server.key;
    #ssl_client_certificate /Users/website/ssl/CA.crt;                                                                              
    ssl_session_timeout  5m;

    ssl_protocols  SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP;

    proxy_set_header         Host             $http_host;
    proxy_set_header         X-Real-IP        $remote_addr;
    proxy_set_header         X_FORWARDED_PROTO https;
    proxy_set_header         X-Forwarded-For  $proxy_add_x_forwarded_for;
    #proxy_set_header        X-SSL-Subject    $ssl_client_s_dn;             
    #proxy_set_header        X-SSL-Issuer     $ssl_client_i_dn;             
    proxy_redirect           off;
    proxy_max_temp_file_size 0;
}

and Rails code in the controller like this:

request.headers.each { |k, v|
  RAILS_DEFAULT_LOGGER.error "Header #{k} Val #{v}"
}

other headers appear, but not those set in nginx, e.g.:

Header rack.multithread Val false
Header REQUEST_URI Val /login/new
Header REMOTE_PORT Val 64021
Header rack.multiprocess Val true
Header PASSENGER_USE_GLOBAL_QUEUE Val false
Header PASSENGER_APP_TYPE Val rails
Header SCGI Val 1
Header SERVER_PORT Val 3443
Header HTTP_ACCEPT_CHARSET Val ISO-8859-1,utf-8;q=0.7,*;q=0.7
Header rack.request.query_hash Val 
Header DOCUMENT_ROOT Val /Users/website/public

I've even gone so far as to modify Passenger's abstract_request_handler's main_loop method, i.e.,

headers, input = parse_request(client)
if headers
  if headers[REQUEST_METHOD] == PING
    process_ping(headers, input, client)
  else
    headers.each { |h,v|
      log.unknown "abstract_request_handler: #{h} = #{v}"
    }
    process_request(headers, input, client)
  end
end

only to find that the supposedly added headers do not exist there either:

abstract_request_handler: HTTP_KEEP_ALIVE = 300
abstract_request_handler: HTTP_USER_AGENT = Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5
abstract_request_handler: PASSENGER_SPAWN_METHOD = smart-lv2
abstract_request_handler: CONTENT_LENGTH = 0
abstract_request_handler: HTTP_IF_NONE_MATCH = "b6e8b9afbc1110ee3bf0c87e119252ad"
abstract_request_handler: HTTP_ACCEPT_LANGUAGE = en-us,en;q=0.5
abstract_request_handler: SERVER_PROTOCOL = HTTP/1.1
abstract_request_handler: HTTPS = on
abstract_request_handler: REMOTE_ADDR = 127.0.0.1
abstract_request_handler: SERVER_SOFTWARE = nginx/0.7.61
abstract_request_handler: SERVER_ADDR = 127.0.0.1
abstract_request_handler: SCRIPT_NAME = 
abstract_request_handler: PASSENGER_ENVIRONMENT = development
abstract_request_handler: REMOTE_PORT = 64021
abstract_request_handler: REQUEST_URI = /login/new
abstract_request_handler: HTTP_ACCEPT_CHARSET = ISO-8859-1,utf-8;q=0.7,*;q=0.7
abstract_request_handler: SERVER_PORT = 3443
abstract_request_handler: SCGI = 1 
abstract_request_handler: PASSENGER_APP_TYPE = rails
abstract_request_handler: PASSENGER_USE_GLOBAL_QUEUE = false

I'm tired of banging my head against the wall, so I'd truly appreciate any help I can get!

share|improve this question

5 Answers 5

Passenger 3 implements this feature with a new directive passenger_set_cgi_param which behaves like proxy_set_header.

For example, to pass SSL variables to Rack, you could do this:

server {
  listen 443 default ssl;

  # other SSL stuff goes here
  # other passenger stuff here

  passenger_set_cgi_param  X_FORWARDED_PROTO       https;
  passenger_set_cgi_param  X-SSL-Raw-Cert          $ssl_client_raw_cert;
  passenger_set_cgi_param  X-SSL-Cert              $ssl_client_cert;
  passenger_set_cgi_param  X-SSL-Client-S-DN       $ssl_client_s_dn;
  passenger_set_cgi_param  X-SSL-Client-I-DN       $ssl_client_i_dn;
  passenger_set_cgi_param  X-SSL-Client-Verify     $ssl_client_verify;
}

You would then have access to X-SSL-Raw-Cert and the others headers in the Rack::Request instance (accessible from #request in your controller).

It's as yet undocumented but here is some more info:

share|improve this answer

Passenger is not the same as proxying, it uses SCGI in some fashion. The only work around I've come up with is to proxy back through nginx on a different (protected) port. It far from ideal but it does work.

share|improve this answer
    
That's a good workaround but Passenger 3 implements this serverfault.com/questions/39159/… –  Dave Nolan Sep 21 '10 at 15:13

Never used nginx with passenger, but maybe this article helps.

share|improve this answer
    
Thanks for your response, Javier. I did find that page and had used it in the setup process. It seems everything is working, except that the headers I'm trying to get are not appearing in Passenger (which leads me to believe that this is an nginx issue). This is important because the end-game is to use client certificate authentication, so I need to pass along to my Rails app the subject of the presented client certificate. Thanks again! –  JackOfAllTrades Jul 14 '09 at 19:58

Hummm... Do you happen to have a location directive where proxy_set_header is used once again ?

I'm asking because array directive like fastcgi or proxy_set_header are not inherited from a higher level when they are modified at a lower level. Since you declare your proxy_set_header at server level, any other proxy_set_header directive at a lower level like "location" for instance will clean-up everything declared so far for this level except your lastest directive.

share|improve this answer

I recommend adding your "star" to passenger issue 371. http://code.google.com/p/phusion-passenger/issues/detail?id=371

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.