solotimes
9/16/2012 - 5:20 AM

Rails / Dragonfly / nginx X-Sendfile (aka X-Accel-Redirect)

Rails / Dragonfly / nginx X-Sendfile (aka X-Accel-Redirect)

upstream unicorn {
  server unix:/tmp/unicorn.<%= application %>.sock fail_timeout=0;
}

server {
  listen 80 default deferred;
  # server_name example.com;
  root <%= current_path %>/public;
  
  if (-f $document_root/system/maintenance.html) {
    return 503;
  }
  error_page 503 @maintenance;
  location @maintenance {
    rewrite  ^(.*)$  /system/maintenance.html last;
    break;
  }
  
  location <%= shared_path %>/tmp/dragonfly/cache/body/ {
    internal;
    alias <%= shared_path %>/tmp/dragonfly/cache/body/;
  }
  
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }
  
  try_files $uri/index.html $uri @unicorn;
  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Sendfile-Type X-Accel-Redirect;
    # This header is required otherwise Rack::Sendfile will not actually return the X-Accel-Redirect header.
    # Be sure to include if testing with cURL.
    proxy_set_header X-Accel-Mapping <%= shared_path %>/tmp/dragonfly/cache/body/=<%= shared_path %>/tmp/dragonfly/cache/body/;
    proxy_redirect off;
    proxy_pass http://unicorn;
  }
  
  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}
# NOTE: Only relevant lines have been included in this Gist

# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

# Sets Rack::Cache to use standard file:/ store rather than rails:/
# Also sets the cache path outside of the rails root in the Capistrano shared folder
# Plays nicely with standard Capistrano recipes
config.action_dispatch.rack_cache = {
  :verbose     => true,
  :metastore   => URI.encode("file:#{File.expand_path(Rails.root.join('..', '..', 'shared'))}/tmp/dragonfly/cache/meta"),
  :entitystore => URI.encode("file:#{File.expand_path(Rails.root.join('..', '..', 'shared'))}/tmp/dragonfly/cache/body")
}

# Ensures Rack::Sendfile is inserted at the front of the middleware stack
config.middleware.insert 0, Rack::Sendfile, config.action_dispatch.x_sendfile_header