2012-02-25 24 views
52

Tôi muốn có SSL API điều khiển sử dụng của tôi, vì vậy tôi thêm một nghe chỉ thị để nginx.conf tôiTại sao tôi nhận được vòng lặp chuyển hướng vô hạn với force_ssl trong ứng dụng Rails của tôi?

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; 
} 

mà vượt qua conftest nginx mà không bất kỳ vấn đề. Tôi cũng đã thêm một chỉ thị force_ssl để ApiController tôi

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 

mà chỉ làm việc tốt khi tôi đã không sử dụng SSL, nhưng bây giờ khi tôi cố gắng curl --LI http://foo/api/auth.json, tôi được chuyển đúng cách để https, nhưng sau đó tôi tiếp tục bị chuyển hướng đến http://foo/api/auth kết thúc bằng một vòng lặp chuyển hướng vô hạn.

tuyến đường của tôi chỉ đơn giản là có

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

Tôi đang sử dụng Rails 3.2.1 trên Ruby 1.9.2 với nginx 0.7.65

Trả lời

106

Bạn không chuyển tiếp bất kỳ thông tin nào về việc liệu yêu cầu này có phải là yêu cầu kết thúc HTTPS hay không. Thông thường, trong một máy chủ, "ssl on;" chỉ thị sẽ thiết lập các tiêu đề này, nhưng bạn đang sử dụng một khối kết hợp.

rack (và force_ssl) xác định SSL theo:

  • Nếu yêu cầu đến ở trên cổng 443 (điều này có thể không được chuyển lại cho Unicorn từ nginx)
  • Nếu ENV [ 'HTTPS'] == "on"
  • Nếu X-Forwarded-Proto tiêu đề == "HTTPS"

Xem the force_ssl source cho toàn bộ câu chuyện.

Vì bạn đang sử dụng khối kết hợp, bạn muốn sử dụng biểu mẫu thứ ba. Hãy thử:

proxy_set_header X-Forwarded-Proto $scheme; 

trong máy chủ hoặc khối vị trí của bạn per the nginx documentation.

Điều này sẽ đặt tiêu đề thành "http" khi bạn truy cập yêu cầu cổng 80 và đặt thành "https" khi bạn yêu cầu 443.

+1

Phép thuật thuần túy. :) Trong trường hợp của tôi, tôi đã chuyển trang web Rails sang sử dụng Varnish. Trang web là HTTPS thuần túy, và như Varnish không hỗ trợ SSL và Passenger cho thấy một ổ cắm thay vì một cổng, hai cấu hình máy chủ Nginx được yêu cầu, một trong hai bên của Varnish. Cách xa kết nối socket Hành khách từ cấu hình HTTPS trên cổng 443 gây ra một vòng lặp chuyển hướng. Và điều này cố định nó. Cảm ơn bạn! –

16

Hãy thử thiết lập chỉ thị này trong nginx bạn location @unicorn khối:

proxy_set_header X-Forwarded-Proto https;

Tôi có cùng vấn đề này và điều tra Trình xử lý trung gian Rack (không phải force_ssl nhưng simi lar) Tôi có thể thấy rằng nó đã được mong đợi rằng tiêu đề được thiết lập để xác định nếu yêu cầu đã được xử lý như là SSL bởi nginx.

+4

Điều này sẽ đánh dấu tất cả các yêu cầu là yêu cầu SSL, ngay cả yêu cầu cổng 80, vì đó là một khối máy chủ kết hợp. –

+0

@ChrisHeald Tôi đã gửi bản chỉnh sửa để sửa. –

Các vấn đề liên quan