Je veux que mon contrôleur API utilise SSL, j'ai donc ajouté une autre directive d'écoute à mon 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;
}
qui passe le conftest nginx sans aucun problème. J'ai également ajouté un force_ssl
directive à mon 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
qui fonctionnait très bien quand je n'utilisais pas SSL, mais maintenant quand j'essaie de curl --LI http://foo/api/auth.json
, Je suis correctement redirigé vers https
, mais je continue à être redirigé vers http://foo/api/auth
se terminant par une boucle de redirection infinie.
Mes itinéraires ont simplement
get "api/auth"
get "api/check"
J'utilise Rails 3.2.1 sur Ruby 1.9.2 avec nginx 0.7.65
Vous ne transmettez aucune information indiquant si cette demande était une demande terminée par HTTPS ou non. Normalement, dans un serveur, le "ssl on;" La directive définira ces en-têtes, mais vous utilisez un bloc combiné.
Rack (et force_ssl) détermine SSL par:
Voir la source force_ssl pour l'histoire complète.
Puisque vous utilisez un bloc combiné, vous souhaitez utiliser le troisième formulaire. Essayer:
proxy_set_header X-Forwarded-Proto $scheme;
dans votre serveur ou bloc d'emplacement selon la documentation nginx .
Cela mettra l'en-tête sur "http" lorsque vous entrerez sur une demande de port 80 et le mettra sur "https" lorsque vous entrerez sur une demande 443.
Essayez de définir cette directive dans votre nginx location @Unicorn
bloquer:
proxy_set_header X-Forwarded-Proto https;
J'ai eu ce même problème et j'ai enquêté sur le gestionnaire de middleware Rack (pas force_ssl
mais similaire) Je pouvais voir qu'il s'attendait à ce que l'en-tête soit défini pour déterminer si la demande était déjà traitée comme SSL par nginx.