Nginx で認証つきで大容量ファイルをダウンロードさせたい時は、X-Accel-Redirect を使います。Rails のファイル操作を介さず、Nginxで直接クライアントへデータを送れます。Lighttpd とか Apache でいうところの、X-sendfile と同じような感じでしょうか。
Lighttpd の場合はこちら -> Rails&Lighttpdで大容量ファイルをダウンロード【変なヤバいもんログ内】
ヘッダに、X-Accel-Redirect でパスを指定して、そのパスを Nginx 側で受けるだけですinternal って付けるのがポイントです。そうすると、このように内部からしか参照できなくなります。外からそのパスを叩いても見れないということになります。
Rails2以前の場合は自分でヘッダに値を設定する必要があり、Rails3以降は設定を変更するだけでいけるようです。
# Rails2以前
def download
# 認証処理などを挟むことができます。
path = "/bigfiles/long_movie.mp4"
response.headers['X-Accel-Redirect'] = path
response.headers['Content-Type'] = "application/force-download"
response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(path)}\""
response.headers['Content-length'] = File.size(RAILS_ROOT + path)
render :nothing => true
end
# Rails3
def download
# 認証処理などを挟むことができます。
path = "/bigfiles/long_movie.mp4"
send_file path,
:type => "application/force-download",
:disposition => "attachment; filename=\"#{File.basename(path)}\""
end
# config/environments/production.rb
# 下記行をコメントアウト (Apache, lighttpd の場合はこの行を使う)
# config.action_dispatch.x_sendfile_header = "X-Sendfile"
# 下記の行を有効にする (nginxの場合はこの行を使う)
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
location / { client_max_body_size 200m; proxy_read_timeout 60; proxy_connect_timeout 60; proxy_pass http://railsapp; } location /bigfiles { # -> /path/to/railsroot/bigfiles root /path/to/railsroot/; internal; }
gist に上げてあります。https://gist.github.com/708959
補足
逆に、ちょっとしたアプリを動かすときに、いちいち nginx の設定とかせずに Unicorn とかから直接ファイルを送りたい場合もあります。Rails3になってから、config/environments/productioin.rb がデフォルトのままだと send_file すると 0bytes になってしまいます。
下記の2行をコメントアウトしておくと、Unicorn なりで直接ファイル送信ができるようになります。
# config.action_dispatch.x_sendfile_header = "X-Sendfile"
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
ついでに、静的ファイルも Unicorn なりで表示したいような手抜き構成のときは、下記の設定もお忘れなく。
config.serve_static_assets = false