症状
- Deviseのログインをしようとすると422エラー
- ActionController::InvalidAuthenticityToken
- Chrome, Safariで発生
- Firefoxでは発生しなかった
発生条件
下記条件で発生しました。他の要因があるかもしれないし、関係ないかもしれません。参考程度に。
- Nginx 1.6.3
- Puma 3.4.0
- Rails 5.0.0.rc1
- HTTPS強制(Railsの
force_ssl
ではなくNginxの設定で)
対処法
Nginxの設定ファイルはこんなかんじになっていた(抜粋)。
nginx.conf
# --------------------------------------------------------------------
# https://example.com/
# --------------------------------------------------------------------
upstream example-app {
server unix:/path/to/server.sock;
}
server {
listen 443 ssl;
server_name example.com;
root /path/to/example-rails-app/public;
location / {
if (!-f $request_filename) {
proxy_pass http://example-app;
}
}
# SSLやassetsのあたりの設定は省略
}
# --------------------------------------------------------------------
# http://example.com/
# --------------------------------------------------------------------
server {
listen 80;
server_name example.com;
rewrite ^(.*)$ https://example.com$1 permanent;
}
これだと、クライアント⇔NginxはHTTPS通信するが、Nginx⇔PumaはHTTP通信になり、RailsにはHTTP接続に見え、ホスト名が example-app
、クライアントのIPアドレスも127.0.0.1に見えてしまう(Pumaから見たNginxのIPアドレス)。Railsが思っている自分のURLと実際のURLが異なるからうまく処理できないような感じが原因に見えた。そのため、下記を server
ディレクティブに加えてNginxがもってる情報を渡してあげたら解決した。
nginx.conf
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-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;