Nginx の X-Accel-Redirect を Rails で使う

 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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です