It's a good idea to have a server maintenance strategy in place during the early phases of any project. Along with CI, provisioning multiple stages, and an efficient way to deploy new features to the client and eventually to production, a strategy for server maintenance from the outset of the project will save time as the application ages.

If your Rails app is already in the wild, no worries. Here are a few easy steps to modify Apache to detect a maintenance mode and a Capistrano task to turn it on and off.

First, you'll need to add these lines to you Apache virtual host configuration:

RewriteEngine On ErrorDocument 503 /system/maintenance.html RewriteCond %{REQUEST_URI} !.(css|gif|jpg|png)$ RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ - [L,R=503]

This tells Apache to bypass the app when it detects the presence of a maintenance file. Instead of serving the request, it will return the maintenance page with the status code 503. If Apache is already running, you'll want to restart it before you try to roll it into maintenance mode.

Next, you'll want to create a maintenance page for your app. A good place to put the file is /public/maintenance.html . Remember, the page will bypass Rails completely, so make sure it's a fully valid HTML file (although the rewrite rules will still serve CSS and image files).

Last, add two Capistrano tasks to turn maintenance mode on and off. The first copies the maintenance page to the place where Apache will start serving it. The second will remove it. Add these lines to deploy.rb:

namespace :deploy namespace :web do desc "Enable maintenance mode for apache" task :disable, :roles => :web do on_rollback { run "rm -f #{shared_path}/system/maintenance.html" } page = File.read('public/maintenance.html') put page, "#{shared_path}/system/maintenance.html", :mode => 0644 end desc "Disable maintenance mode for apache" task :enable, :roles => :web do run "rm -f #{shared_path}/system/maintenance.html" end end end

Now when you want to set a stage into maintenance mode (integration in this example), just run the task:

cap integration deploy:web:disable

To disable maintenance mode, run:

cap integration deploy:web:enable

And there you have it: maintenance mode, easy mode.

A few caveats:

Make sure the shared path for Capistrano has a system directory. Otherwise, you'll get an error writing the maintenance file there. Be careful if there is a load balancer in front of your app servers. It might be configured NOT to serve 503s, but instead start ignoring that app server.

A few links I used to write this post: