Okay - the logic of my brain is far from the logic of how code in a .htaccess file gets processed... to bad as it get frustrating sometimes when you try to achieve something "logical".
I would like to set a custom ErrorDocument when variable MAINTENANCE_MODE is set but it will simply not load the correct file. Is this because the If-directive is looked at earlier than the RewriteRules?
SetEnv MAINTENANCE_MODE 1
ErrorDocument 503 /msg/503_default.html
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{ENV:MAINTENANCE_MODE} 1
RewriteRule ^ - [E=MAINTENANCE_503:1]
</IfModule>
<If "%{ENV:MAINTENANCE_503} == '1'">
ErrorDocument 503 /msg/503_maintenance.php
RewriteRule !^503 - [R=503]
</If>
When it's totally not possible, which alternative route would be producing the best result?
Would that be to create a 503_default.php which can receive a value so it knows which custom message to show? If so, how do I set/pass that value onto the default 503 page?
Btw - this is just a simplified base version of what it will have to become. I also have other scenario's in which I want to serve a custom 503 message. But without a base there is not point in writing extended code :)
Okay - with help of the input from MrWhite to this and my previous question I managed to land on a working solution with a custom ErrorDocument 503. Thanks @MrWhite!
The requirement
A custom 503 message for 3 specific situations:
The third reason might need some explanation. We (a community of whisky enthousiasts) buy casks and anyone in the community can buy a share of it through the shop, as long as it's in stock of course. We always release products at 1900 CE(S)T after announcing it first in the newsletter. So especially with popular/hard to get brands it can get busy real fast on the server as typically we have between 30 to 100 caskshares in a cask and the community has over 1.000 members these days. So this measure helps us to crash only at a later load and has helped us to reduce the occurrences of crashing the site from roughly 3 times a year to 0 (so far, in the last 3 years). As it's a profitless hobby initiative we just keep the webhosting costs under control as we can't justify to enlarge the server capacity for just that handful of times in a year.
The solution
The .htaccess file
Let's start with the .htaccess file. The (simplified) code I landed on is:
SetEnvIf ^ ^ GEO_BLOCK_MODE=1
SetEnvIf ^ ^ MAINTENANCE_MODE=0
SetEnvIf ^ ^ PRODUCT_RELEASE_MODE=1
ErrorDocument 503 /msg/503_handler.php
RewriteEngine On
# [0] off [1] on
RewriteCond %{ENV:GEO_BLOCK_MODE} =1
RewriteCond %{ENV:REDIRECT_STATUS} !=503
RewriteCond %{ENV:GEOIP_CONTINENT_CODE} ^(AF|AS|SA)$ [OR]
RewriteCond %{ENV:GEOIP_CONTINENT_CODE_V6} ^(AF|AS|SA)$ [OR]
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(AL|AM|AZ|BY|BG|GE|KZ|MD|MK|RO|RU|TR)$ [OR]
RewriteCond %{ENV:GEOIP_COUNTRY_CODE_v6} ^(AL|AM|AZ|BY|BG|GE|KZ|MD|MK|RO|RU|TR)$
RewriteCond %{REQUEST_URI} ^/shop/?.* [NC]
RewriteRule ^ - [R=503,E=503_MODE:GEO_BLOCK]
# [0] off [1] this morning | afternoon | evening/night [2] entire day [3] this weekend
RewriteCond %{ENV:MAINTENANCE_MODE} !=0
RewriteCond %{ENV:REDIRECT_STATUS} !=503
RewriteRule ^ - [R=503,E=503_MODE:MAINTENANCE]
# [0] off [1] on
RewriteCond %{ENV:PRODUCT_RELEASE_MODE} =1
RewriteCond %{TIME_HOUR}%{TIME_MIN} >1844
RewriteCond %{TIME_HOUR}%{TIME_MIN} <1946
RewriteCond %{DOCUMENT_ROOT}/.productrelease -f
RewriteCond %{REQUEST_URI} ^/(forum|etcetera)(/.*)?$ [NC]
RewriteRule ^ - [R=503,E=503_MODE:PRODUCT_RELEASE]
With GEO_BLOCK_MODE
set to 1
the section is enabled.
Then we check if the page is not a redirected page with code 503 before we continue with the other conditions we want to be applicable to the situation.
At the end we redirect to 503 and set a 503_MODE
$_SERVER variable we can retrieve in our 503_handler.php via REDIRECT_503_MODE
.
The other 2 sections are setup in the same fashion and with regards to the PRODUCT_RELEASE_MODE
section... there are 2 cronjobs running on the server:
The 503_handler.php file
The code in our .htaccess leads us to a custom 503 handler file. Which I have setup as follow to suit my needs:
<?php
$minutes = 15;
$retry_after = date("D, d M Y H:i:s T", strtotime('+' . $minutes . ' minutes'));
$refresh = $minutes * 60;
header('HTTP/1.1 503 Service Unavailable', true, 503);
header('Retry-After: '. $retry_after );
header('Refresh: '. $refresh .'; url=' . $_SERVER["REQUEST_URI"] );
switch( $_SERVER['REDIRECT_503_MODE'] ) {
case "GEO_BLOCK":
$class = "bg-yellow";
$title = "Service Unavailable";
$text = "...";
break;
case "MAINTENANCE":
$class = "bg-blue";
$title = "Maintenance Window";
switch( $_SERVER['REDIRECT_MAINTENANCE_MODE'] ) {
case 2: # today, entire day
$text = "...";
break;
case 3: # this weekend
$text = "...";
break;
# case 1: # dynamic: morning | afternoon | evening/night
default:
$hour = date('G');
if( $hour >= 6 && $hour < 12 ) {
$text = '...morning';
} elseif( $hour >= 12 && $hour < 18 ) {
$text = '...afternoon';
} else {
$text = '...evening/night';
}
break;
}
break;
case "PRODUCT_RELEASE":
$class = "bg-blue";
$title = "Scheduled Downtime";
$text = "...";
break;
default:
$class = "bg-purple";
$title = "Service Unavailable";
$text = "...";
break;
}
?><!DOCTYPE html>
<html>
...
Okay - this is just the bare bones of my custom 503_handler.php file but it gives you a clear idea on how to set it up and how to capture the values we've setup / generated within our .htaccess code.
That's it
And that is it.
I now have a working solution to show custom 503 messages for the 3 defined satiations and best of all:
Sweet!