我想让我的API控制器使用SSL,所以我在我的nginx.conf中添加了另一个listen指令
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;
}
通过nginx conftest没有任何问题。我还在我的ApiController中添加了force_ssl
指令
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
在我没有使用SSL时工作得很好,但现在当我尝试curl --LI http://foo/api/auth.json
时,我被正确地重定向到https
,但随后我继续被重定向到http://foo/api/auth
以无限重定向循环结束。
我的路线只有
get "api/auth"
get "api/check"
我在Ruby 1.9.2上使用Rails 3.2.1,nginx为0.7.65
答案 0 :(得分:122)
您不会转发有关此请求是否为HTTPS终止请求的任何信息。通常,在服务器中,“ssl on;”指令将设置这些标题,但您使用的是组合块。
Rack(和force_ssl)通过以下方式确定SSL:
有关完整故事,请参阅the force_ssl source。
由于您使用的是组合块,因此您需要使用第三种形式。尝试:
proxy_set_header X-Forwarded-Proto $scheme;
在您的服务器或位置区per the nginx documentation。
当您进入端口80请求时,这会将标头设置为“http”,并在您收到443请求时将其设置为“https”。
答案 1 :(得分:21)
尝试在nginx location @unicorn
块中设置此指令:
proxy_set_header X-Forwarded-Proto https;
我遇到了同样的问题并且调查了Rack中间件处理程序(不是force_ssl
但是类似)我可以看到它期望设置标头以确定请求是否已经被nginx处理为SSL。