Add ‘Options FollowSymLinks’ and avoid ‘Options SymLinksIfOwnerMatch’ in Apache to save disk I/O

Mattias Geniar, Saturday, February 11, 2012 - last modified: Friday, November 28, 2014

Following up on the advice to stop using AllowOverride All in Apache configs, Wim Godden kindly reminded me of a similar issue that exists when not using FollowSymLinks or when using SymLinksOfOwnerMatch.

The bad configuration

It's about the following kind of configuration.

<Directory "/var/www/html/">
    Options SymLinksIfOwnerMatch -FollowSymLinks

The option FollowSymLinks should always be kept on if possible. Without that, every time you request a file, Apache will check if that file resides in a directory that is somehow symlinked. If it is, it will block your request. But that requires an extra check for every file being accessed.

If someone on the site would request the file "/content/styles/v3/style.css", that would results in the following system calls:

stat("/var/www/html/", {st_mode=S_IFREG|0644, st_size=5, ...}) = 0
lstat("/var/www/html/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www/html/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www/html/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www/html/", {st_mode=S_IFREG|0644, st_size=5, ...}) = 0
open("/var/www/html/", O_RDONLY|O_CLOEXEC) = 10

That's 4x an lstat() disk I/O to check if any of the directories between "/var/www/html" and "/var/www/html/" contain any symlinks.

The good configuration

Below is a better configuration. It does not check the symlinks if the owners match (-SymLinksIfOwnerMatch) and it does not limit the Apache server from following Symlinks (+FollowSymLinks).

<Directory "/var/www/html/">
    Options -SymLinksIfOwnerMatch +FollowSymLinks

If I were to request a simple file "/content/styles/v3/style.css", it would result in the following system calls:

stat("/var/www/html/", {st_mode=S_IFREG|0644, st_size=5, ...}) = 0
open("/var/www/html/", O_RDONLY|O_CLOEXEC) = 10

That's a lot less disk I/O on a busy server.

Hi! My name is Mattias Geniar. I'm a Support Manager at Nucleus Hosting in Belgium, a general web geek, public speaker and podcaster. If you're interested in keeping up with me, have a look at my podcast and weekly newsletter below. For more updates, follow me on Twitter as @mattiasgeniar.

I respect your privacy and you won't get spam. Ever.
Just a weekly newsletter about Linux and open source.

SysCast podcast

In the SysCast podcast I talk about Linux & open source projects, interview sysadmins or developers and discuss web-related technologies. A show by and for geeks!

cron.weekly newsletter

A weekly newsletter - delivered every Sunday - for Linux sysadmins and open source users. It helps keeps you informed about open source projects, Linux guides & tutorials and the latest news.

Share this post

Did you like this post? Will you help me share it on social media? Thanks!


Philip Paeps Monday, February 13, 2012 at 19:42

On modern operating systems, this shouldn’t affect disk i/o much or at all. The kernel will cache the result of the stat() and lstat() calls and return them immediately on subsequent calls. You might gain a slight reduction in context switches but on Linux with VDSO, that shouldn’t be measurable.

Did you measure any reduction in i/o, or are you just looking at strace output and looking at system calls?


    Matti Tuesday, February 14, 2012 at 19:16

    For the moment: only looking at strace & system calls, no actual benchmarks on the performance. But even so, avoiding (even cached) system/kernel calls should be encouraged.


Leave a Reply

Your email address will not be published. Required fields are marked *

Inbound links