This post was written by Markus Stefanko

Move your htaccess files into your virtualhosts file

Every time your apache accesses a directory, it might be looking for a .htaccess in each of them. Not only in the current directly, but also the parent directories. That’s expensive lookups, especially on cloud based drives, which add network latency and cost expensive performance.

Word on the street is, you don’t want to use .htaccess files

The official recommendation for .htaccess files from the Apache Foundation itself is to not use them, unless you have no other choice – e.g. your host doesn’t allow you to edit virtualhost directives for your website.

So there is no such reason if you have access to such, as .htaccess files are nothing more than what should be written in the virtualhost file itself.

However keeping track of every .htaccess change and implementing it into one huge Virtualhost file would be a nightmare to maintain. So let’s simplify by simply including the .htaccess files into it, and removing the on-load lookups for such by disabling AllowOverride.

Let’s implement

In order to reduce this overhead on our machines, we have decided to set Apache’s Virtualhost directives to Allowoverride None and include each .htaccess file in the respective domain configuration files, which you can usually find on debian systems in e.g. /etc/apache2/sites-enabled.

All you need is do a basic find command in your website folder, such as : find /var/www/websitename|grep '.htaccess'. An example output might look like the following :

/var/www/www.website.com/wp-content/cache/page_enhanced/.htaccess
/var/www/www.website.com/wp-content/cache/minify/.htaccess
/var/www/www.website.com/wp-content/cache/.htaccess
/var/www/www.website.com/.htaccess

Now let’s add these directives into your virtualhost file at /etc/apache2/sites-enabled/www.website.com which might look like the following :

<VirtualHost *:8080>

    ServerName website.com
    ServerAlias www.website.com

    ServerAdmin your@email.com

    DocumentRoot /var/www/www.website.com/

    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>

    <Directory "/var/www/www.website.com/">
        Options -Indexes FollowSymLinks MultiViews
        AllowOverRide None
        Include /var/www/www.website.com/.htaccess
        Order allow,deny
        allow from all
    </Directory>

    <Directory "/var/www/www.website.com/wp-content/cache/page_enhanced/">
        AllowOverRide None
        Include /var/www/www.website.com/wp-content/cache/page_enhanced/.htaccess
    </directory>

    <Directory "/var/www/www.website.com/wp-content/cache/minify/">
         AllowOverRide None
         Include /var/www/www.website.com/wp-content/cache/minify/.htaccess
    </directory>

    <Directory "/var/www/www.website.com/wp-content/cache/">
          AllowOverRide None
          Include /var/www/www.website.com/wp-content/cache/.htaccess
    </directory>

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/www.website.com-error.log

    # Since Apache is running on :8080 with a varnish on :80, let's log the real IP
    SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
    CustomLog ${APACHE_LOG_DIR}/www.website.com-access.log combined env=!forwarded
    CustomLog ${APACHE_LOG_DIR}/www.website.com-access.log proxy env=forwarded

</VirtualHost>

Additionally we have disabled any access to .htaccess files to read only, so websites wouldn’t be able to alter them on their own. In WordPress plugins like W3TC will notify you that they are lacking access, and will ask you to ammend such changes.

Apache2 won’t boot up if .htaccess is suddenly missing

One caveat to consider is to check if all .htaccess files exist when you restart your Apache Webserver. E.g. the Akismet plugin recently removed its .htaccess file in the latest update, which would fail Apache to start.

For that simply ammend your Apache daemon script in /etc/init.d/apache2 with a new function :

apache_test() {
        $APACHE2CTL configtest
}

and add it as variable to your daemon in the section starting after case $1 in like so :

test)
        apache_test
;;

Now you will be able to run /etc/init.d/apache2 test before attempting to stop/start/restart the server. You might want to extend the functionality to automatically check for it before these, and the apache2 daemon has it’s own handling with configtest as well. But it’s always good to doublecheck if changes you did were correct, before relying on automatic handling.

Apache2 will need to be restarted for .htaccess changes to be effective

The biggest caveat in this setup is that Apache has to be restarted after any .htaccess changes have been made, but that is a tolerable adjustment, as such changes should not happen often.

Now we have .htaccess loaded with Apache at server start, and no more additional recursive directory lookups have to be made by Apache for the .htaccess files on each request. That saves disk IO, performance with network drives and cloud providers induces cost savings as well.

by Markus Stefanko