Dev Notes

Software Development Resources by David Egan.

Apache Directives in Config vs .htaccess


Apache, Sysadmin
David Egan

Apache allows configuration rules to be overridden at the directory level by means of distributed configuration files. These files are usually called .htaccess, but the file name can be customised. Directives placed in .htaccess apply to the directory that contains the file, and changes to .htaccess have immediate effect for that directory. However, this can be wasteful of resources - .htaccess files are read on every request.

In general, you should only use .htaccess files when you don’t have access to the main server configuration file…

….htaccess files should be used in a case where the content providers need to make configuration changes to the server on a per-directory basis, but do not have root access on the server system…

…However, in general, use of .htaccess files should be avoided when possible. Any configuration that you would consider putting in a .htaccess file, can just as effectively be made in a section in your main server configuration file.

Apache Docs, .htaccess

If you’re managing sites on a VPS, there’s no need to use distributed configuration files. I think I personally became conditioned to them from managing sites on shared hosting, with no root access.

Because of this, I’ve been moving Apache rewrite rules and access restrictions out of .htaccess files and into virtual host configs.

Global Rules

In some cases, the rules that might have gone into a .htaccess file can be applied at a server level - for example, preventing access to .git directories and restricting access to config files (e.g. wp-config.php) is probably best achieved by adding appropriate rules to /etc/apache2/conf-enabled/security.conf (the Ubuntu apache2 security config file). If you’re blocking access to these files in one directory, the chances are that you’ll want to apply this to the whole server.

Per-Directory Rules: WordPress

The normal WordPress rewrite block can be easily added to a virtual host config. This allows you to disallow overriding at the directory level which speeds things up.

The following sections contrast how to achieve the same effect with a .htaccess file and a virtual host configuration. In this case, a set of WordPress rewrites are needed, along with some restrictions based on IP address.

Typical WordPress .htaccess File: Production Site

The .htaccess file is placed in the site document root. If the file is writeable by WordPress, WP will generate the config block between # BEGIN WordPress and # END WordPress.

The following .htaccess file has an additional rule that restricts access to the main site login by IP.

# ==============================================================================
# Restrict access to WordPress login page by IP
# See: http://httpd.apache.org/docs/2.4/mod/core.html#files
# ==============================================================================
<Files "wp-login.php">
    Require ip x.x.x.x y.y.y.y
</Files>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

Apache vHost Configuration with WordPress Specific Rules

To achieve the same thing without use of .htaccess, amend the site virtual host config file:

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin info@example.com
        DocumentRoot /var/www/html/example.com/web
        # Disallow overrides (.htaccess) in the document root
        <Directory /var/www/html/example.com/web>
                Options -Indexes +FollowSymLinks
                AllowOverride None
                Require all granted
        </Directory>
        # Restrict access to wp-login.php - space separated list of allowed IPs
        <Files "wp-login.php">
                Require ip x.x.x.x y.y.y.y
        </Files>
        # Restrict access to the site admin area by IP
        <Directory /var/www/html/example.com/web/wp/wp-admin>
                AllowOverride None
                Require ip x.x.x.x y.y.y.y
        </Directory>
        # WordPress Config - this must be placed in a <Directory> block
        <Directory "/var/www/html/example.com/web">
                <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteBase /
                RewriteRule ^index\.php$ - [L]
                RewriteCond %{REQUEST_FILENAME} !-f
                RewriteCond %{REQUEST_FILENAME} !-d
                RewriteRule . /index.php [L]
                </IfModule>
        </Directory>
        # Set custom logs
        ErrorLog ${APACHE_LOG_DIR}/example.com.error.log
        CustomLog ${APACHE_LOG_DIR}/example.com.access.log combined
        # SSL cert details (LetsEncrypt)
        SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

Typical .htaccess Rules for Private Staging Site

This .htaccess file is for a site that is in a sub-directory of the domain document root. For example: testdomain.com/testsite. This is often a convenient way of handling staging websites.

In this case, the main Apache vHost configuration for the “parent” domain needs to allow override by means of .htaccess. This is achieved by setting the AllowOverride directive to “All” in the virtual host config file. When this directive is set to None and AllowOverrideList is set to None, .htaccess files are completely ignored. In this case, the server will not even attempt to read .htaccess files in the filesystem.

# ==============================================================================
# Full block - private. This is a staging site!
# ==============================================================================
<RequireAll>
    Require ip x.x.x.x y.y.y.y
</RequireAll>

# ==============================================================================
# Restrict access to WordPress login page by IP
# See: http://httpd.apache.org/docs/2.4/mod/core.html#files
# ==============================================================================
<Files "wp-login.php">
    Require ip x.x.x.x y.y.y.y
</Files>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /testsite/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /testsite/index.php [L]
</IfModule>
# END WordPress

Reload Apache Configs

If you move your local config into virtual host configs, any changes you make will not take effect until you reload Apache:

sudo /etc/init.d/apache2 reload

# or use `force-reload`, an alias for the same command:
sudo /etc/init.d/apache2 force-reload

comments powered by Disqus