Sign up ×
Server Fault is a question and answer site for 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;
    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 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)
    headers.each { |h,v|
      log.unknown "abstract_request_handler: #{h} = #{v}"
    process_request(headers, input, client)

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 =
abstract_request_handler: SERVER_SOFTWARE = nginx/0.7.61
abstract_request_handler: SERVER_ADDR =
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 5 replaces passenger_set_cgi_param with passenger_set_env and passenger_set_header: – jwadsack Jul 13 at 22:02

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… – 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.

share|improve this answer

Your Answer


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.