Speed up file downloads with Rails, Apache and X-Sendfile
When you use the
send_file method to send a local file to the browser, you can save resources on the application server by setting the
:x_sendfile option to
true. This option is activated by default for Rails 3, so you need to understand this.
What this option does is not to send any data at all, but rather set the local file path as a new response header:
When the response comes back from Rails to Apache for delivery, Apache will detect that header and replace the empty response body with the local file contents. This trick frees up the expensive Rails/Passenger worker process and lets the lightweight Apache worker do the heavy lifting.
You need to configure Apache to be aware of
X-Sendfile or you will end up with unprocessed, zero-byte file dowloads.
Configuring the Apache module
Install the Apache module by saying
sudo apt-get install libapache2-mod-xsendfile
Check which version you got because that will be relevant later:
dpkg -l | grep libapache2-mod-xsendfile
If you have a module version < 0.10, add this to the virtual host config that needs to send files:
XSendFile On XSendFileAllowAbove On
This allows any file path (not only those below your VHost root) to be sent through
X-Sendfile, which is sort of bad practice. You can either live with it or compile a newer version of the module.
If you got a module version >= 0.10 you can whitelist the allowed paths instead:
XSendFile On XSendFilePath /opt/www/awesome-project
Note that you cannot whitelist a symlink inside a
current release directory, because Apache sees those downloads with their real paths (
Now restart Apache and you're good to go.