Custom Maintenance Pages
Update: The Advanced Rails Recipes book includes an updated and extended version of this recipe. Thanks for your support!
Capistrano makes it quick and easy to put up a temporary maintenance page while you're doing chores around your production Rails app. Hopefully users won't see that page for long, but even when they do it's a nice touch to customize the page a smidge.
The stock maintenance page template that Capistrano uses by default is good,
but it's easy to set your app apart from the rest. Simply redefine the
disable_web task in your deploy.rb file to render a
custom template. Here's an example:
task :disable_web, :roles => :web do
on_rollback { delete "#{shared_path}/system/maintenance.html" }
maintenance = render("./app/views/layouts/maintenance.rhtml",
:deadline => ENV['UNTIL'],
:reason => ENV['REASON'])
put maintenance, "#{shared_path}/system/maintenance.html",
:mode => 0644
end
This task uses ERb to render your local maintenance.rhtml template,
and transfers the result to the maintenance.html file on all remote
hosts in the web role.
I tend to put the maintenance.rhtml template in the
layouts directory because it's a full HTML file like
the other layout files, not just a fragment of HTML. Here's an example maintenance.rhtml template, sans all the surrounding HTML:
<h1>
We're currently down for <%= reason ? reason : "maintenance" %>
as of <%= Time.now.strftime("%H:%M %Z") %>.
</h1>
<p>
Sorry for the inconvenience. We'll be back
<%= deadline ? "by #{deadline}" : "shortly" %>.
Please email us if you need to get in touch.
</p>
You'll also need to tell your web server to check for the static maintenance file and redirect all requests to it if the file exists. Here's an example for Apache:
RewriteCond %{REQUEST_URI} !\.(css|jpg|png)$
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]
Then, when it's time for some app maintenance, you can put up your custom maintenance page by typing
cap disable_web
Here's an example of what you'd see if we were cleaning out the dust bunnies on one of our apps:
And when you've finished, simply take down the maintenance page by typing
cap enable_web
Another benefit of redefining disable_web and using a custom
template is being able to define in any variables you like. Here's how
you'd pass in the two variables used in the template above, but you can imagine
defining an arbitrary number of variables:
UNTIL="16:00 MST" REASON="a database upgrade" cap disable_web
Ideally your site would never be down, but once in a while you need to do some preventative maintenance. People who use your app will appreciate that you've taken the time to spruce up the edge cases.