I recently had the pleasure of moving a Rails app from Apache/Passenger based system to an nginx/Passenger system, deployed by Capistrano. In Apache, I had a setup where I could take a production site down for maintenance by touching tmp/stop.txt and using the following directive in my VirtualHost (courtesy of Otto Hilska at Nodeta):

<VirtualHost *:80>
	ServerName www.example.com
	DocumentRoot /u/apps/example/current/public
	ErrorDocument 503 /maintenance.html
	RewriteEngine on
	RewriteCond %{DOCUMENT_ROOT}/../tmp/stop.txt -f
	RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
	RewriteCond %{SCRIPT_FILENAME} !maintenance.html
	RewriteRule ^(.*)$ /$1 [R=503,L]

	<Directory /u/apps/example/current/public>
		RailsEnv production
		Options -MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>
</VirtualHost>

This worked perfectly, and allowed me to use images/css/etc on my error documents without them being redirected to 503s as well. Based on Eli Miller’s solution, I was able to write something similar for my nginx server config:

server {
	listen 80;
	server_name www.example.com;
	error_page 503 /maintenance.html;
	root /u/apps/example/current/public;
	passenger_enabled on;
	rails_env production;

	# If the maintenance stop file exists
	if (-f $document_root/../tmp/stop.txt) {
		set $maintenance 1;
	}

	# If the request exists as a static file in public
	if (-f $document_root/$uri) {
		set $maintenance 0;
	}

	if ($maintenance) {
		return 503;
	}
}

I was able to test this successfully with nginx 0.7.67 and 0.8.53, and Passenger 2.2.15 and 3.0.1. If you know a better/clearer way to do this, please share!