My solution:
- Create a maintenance mode template and link to it via a urlconf, so when visiting /under-maintenance/ a maintenance page is shown.
- Then, configure apache to test for the presence of a 'maintenance-mode-on' file, and if it is present do a 302 redirect to the url of the maintenance mode page.
- Configure apache to redirect from the maintenance mode URL to the home page, if the 'maintenance-mode-off' file is present.
- Fabric script to facilitate switching the files between maintenance-mode-on and maintenance-mode-off.
Here's the relevant section of the Apache config file:
RewriteEngine On
# If this file (toggle file) exists then put the site into maintenance mode
RewriteCond /path/to/toggle/file/maintenance-mode-on -f
RewriteCond %{REQUEST_URI} !^/static.*
RewriteCond %{REQUEST_URI} !^/admin.*
RewriteCond %{REQUEST_URI} !^/under-maintenance/
# redirect to the maintenance mode page
RewriteRule ^(.*) /under-maintenance/ [R,L]
#If not under maintenance mode, redirect away from the maintenance page
RewriteCond /path/to/toggle/file/maintenance-mode-off -f
RewriteCond %{REQUEST_URI} ^/under-maintenance/
RewriteRule ^(.*) / [R,L]
Then the relevant parts of the fabric script:
env.var_dir = '/path/to/toggle/file/'
def is_in_mm():
"Returns whether the site is in maintenance mode"
return files.exists(os.path.join(env.var_dir, 'maintenance-mode-on'))
@task
def mm_on():
"""Turns on maintenance mode"""
if not is_in_mm():
with cd(env.var_dir):
run('mv maintenance-mode-off maintenance-mode-on')
utils.fastprint('Turned on maintenance mode.')
else:
utils.error('The site is already in maintenance mode!')
@task
def mm_off():
"""Turns off maintenance mode"""
if is_in_mm():
with cd(env.var_dir):
run('mv maintenance-mode-on maintenance-mode-off')
utils.fastprint('Turned off maintenance mode.')
else:
utils.error('The site is not in maintenance mode!')
This works well, though it does depend on Django handling requests during maintenance mode; it would be nice to just serve a static file.