Почему я получаю бесконечный цикл перенаправления с помощью force ssl в своем приложении Rails?
Я хочу, чтобы мой контроллер API использовал SSL, поэтому я добавил еще одну директиву listen к моему nginx.conf
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 без каких-либо проблем. Я также добавил force_ssl директива моему ApiController
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"
Я использую рельсы 3.2.1 на Ruby 1.9.2 с nginx 0.7.65
2 ответов:
вы не пересылаете никакой информации о том, был ли этот запрос завершенным запросом HTTPS или нет. Обычно на сервере директива "ssl on;" устанавливает эти заголовки, но вы используете комбинированный блок.
Rack (и force_ssl) определяет SSL по:
- если запрос поступил на порт 443 (это, вероятно, не передается обратно в Unicorn от nginx)
- если ENV ['HTTPS'] = = "on"
- Если заголовок X-Forwarded-Proto == "HTTPS"
посмотреть источник force_ssl за всю историю.
Так как вы используете комбинированный блок, вы хотите использовать третью форму. Попробуйте:
proxy_set_header X-Forwarded-Proto $scheme;в вашем блоке сервера или местоположения в документации nginx.
это установит заголовок в "http", когда вы входите в запрос порта 80, и установите его в" https", когда вы входите в запрос 443.
попробуйте установить эту директиву в вашем nginx
location @unicornблок:
proxy_set_header X-Forwarded-Proto https;у меня была такая же проблема и исследование обработчика промежуточного программного обеспечения стойки (не
force_sslно похоже) я мог видеть, что он ожидал, что заголовок будет установлен, чтобы определить, был ли запрос уже обработан как SSL nginx.
Comments