Railsでsubdomainを使う際nginxのReverseProxy設定で気をつけること

Railsでは、request.subdomainで簡単にサブドメインの判別ができます。
詳しくはRailsCastsに書いてありますが、特にgemを入れなくても、url_forに1つ機能追加するだけで、実用的なサブドメイン機能が使えます。

何が嬉しいかというと、

  • ja.example.com
  • en.example.com

のようなwikipedia風のURLを作ったり、ブログサイトでユーザ毎にサブドメインを切ってあげたりできるわけですね。

サブドメインは当然HTTPリクエスト時のホスト名から取得されるので、環境によってはうまく取得できない場合があります。

ローカルでテストする場合

通常localhost:3000で開発すると思いますが、これにサブドメインを付けてja.localhost:3000としても、127.0.0.1に名前解決はしてくれません。
hostsファイル(/etc/hosts)はワイルドカードが使えないので、個別に記述する必要があります。

RailsCastsにあるように、「lvh.me」というドメインが127.0.0.1を向いているので、ja.lvh.me:3000とやるのがお手軽です。

nginxをリバースプロキシにする場合

リバースプロキシからは、X-Forwarded-Hostを送ってやる必要があります。
Railsのドメイン判別は以下のようになっているので、X-Forwarded-Hostがあると、HTTP_HOSTに優先して採用されます。

# actionpack-3.2.8/lib/action_dispatch/http/url.rb
# Returns the \host for this request, such as "example.com".
def raw_host_with_port
  if forwarded = env["HTTP_X_FORWARDED_HOST"]
    forwarded.split(/,\s?/).last
  else
    env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
  end 
end

nginxのconfファイルとしてはこんな感じになりますね。

proxy_redirect     off;
proxy_set_header   X-Forwarded-Proto http;
proxy_set_header   X-Forwarded-Host  $host; # これ!
proxy_set_header   Host              $host;
proxy_set_header   X-Real-IP         $remote_addr;
proxy_set_header   X-Forwarded-For   $remote_addr;
proxy_pass         http://myproxy

nginxで多段リバースプロキシする場合

多段Revese Proxyしたいときもあると思います。
たとえば、社内サーバでIP節約のためにReverse Proxyを通す必要があり、かつRailsアプリサーバはproductionで動かしたいので、assetsファイルをserveするためにアプリサーバ内でnginxを動かしたい場合です。

多段の場合、外側のnginxは上記設定のままでOKですが、内側のnginxは一部パラメータを改めて渡す設定が必要になったりします。
X-Forwarded-Hostは設定不要でしたが、手元の環境では、x_forwarded_forとx_forwarded_protoを改めて渡さないと、force_sslでリダイレクトループが発生しました。

proxy_redirect     off;
proxy_set_header   X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header   Host              mangareborn-stg.bpsinc.jp;
proxy_set_header   X-Real-IP         $http_x_real_ip;
proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_pass         http://myproxy

nginxでパラメータをデバッグする

上記のような設定をしていると、思うようにヘッダが渡らないことも多いと思います。
nginxでどの変数が使えてどんな値が入っているかを知りたいときは、アクセスログに出すのが手っ取り早いです。

log_format custom 'MY HEADER $host $proxy_add_x_forwarded_for'; # 好きにいじる
access_log /var/log/nginx/mycustom.log custom;

本記事の対象バージョンはRails 3.2.8です

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

baba

ゆとりプログラマー。 高校時代から趣味でプログラミングを初め、そのままコードを書き続けて現在に至る。慶應義塾大学環境情報学部(SFC)卒業。BPS設立初期に在学中から参加している最古参メンバーの一人。得意分野はWeb全般、Ruby on Rails、Androidアプリケーションなど。最近はBlinkと格闘中。軽度の資格マニアで、情報処理技術者試験(高度10区分)などを保有。

babaの書いた記事

週刊Railsウォッチ

インフラ

Rubyスタイルガイドを読む

BigBinary記事より

ActiveSupport探訪シリーズ