rails3.0.9・nginxの組み合わせで、apacheでのX-Sendfile相当の事が実現したく検証しましたが、これまた少しはまりました。
■答えまでの道のり
config/environments/production.rb を見ると
# Specifies the header that your server uses for sending files config.action_dispatch.x_sendfile_header = "X-Sendfile" # For nginx: # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
という記載があるので、上をコメントアウトし、下をコメント外せば、OKと思ったのですが甘かったです。。上手く行かずエラーが出ます。
nginxのドキュメントを見ても、internalに対応する内部向けurlが、必要なのは分かりますが、いまいち良くわかりません。
ではrailsのsend_fileメソッド(actionpack-3.0.x/lib/action_controller/metal/streaming.rb)のソースを確認しても、pathには絶対パスを渡さないと上手く行かない事が予想されます(冒頭でファイルシステムとしての存在チェックをしているので)。しかしよく見ると
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
# via the Rack::Sendfile middleware. The header to use is set via
と書いてあるので、次はRack::Sendfile(rack-1.2.x/lib/rack/sendfile.rb)を見てみました。コメントには下記の用にnginx用のサンプルがあります。
# location ~ /files/(.*) { # internal; # alias /var/www/$1; # } # # location / { # proxy_redirect off; # # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # # proxy_set_header X-Sendfile-Type X-Accel-Redirect; # ① # proxy_set_header X-Accel-Mapping /files/=/var/www/; # ② # # proxy_pass http://127.0.0.1:8080/; # }
アプリケーションの通常処理を行うlocation "/" と、ファイル転送用のlocation "~ /files(.*)"があり/var/wwwがマッピングされるのかな?と思い、真似してみましたが上手くいきません。。
もう少しRackのソースを読んでみると、上記設定の意味が良くわかります。①はvariationメソッドの戻り値になります。したがってcall内の分岐は"X-Accel-Redirect"に進みます。その後map_accel_pathメソッドを実行するのですが、ここで驚愕の事実に気付きます。
def map_accel_path(env, file) if mapping = env['HTTP_X_ACCEL_MAPPING'] internal, external = mapping.split('=', 2).map{ |p| p.strip } file.sub(/^#{internal}/i, external) end end
②は絶対パスを、nginx用内部urlに変換する為に必要な設定ですが「右辺と左辺をドキュメントでは逆に書いている!」という事に気付きました。(internalとexternal)
よって②は左右逆転にしなければいけません。
proxy_set_header X-Accel-Mapping /var/www/=/files/;
ここまでやって上手くいきました。
/var/www/hoge.txt (send_file) => /files/hoge.txt (rackから出た時点) => /var/www/hoge.txt (nginxでの処理)
■設定方法(まとめ)
・config/environments/production.rb
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
のコメントをはずし、一つ上のX-Sendfileはコメントアウトします。
・プログラム
ファイル送信部分は絶対パス指定します。
send_file "/var/www/baz.txt"
・/etc/nginx/nginx.conf
下記の様に、通常処理側には、X-Sendfile-Type・X-Accel-Mapping、内部処理向けには、internal・alias設定を記載すればOKです。
location / { ... proxy_set_header X-Sendfile-Type X-Accel-Redirect; proxy_set_header X-Accel-Mapping /var/www/=/files/; ... } location /files/ { internal; alias /var/www; }
0 件のコメント:
コメントを投稿