mod-rewriteapache2maintenance-mode

Apache2 mod_rewrite to custom maintenance.html page


I have the following situation. I have for my webapp under /var/www the folder "my_project". Now I want to display a maintenance page using mod_rewrite.

For this I have placed under /var/www the file "maintenance.html". Additionally I added the following rewrite conditions including the following rewrite rule in the config file for the "my_project" folder under /etc/apache2/sites-available :

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName my_project.de
    ServerAlias www.my_project.de

    DocumentRoot /var/www/my_project.de/public

    <Directory /var/www/my_project.de/public/>
      Options Indexes FollowSymLinks MultiViews
      AllowOverride All
      Require all granted
    </Directory>

    RewriteEngine on
    RewriteCond /var/www/maintenance.html -f
    RewriteCond %{REQUEST_URI} !^/maintenance\.html$
    RewriteCond %{REMOTE_ADDR} !^00\.00\.00\.000
    RewriteRule ^ - [R=503]
    ErrorDocument 503 /var/www/maintenance.html
    

    LogLevel debug
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Now I get the message "Service Unavailble. The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later", if the file "maintenance.html" is located in the folder /var/www. However, I want the maintenance.html file to be displayed instead of the message described above.

Can anyone tell me what I may be doing wrong or understanding here?

UPDATE:

I adjusted the config file and the above config represents the current situation. However this seems to result in a redirect loop. Because in the error.log file of apache is the following written:

Error logs:

AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /var/www/maintenance.html
AH00122: redirected from r->uri = /login

Note: I already tried a relative path vor the maintenance.html file but that did not work as well (e.g. /maintenance.html)

FINAL SOLUTION:

Thanks to @MrWhite I got it working. The final vHost config looks like this:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName my_project.de
    ServerAlias www.my_project.de
    
    Alias /errordocs /var/www

    # Permit access to the Alias target
    <Directory /var/www>
        Require all granted
    </Directory>

    ErrorDocument 503 /errordocs/maintenance.html

    DocumentRoot /var/www/my_project.de/public

    <Directory /var/www/my_project.de/public/>
      Options Indexes FollowSymLinks MultiViews
      AllowOverride All
      Require all granted
    </Directory>

    RewriteEngine on
    RewriteCond /var/www/maintenance.html -f
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{REMOTE_ADDR} !^00\.00\.00\.000
    RewriteRule ^ - [R=503]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

In order to "activate" the maintenance mode it is now only required to place a "maintenance.html" file in the directory "var/www/".


Solution

  • RewriteRule (.*) /maintenance.html [R=503,L]
    

    When using the R flag with a non-3xx status, the substitution string is ignored (you should ideally include a single hyphen as the substitution in this case).

    To serve /maintenance.html in this case you should set an appropriate ErrorDocument and simply use the R=503 flag in the RewriteRule directive to trigger this via an internal subrequest.

    For example

    ErrorDocument 503 /maintenance.html
    
    :
    RewriteRule ^ - [R=503]
    

    The L flag is also unnecessary when specifying a non-3xx status, since it is implied.

    If the rule is inside a <Directory> block that targets the my_project subdirectory then you don't need the condition that checks the request is not already /maintenance.html. The ErrorDocument should probably be defined outside of the <Directory> container.


    UPDATE:

    The ErrorDocument directive requires a root-relative URL-path, not an absolute file-path. Consequently this error document needs to exist within the confines of the vHost. It would seem from your updated config that the my_project "subdirectory" is in fact its own vHost, not a subdirectory off the "parent" (as I assumed).

    If you want to use an ErrorDocument that is located elsewhere on the filesystem (ie. outside of the vHost) then you could use an Alias to point to this other location.

    For example, in your existing vHost for my_project.de:

    Alias /errordocs /var/www
    
    # Permit access to the Alias target
    <Directory /var/www>
        Require all granted
    </Directory>
    
    ErrorDocument 503 /errordocs/maintenance.html
    

    Alternatively you could configure /var/www/my_project.de/public/maintenance.html as a symlink to /var/www/maintenance.html.

     RewriteCond %{REQUEST_URI} !^/maintenance\.html$
    

    This condition will need to be modified to include the /errordocs prefix. Alternatively, remove this condition altogether and modify the RewriteRule pattern. For example:

    RewriteRule !^/errordocs/maintenance\.html$ - [R=503]
    

    A minor issue with your existing mod_rewrite implementation is that direct requests to the ErrorDocument itself will be served with a 200 OK status and potentially be indexed by search engines. (Not that this should be a serious issue since the location of this file is unknown to the user - better than when it is located in the document root). However, this can be resolved with the following instead:

    # Trigger a 503 for all "user" requests
    RewriteCond /var/www/maintenance.html -f
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{REMOTE_ADDR} !^203\.0\.113\.111
    RewriteRule ^ - [R=503]
    

    The check against the REDIRECT_STATUS environment variable ensures that only direct requests from the client are processed, not internal subrequests.