ADZ 學習筆記

Ruby/Rails, Startup, Life

Nginx + Unicorn SSL URL 錯誤問題

| Comments

這幾天在 DigitalOcean 上開了 Ruby on Rails (Ngnix + Unicorn) 的 droplet 準備來 deploy 新版晚鳥票

開完機器更新完 rvm, ruby 2.1.0, rails 4.0.2 之後,安裝一切順利,但最後在測試時發現,發出去的 email 只要是使用了 url helper 出來的 protocol 都是 http 不是 https (by the way 晚鳥票全站使用 https)

一開始以為是哪邊 config 少了,查了查資料,原來可以設定 action_controller 的 default_url_options

production.rb
LatebirdCo::Application.configure do
  config.action_controller.default_url_options = { host: Setting.domain, protocol: :https }
end

設定完以後是正常了,不過還是覺得有點奇怪,這些設定不應該在 rails project 裡解決,如果遇到要同時支援 http, https 的需求,那不就等於寫死了嗎?

而且晚鳥票 v1 使用 passenger + nginx 並沒有這樣設定,都是靠當前的使用的 protocol + domain 才對。

之後又發現在 controller 內使用 request.original_url 又會自動使用 prefix http:// 作為網址開頭,猜想應該不是 project config 的問題,可能是 nginx proxy 的沒有把 request header 傳給 unicorn 導致 rails app 不知道自己身處於 http 還是 https,查一下關於 nginx 的 proxy setting 找到以下參數

proxy_set_header X-Forwarded-Protocol https;

http://stackoverflow.com/questions/4622704/trouble-getting-ssl-to-work-with-django-nginx-wsgi

但設定完以後還是無效,搞了 30 分鐘最後看到一篇 ...

http://blog.seancarpenter.net/2013/09/02/rails-ssl-route-generation-with-nginx-and-unicorn/

request.rb
def scheme
  if @env['HTTPS'] == 'on'
    'https'
  elsif @env['HTTP_X_FORWARDED_SSL'] == 'on'
    'https'
  elsif @env['HTTP_X_FORWARDED_SCHEME']
    @env['HTTP_X_FORWARDED_SCHEME']
  elsif @env['HTTP_X_FORWARDED_PROTO']
    @env['HTTP_X_FORWARDED_PROTO'].split(',')[0]
  else
    @env["rack.url_scheme"]
  end
end

def ssl?
  scheme == 'https'
end

原來 request 在實作上讀取 proxy header 的名字是要這樣設定

/etc/nginx/site-enabled/default
location @app {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Client-IP $remote_addr;
  proxy_set_header X-Forwarded-Protocol https;
  proxy_set_header X-Forwarded-Proto https; # 加這一行

  proxy_redirect off;
  proxy_pass http://app_server;
}   

Done! 收工 :)

Comments

comments powered by Disqus