Install a maintenance page without restarting apache
2009 mai 8 4 Commentaires
These days we are working with fabric to remove some hazard in maintenance.
Recently someone gzip a Data.fs file in production and our customer loose 2 days of work. We choose to use fabric (http://www.nongnu.org/fab/) to limit command line working to the strict minimum.
Now, almost all procedures were added in a fabric factory, from the installation of a development environment to the upgrade of the production server. In this last part, we search a solution to put a maintenance page without have to gain root privileges to restart the apache used in frontend. For static or CGI sites you can use a .htaccess file to override the global rules. For a stopped Zope server it doesn’t help much.
The goal is to use RewriteCond and RewriteRule in a such way that a static HTML file would be displayed when it exists. We can call it ‘maintenance.html‘ and rename it ‘maintenance.html-disabled‘ to let the site be displayed normally.
We start with a virtual host generated by iw.recipe.squid:
<VirtualHost *:80>
ServerName www.gosseyn.fr
RewriteEngine On
RewriteLog /my/path/to/squid/parts/squid/log/rewrite_www.gosseyn.fr.log
RewriteLogLevel 0
CustomLog /my/path/to/squid//parts/squid/log/access_www.gosseyn.fr.log common
ErrorLog /my/path/to/squid//parts/squid/log/error_www.gosseyn.fr.log
## common rules for squid rewrite rules
RewriteRule ^(.*)$ - [E=BACKEND_LOCATION:127.0.0.1]
RewriteRule ^(.*)$ - [E=BACKEND_PORT:8081]
RewriteRule ^(.*)$ - [E=BACKEND_PATH:site]
RewriteRule ^/(.*)/$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
RewriteRule ^/(.*)$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
## specific rules base on cookie
</VirtualHost>
First we need to declare a document root and to bypass all security rules. We create a new path in the root of our buildout folder called ‘maintenances_pages’.
DocumentRoot /my/path/to/buildout/prod/maintenance_pages
<Directory "/my/path/to/buildout/prod/maintenance_pages">
Options None
AllowOverride None
Order allow,deny
allow from all
<LimitExcept GET>
Order allow,deny
allow from all
</LimitExcept>
</Directory>
These declaration should satisfy all paranoid BOFH.
Now create a file called maintenance.html within the folder. All code (javascript, CSS and images) must be embeded, this is a limitation of this approach.
Well, how to detect that a file exist on the filesystem from apache. You can do this with the flag ‘-f’ from the rewrite module:
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html -f
Then redirect all pages to our maintenance page:
RewriteCond %{REQUEST_URI} !/maintenance.html
RewriteRule $ /maintenance.html [R=302,L]
We also need to disable the standard rewrite rules. The easier way to do it is to use ‘!-f‘.
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html !-f
RewriteRule ^/(.*)/$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html !-f
RewriteRule ^/(.*)$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
These rules will not be applied anymore when our maintenance file will be name ‘maintenance.html’. Our goal is reached.
The whole virtualhost file look like this:
<VirtualHost *:80>
ServerName www.gosseyn.fr
RewriteEngine On
RewriteLog /my/path/to/squid/parts/squid/log/rewrite_www.gosseyn.fr.log
RewriteLogLevel 0
CustomLog /my/path/to/squid//parts/squid/log/access_www.gosseyn.fr.log common
ErrorLog /my/path/to/squid//parts/squid/log/error_www.gosseyn.fr.log
DocumentRoot /my/path/to/buildout/prod/maintenance_pages
<Directory "/my/path/to/buildout/prod/maintenance_pages">
Options None
AllowOverride None
Order allow,deny
allow from all
<LimitExcept GET>
Order allow,deny
allow from all
</LimitExcept>
</Directory>
## our maintenance page
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html -f
RewriteCond %{REQUEST_URI} !/maintenance.html
RewriteRule $ /maintenance.html [R=302,L]
## common rules for squid rewrite rules
RewriteRule ^(.*)$ - [E=BACKEND_LOCATION:127.0.0.1]
RewriteRule ^(.*)$ - [E=BACKEND_PORT:8081]
RewriteRule ^(.*)$ - [E=BACKEND_PATH:site]
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html !-f
RewriteRule ^/(.*)/$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
RewriteCond /my/path/to/buildout/prod/maintenance_pages/maintenance.html !-f
RewriteRule ^/(.*)$ http://127.0.0.1:3128/%{ENV:BACKEND_LOCATION}/%{ENV:BACKEND_PORT}/http/%{SERVER_NAME}/80/%{ENV:BACKEND_PATH}/__original_url__/$1 [L,P]
## specific rules base on cookie
</VirtualHost>
It will be difficult to include this in a recipe as we modify an existing virtualhost in a very specific way.
As usual, all feedbacks are appreciated.
Have tried using iw.recipe.cmd with sed to apply the transformations automatically?
Using sed suppose that you drop windows compatibity.
Very usefull as usual !
I remember this kind of tips on a previous post :
http://zebert.blogspot.com/2007/12/maintenance-mode-for-apache.html
Yes, it is a variant of this one.