Speed up file downloads with Rails, Apache and X-Sendfile

Updated . Posted . Visible to the public.

When you use the send_file Show archive.org snapshot 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:

X-Sendfile: /opt/www/awesome-project/shared/downloads/image.png

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 Show archive.org snapshot .

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 (releases/123456).

Now restart Apache and you're good to go.

Henning Koch
Last edit
Besprechungs-PC
Keywords
bytes
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2011-02-09 16:24)