Nginx でリバースプロキシをする場合に、どうやってセキュアなリクエストであることをアプリケーションに伝えるか?のメモ。
Nginx - Rails の場合
NginxでリバースプロキシするときにもSSLはNginxで処理させる場合が多く、プロキシされるアプリケーションサーバにはSSLが解かれた状態でリクエストが届く。
そのため次のヘッダをNginxでつけるように設定する必要がある。
server {
listen 80;
server_name hoge.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
index index.html index.htm;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:3000;
}
}
AWS で ELB と組み合わせて使う場合
ELB - EC2(Nginx + Rails) 構成の場合には普通、ELBでSSLを終端する。
その時、ELBは次のヘッダをリクエストに付加してEC2側に送ってくれる。
X-Forwarded-For: xxx.xxx.xxx.xxx
X-Forwarded-Port: 443
X-Forwarded-Proto: https
ELB で SSL を終端してしまうと、Nginxにとっては $scheme が HTTP となる。
これではアプリケーションサーバ側にもともとのプロトコルが伝わらない。
アプリケーション側からセキュアなリクエストなのかどうかを判別する必要がある場合には困る。
で、アプリケーション側でスキームを知る必要がある場合には、次のように設定する。
server {
listen 80;
server_name hoge.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
index index.html index.htm;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:3000;
}
}
Railsの force_ssl は次の条件でSSLによるアクセスで有ることを判定する(Rack::Request#scheme メソッドに実装がある)。
- HTTP_X_FORWARDED_SCHEME の値
- HTTP_X_FORWARDED_PROTO の値
- HTTP_X_FORWARDED_SSL の値
上記の設定は X-Forwarded-Proto ヘッダを使って SSL であることを Railsに伝えており、force_ssl が機能する。