? tweets | tweet this
Sometimes we need to take our web apps offline temporarily (usually for scheduled major updates or emergency repair work), whereby regular users are shown a simple static page notifying them that the site is unavailable but still giving developers/admins full access to the site to test changes. Of course you could implement this in your application, but wouldn’t it be nice if you could get your web server to do it all for you?
Its not as hard as it sounds thanks to some great Apache modules, most notably mod_rewrite.
Here are the basic rules we regularly use at Neutron Creations (I’ll go in to more detail in a moment), these go inside our .htaccess file, but with some modification could go in the main httpd.conf file if you’d prefer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Part I RewriteCond APP_ROOT/maintenance.txt -f RewriteRule SUPER_SECRET_URL / [R,L,CO=AllowMaintenance:1:YOUR-DOMAIN.COM] # Part II RewriteCond APP_ROOT/maintenance.txt -f RewriteCond %{REQUEST_URI} !^/maintenance/ RewriteCond %{HTTP_COOKIE} !AllowMaintenance RewriteRule .* /maintenance/ [L] # Part III RewriteCond APP_ROOT/maintenance.txt -f RewriteRule ^(.*)$ - [env=MAINTENANCE:1] Header set cache-control "max-age=0,must-revalidate,post-check=0,pre-check=0" env=MAINTENANCE Header set Expires -1 env=MAINTENANCE |
This technique uses the presence of a file (APP_ROOT/maintenance.txt) to enforce a set of rules. To enter maintenance mode simply create this file with touch APP_ROOT/maintenance.txt, to leave maintenance mode remove this file with rm APP_ROOT/maintenance.txt. You’ll need to replace APP_ROOT with whatever makes sense in your application environment.
I tried to set this relative to Apache’s DOCUMENT_ROOT but could not get this to work, if anyone knows how to do this please do let me know in the comments. Thanks to ianjs for pointing out the correct syntax for this, you can use %{DOCUMENT_ROOT} in place of an absolute value for APP_ROOT to reference your document root
This provides developers (or anyone who knows the secret URL) with continued access to the app by setting a cookie that will be remembered for the session, and used in later rules. You will need to change YOUR-DOMAIN.COM to be the correct domain for your app, you could also add an expire time on this cookie if you wish (more info in the mod_rewrite flags docs).
You will also need to ensure the SUPER_SECRET_URL is set to something suitable, complex enough to be unguessable by users but easily read out if case you need to give it out over the phone.
This is the key set of rules for what we’re trying to achieve, and reads like this: IF we are in maintenance mode AND the request is not for the maintenance page AND the AllowMaintenance cookie is not set THEN redirect the request to the maintenance page.
The maintenance page must be completely self contained within this maintenance directory, as any sub-requests outside of this path (for any CSS/JS assets used on the maintenance page for example) will be redirected to the maintenance page themselves.
With this directive, Apache will serve an internal redirect so the user will still see their original URL in their address bar, allowing them to refresh to try again later. If you want an external redirect so that the user sees the ‘/maintenance’ URL instead, then just add the R flag to this RewriteRule.
This part could be quite important depending on how aggressively you cache HTTP requests in your application. Using an environment variable that’s only set if you’re in maintenance mode, we override any cache related headers sent from your app, making all requests expire immediately and telling proxies/caches to avoid caching anything going forward. You’ll need mod_headers enabled for this part to work.
So there you have it, a very simple method to gracefully shift your web app into maintenance mode, completely independent of your application code itself. I’m sure this could be expanded upon and I’d love to see any ideas you might have for building on this technique, so drop a comment here and let me know.
Photo credit: tweek
Update: Its important to make sure that if you are NOT using an external redirect in Part II that you need to be careful linking to any assets as any relative paths will be relative to the url that user was trying to reach. Try to use absolute links where possible. I wasn’t clear about this before, thanks to Dasha for pointing this out.
Update 2: I’ve been asked if it would be possible to serve a 503 (or similar) response to search engines to prevent them indexing the maintenance page. I have an alternate solution for this, if you serve an external redirect with a status code ‘307 – Temporary Redirect’, by adding the R=307 flag in Part II, this will tell search engines to ignore the response and continue to index the original page. In addition you can add a ‘Retry-After’ header to inform them when to try again, just add this after the other Header directives Header set Retry-After 1800 env=MAINTENANCE which says to try again after 30 minutes.
Ben
March 18th 2010 @ 11:09 am #
I’m glad you’re on my side. Apache configs look like the result of some frantic keyboard mashing to me.
Gary
March 19th 2010 @ 10:27 am #
This is great stuff!
Is there a way to allow Google to still crawl the site, even while the site is in maintenance mode?
Marc
March 19th 2010 @ 11:53 am #
@Gary
You could add another condition to part II that goes something like “RewriteCond %{USER_AGENT} !/Googlebot/” this would prevent the redirection happening for the google crawler. This would allow users to access the site too by spoofing their user agent. Having thought about this a bit more it may be better to serve a 503 response to the google crawler (or any other crawlers) during maintenance mode which would keep it away from your site and prevent it from indexing/caching the maintenance page. I’ll update the post shortly showing how to do that.
Gary
March 19th 2010 @ 12:20 pm #
Thanks Mark
I often use maintenance mode when setting up a new site.
Whilst I do not want the public to be able to view the site, it would be good if Google could start indexing it. That way if a site takes 4 – 8 weeks to develop I am that far ahead in my SEO efforts. Does that make sense?
Marc
March 19th 2010 @ 12:31 pm #
@Gary
Yes, that makes perfect sense. I had not thought of using this during development. We tend to use a staging server with IP restrictions instead and only use maintenance mode for subsequent deployments on the live servers.
Gary
March 19th 2010 @ 12:35 pm #
Hi Marc
When there is already a live site in place then we use a development server and swap to the live server after sign off.
But for new domains we save the swap over time and just use maintenance mode on the live server. As these are new domains, allowing Google to index at as early a stage as possible would be great.
Nico du Plessis
March 26th 2010 @ 6:36 am #
Great article and most definitely a trick that belongs in every web developer’s toolbox
Mike
March 26th 2010 @ 8:18 am #
You mention checking the user agent. I could see myself checking for a specially-crafted user agent while in maintenance mode instead of SUPER_SECRET_URL. Wouldn’t work in different browsers, but this is assuming maintenance is fixing simple bugs or rolling out already-tested code.
With Firefox and the User Agent Switcher it’d be a snap.
A simple technique for web app maintenance modes using Apache « Neutron Creations « Netcrema – creme de la social news via digg + delicious + stumpleupon + reddit
March 26th 2010 @ 9:15 am #
[...] A simple technique for web app maintenance modes using Apache « Neutron Creationsneutroncreations.com [...]
Adam
March 26th 2010 @ 10:47 am #
Very useful technique, thanks Marc.
Gary: Giving Google early access to a new site is potentially dangerous for your appearance in Google’s rankings if they notice you doing it. Google doesn’t look kindly on its bots being served different content to real users, even if the intentions are good.
Dasha
April 1st 2010 @ 2:56 pm #
Hello Marc,
Very useful article, thanks a lot!
You mentioned that the maintenance page should be self contained. I use pic and some external css on my maintenance page. I put all the necessary files into the same folder where the maintenance.html is and linked them correctly. However, img and css aren’t picked up at all :(
Any tips what I’m doing wrong?
I would really appreciate any help :)
Many thanks,
Dasha
ianjs
June 10th 2010 @ 9:28 am #
This works for me:
Is that what you were trying to do?
Marc
June 16th 2010 @ 11:03 pm #
Thanks @Dasha and @ianjs for your feedback, I’ve update the post with this extra information.