2012-02-25 9 views
52

は、私は私のAPIコントローラの使用SSLを持つようにしたいので、私は別の問題なくnginxののconftestを渡し、私のnginx.confRailsアプリケーションでforce_sslを使用して無限リダイレクトループを取得するのはなぜですか?

upstream unicorn { 
    server unix:/tmp/unicorn.foo.sock fail_timeout=0; 
} 

server { 
    listen 80 default deferred; 
    listen 443 ssl default; 
    ssl_certificate /etc/ssl/certs/foo.crt; 
    ssl_certificate_key /etc/ssl/private/foo.key; 

    server_name foo; 
    root /var/apps/foo/current/public; 

    try_files $uri/system/maintenance.html $uri/index.html $uri @unicorn; 

    location @unicorn { 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Host $http_host; 
    proxy_redirect off; 
    proxy_pass http://unicorn; 
    } 

    error_page 502 503 /maintenance.html; 
    error_page 500 504 /500.html; 
    keepalive_timeout 5; 
} 

にディレクティブを聞く追加しました。私も自分のApiControllerにforce_sslディレクティブを追加しました私はSSLを使用していませんでしたが、今私はcurl --LI http://foo/api/auth.jsonしようとすると、私はきちんとhttpsにリダイレクトが、その後、私はリダイレクト取得し続けたときにうまく働いた

class ApiController < ApplicationController 
    force_ssl if Rails.env.production? 

    def auth 
    user = User.authenticate(params[:username], params[:password]) 
    respond_to do |format| 
     format.json do 
     if user 
      user.generate_api_key! unless user.api_key.present? 
      render json: { key: user.api_key } 
     else 
      render json: { error: 401 }, status: 401 
     end 
     end 
    end 
    end 

    def check 
    user = User.find_by_api_key(params[:api_key]) 
    respond_to do |format| 
     format.json do 
     if user 
      render json: { status: 'ok' } 
     else 
      render json: { status: 'failure' }, status: 401 
     end 
     end 
    end 
    end 
end 

無限のリダイレクトループで終了するhttp://foo/api/authになります。

私のルートは、単にRubyの上で、私はRailsの3.2.1を使用してい

get "api/auth" 
get "api/check" 

を持っているがnginxの0.7.65

答えて

106

このリクエストがHTTPSで終了するリクエストかどうかについての情報は転送していません。通常、サーバーでは、 "ssl on;"これらのヘッダーが設定されますが、結合ブロックを使用しています。

ラック(およびFORCE_SSL)でSSLを決定します。要求は(これはnginxのから戻ってユニコーンの可能性が渡されていません)ポート443上で来た場合

  • ENV場合は[ 'HTTPS'] == "HTTPS" == X-転送さ-プロトヘッダーの場合
  • "オン"

は完全な物語のためthe force_ssl sourceを参照してください。

結合ブロックを使用しているので、3番目のフォームを使用します。お試しください:

proxy_set_header X-Forwarded-Proto $scheme; 

お客様のサーバーまたは地域ブロックper the nginx documentationにあります。

これは、ポート80の要求を受け取ったときにヘッダーを "http"に設定し、443要求を受け取ったときにヘッダーを "https"に設定します。

+1

純粋な魔法。 :) 私の場合は、RailsサイトをVarnishを使用して移動していました。このサイトは純粋なHTTPSであり、VarnishはSSLをサポートしておらず、Passengerはポートではなくソケットを公開しているため、Narnxサーバーの2つの設定が必要でした。ポート443のHTTPS設定からPassengerソケット接続を離すと、リダイレクトループが発生しました。これで解決しました。ありがとうございました! –

16

と1.9.2あなたのnginx location @unicornブロックでこのディレクティブを設定してみてください:

proxy_set_header X-Forwarded-Proto https;

私はこの同じ問題を抱えていましたが、ラックミドルウェアハンドラ(force_sslではなくsimi lar)リクエストが既にnginxによってSSLとして処理されているかどうかを判断するためにヘッダーが設定されることを期待していました。

+4

これは、結合されたサーバーブロックであるため、すべての要求をSSL要求(ポート80の要求であっても)としてマークします。 –

+0

@ChrisHeald私はそれを修正する編集を提出しました。 –

関連する問題