Drupal has a setting that allows you to put the site off-line, and show a maintenance message to the visitors. However, in order to determine that the site is in off-line mode and load the maintenance page, Drupal still needs to boot up to some extent, which involves loading several PHP files and connecting to the database. This may lead to the visitors seeing error messages, if the site is being tampered with while they try to access the site.

The problem stems from the fact that the massive amount of files that Drupal has cannot be replace instantly, and the site may be in an inconsistent state for a short amount of time. Even a minor core update may require you to temporarily remove your old sites directory, with settings.php in it, in which case the unwitting visitors will be redirected to the installation screen – a definitely undesired occurrence. If the whole Drupal site is removed, of course, the visitors get a 404 error. The removal of any files can be avoided by using svn or git to update the site, which updates files one by one, although it still leaves the files in an inconsistent state for seconds.

For this reason, I looked for an alternate solution when I was once working on a major Drupal upgrade (D6 to D7). I used Apache’s rewrite engine to prevent any incoming traffic from hitting Drupal at all. With one RewriteRule directive, one can redirect every incoming request to a static HTML page. However, I needed to be able to access the site in order to perform and eventually validate the upgrade, so I used a RewriteCond directive to filter on IP address and let myself access the site. The lines I inserted into .htaccess are as follows:

RewriteCond %{REMOTE_ADDR} !^1\.2\.3\.4
RewriteRule !maintenance\.html http://example.com/maintenance.html [R=302,L]

The ! negates the regular expression, so it matches when the remote IP is not the one defined. The rewrite rule should exclude the HTML file it is redirecting to, so that no redirect loop occurs – hence the negative matching condition again. I used the 302 – Found status code, which implies that the page has been moved temporarily, so search engines do not update the URL in their indexes.

If you have multiple hostnames assigned to the site – or can access it by IP -, you can set up the condition based on the requested hostname. That way, visitors requesting a page using the publicly known hostname get redirected, while you can access the site by IP or a secondary hostname. The following condition lets you through if you use the fictional hostname test.example.com to access the site, but redirects when any other hostname is used:

RewriteCond %{HTTP_HOST} !^test\.example\.com

The static HTML file is the only one that this rule lets through, which means if there was an image in our static maintenance page, it would not display. If an image needs to be displayed on the page, it needs to be excluded from the rewrite rule. This can be done by using alternation – pipe symbol - in the regular expression.

RewriteRule !(maintenance\.html|logo\.jpg) http://example.com/maintenance.html [R=302,L]

This rule redirects every request except those for maintenance.html and logo.jpg.

I prefer this method over the standard maintenance page whenever I perform a major upgrade, although I keep on using Drupal’s maintenance page for smaller ones. Another factor to consider is how popular the site is – the more visitor it attracts, the more the chances are that some of them may see an error message during the upgrade process.