How to use mod_rewrite rules to easily enable web site “maintenance” modes

When you’re administering a web site, sometimes you need to make changes that for whatever reasons require that the web site be temporarily unavailable for normal visitors. One obvious example is database maintenance. Unless you have the resources to do full-blown load balancing across a server cluster, you probably have to accept that your site is going to be down for a short period of time.

When this happens, it’s generally a good idea to show your visitors a web page that briefly explains the situation. This is typically a page that politely explains that the “site is temporarily down for maintenance” and so on. I’ve taken to calling such a page a “curtain” because it’s a little like putting a curtain up in front of construction work.

You put the curtain up, do whatever you need to do to fix or upgrade or maintain your web site in the background, then take the curtain down. For delicate servers, this has the added benefit of dramatically reducing server load while you do your maintenance tasks. You can even allow access to specific visitors, such as QA testers or remote admins while this curtain is up, while still redirecting normal users to the “down for maintenance” page.

Obviously, the first thing you need is the page that explains your site is down for maintenance reasons. This can be anything you like, but it’s simplest to make it a static HTML page and place any and all resources you need for this page (like images) into the same folder. I often use a directory named down-for-maintenance and I place an index.html file in that folder to use as my “curtain” page. Images go straight into the down-for-maintenance directory, too.

Once you have that, you can then use the following Apache configurations to create an “on/off switch” for putting your curtain up and taking it down.

# To take the web site into a maintenance mode, create a file named
# maintenance-mode-on at the document (website) root, such as this:
#
#     touch maintenance-mode-on
#
# To bring the web site back, remove or rename the file, such as this:
#
#    mv maintenance-mode-on maintenance-mode-off
#
# To enable the site for your IP address only but nobody else's
# uncomment the second RewriteCond directive.
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{DOCUMENT_ROOT}/maintenance-mode-on -f
    #RewriteCond %{REMOTE_ADDR} !^your.IP.address.here$
    RewriteRule !^down-for-maintenance/.*$ /down-for-maintenance/ [R,L]
</IfModule>

What this does, step by step, is:

  1. Determines whether or not you have mod_rewrite enabled. If you don’t, then nothing happens.
  2. Enables the mod_rewrite rewriting engine.
  3. Checks for the existence of a file called maintenance-mode-on at your site’s root. If such a file does not exist, nothing happens.
  4. With the second RewriteCond directive uncommented, it also checks the visitor’s IP address and if it does match the one listed nothing special happens. If it does not match the one listed, the next line, which is the redirect, is executed.
  5. Checks the requested URI and if it does not begin with down-for-maintenance, a temporary redirect (HTTP status code 302) is issued that points browsers to the down-for-maintenance directory you created earlier. Obviously, if you named this directory something else, you should change this RewriteRule.

This isn’t perfect. For example, if a visitor is filling out a multi-page form then they might get interrupted half way through when you enable the curtain since the curtain takes effect starting at the next HTTP request after you enable it. That said, the only way to do truly graceful maintenance with zero downtime is load balancing, and that is beyond the capability of most simple sites, but this curtain is extremely simple and extremely effective.

7 replies on “How to use mod_rewrite rules to easily enable web site “maintenance” modes”

  1. Hey Meitar,

    This is a nice solution. I’ve seen others attempt the same thing but with more steps and less instructions on how to implement it (other than a “use this”). Your step by step explanation is really helpful.

    I’m bookmarking your site. If the rest of your articles are as well done as this, I should have some fun reading and might learn a few things along the way.

    I wish I had done this prior to throwing the site up (I need a curtain to implement the curtain).

    :-)

    Still, I’ll give is a test run on a local apache installation before putting it on the server.

    Once again, thanks…

    Michael.

  2. Hey Michael, I’m glad you liked this. :) I don’t want to vouch for the rest of my blog posts but if you do find other things valuable I hope you’ll let me know. For that matter, feel free to let me know how to improve on less-than-valuable posts as well. Constructive feedback is always appreciated.

  3. Hi Meitar,

    I thought you’d find this interesting…

    I tried putting your rewrite rules in play and ran into some problems. I’m not sure why. But anyway, I had previously bookmarked a few other pages on the net related to the same topic and I went to take a peek to see the difference in rules to get a feel for the issue at hand.

    One of them is (was?) this:

    (don’t visit it yet)

    http://www.techiecorner.com/97/redirect-to-maintenance-page-during-upgrade-using-htaccess/

    Before you go there, understand that that site has been hacked. I thought it was a joke, but I googled the hacker’s name (not putting it here so it doesn’t show up on a googlebot crawl) and it seems this guy is hitting a lot of sites. It seems like a mini epidemic with this guy.

    He even managed to effect the google cache of the page he hits.

    Anyways…he seems to hit PHP sites and since you’re running WordPress, I thought I’d pass this on to you to give you a chance to lock down your site just in case.

    Cheers…

    Michael.

  4. After a bit of experimenting, I got it to work.

    A few things made the journey a bit longer than it should have been. :-)

    1. This rewrite rule (from above) didn’t work for me:

    RewriteRule !^down-for-maintenance/.*$ /down-for-maintenance/ [R,L]

    It would put me in an endless loop.

    Instead, I put a leading backslash into it as follows:

    RewriteRule !^/down-for-maintenance/.*$ /down-for-maintenance/ [R,L]

    I can’t explain why but it works.

    2. I’m using ProxyPass and I had to put these rewrite rules above it.

    3. I had to allow for an exception with the down-for-maintenance page as follows:

    ProxyPass /down-for-maintenance !

    ———-

    The only thing that doesn’t work is testing for my IP. I get the maintenance page no matter what (when turned on). I’d like that feature to work, but I can do without it.

    The big learning lesson here: Some (many?) Apache rules are contextual. You just can’t copy and paste a solution in because the surrounding settings in your httpd.conf may influence the solution you paste in. What works on one server may not work on another without understanding the rest of the settings in place.

    Also, keep in mind your FF/IE browser cache. At one point, I thought I had something working and hit Ctrl-F5 on FF and was caught by surprise that it really wasn’t working.

    So, where I stand now: The essence of the suggested solution above works nicely. I can toggle the maintenance page on or off by simply renaming it. It’s simple and elegant.

    Michael.

  5. Well…it worked nicely on Windows. On Linux…not so much. I’m sure something else in the Linux version of the conf file is causing it to fail.

    Next up is seeing if there’s a way to determine why it’s failing in some explicit manner. The log files are not showing me anything important. It’s like trying to fix a bug without any error message or the ability to set a breakpoint. I’m swinging in the dark right now.

    I can’t tell if it’s getting confused by an Alias, if I’m not setting the right codes (R vs. PT), if ProxyPass is not playing nicely with it, or the regexp of the rule itself is a problem.

    sigh.

  6. Michael, The issue you describe with regards to not being able to copy-and-paste a solution because of surrounding settings is, unfortunately, universal to all environments. It’s simply the nature of the beast. Your environment certainly sounds different than most.

    As for not seeing any logs, note that Apache’s rewriting engine uses a different logging mechanism than the generic logs for the rest of the server. To turn it on, use the RewriteLog directive. I usually go all the way to RewriteLogLevel 9 and investigate that way, turning down the verbosity incrementally until the problem is resolved.

Comments are closed.