Speed WordPress MultiSite With X-Sendfile For Apache

Like WordPress MU before, MultiSite implementations of WordPress 3.0 use a script to handle image and other attachment downloads. That script checks permissions and maps the request path to the files path on disk, then reads the file out to the web server, which sends it to the browser.

That approach has some inefficiencies, and for me it introduces some problems. The process would often give up before completing the file transfer, resulting in broken images and truncated MP3s among other problems. Interestingly, the problem is exacerbated when Memcached is activated.

I haven’t solved the problem, but I found a work around in X-Sendfile and X-Accel-Redirect. Both do basically the same thing, the different names are for different implementations in various servers. A post at Tech Rocket Science offers some background and explains that support is built in to lighthttpd and nginx, while Apache httpd requires a module. The benefits are simple: Apache httpd is well optimized for reading files from disk and sending them to clients, but PHP isn’t. Those httpd servers also know how to send or respond to headers that make it even faster, including Etag, If-Modified-Since, and If-None-Match.

Here’s how to get it working on CentOS 5 with the packaged Apache httpd:

  1. Nils Maier wrote the module for Apache httpd. Download the source and take some time to review the docs there.
  2. Compile and install the module on the command line:

    /usr/sbin/apxs -cia mod_xsendfile.c

  3. If you don’t have apxs, you probably need to install the httpd-devel package. Get that with this command:

    yum install httpd-devel

  4. Once compiled and installed, you’ll need to enable it in your httpd.conf or .htaccess (I enabled it by putting a file in my conf.d directory). These are the directives you’ll need to set:

    XSendFile on<br /> XSendFileAllowAbove on

  5. Now restart Apache httpd

    /sbin/service httpd restart

  6. Finally, you’ll need to enable the support in your wp-config.php:

    define('WPMU_SENDFILE', true);