I must not be the only one who occasionally wants to stop a Ruby on Rails application. There are long-running and risky database schema migrations and data migrations, and you don’t want users fiddling the system in the middle of the deployment.

With a Mongrel-based setup it was easy to set up a 503 (Service unavailable) error page and then just shut down all the Mongrels, so that Apache could give users a maintenance page. Using mod_rails (Phusion Passenger), only restart is supported out-of-the-box.

However, it’s possible to use mod_rewrite to prevent users from accessing your site during the deployment. Try this in your Apache virtual host configuration file:

# This option is not needed with Passenger >=2.1.1.
RailsAllowModRewrite on

ErrorDocument 503 /503.html

RewriteEngine on

RewriteCond %{DOCUMENT_ROOT}/../tmp/stop.txt -f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /$1 [R=503,L]

Basically the last three lines mean:

  1. If there is a tmp/stop.txt file
  2. and user is requesting a file that does not directly exist in the file system
  3. then return error 503 and render the appropriate maintenance page

It doesn’t actually stop your Rails processes, though. They will die when Passenger times out.

Now it’s also easy to incorporate this to your Capistrano configuration:

namespace :passenger do
  desc "Restart Passenger"
  task :restart, :roles => :app do
    run "touch #{current_path}/tmp/restart.txt"
  end

  desc "Stop Passenger"
  task :stop, :roles => :app do
    run "touch #{current_path}/tmp/stop.txt"
  end

  desc "Start (or un-stop) Passenger"
  task :start, :roles => :app do
    run "rm -f #{current_path}/tmp/stop.txt"
  end
end

After this it’s safe to deploy big new releases without completely taking down your Apache.