Display a custom HTML message instead of a default Apache ErrorDocument for select Virtual Hosts
At work, needed to serve up a custom HTML page in place of a default Apache 403 ErrorDocument for some sites. As per Apache documentation on the subject, it's trivial to serve up a custom HTML message by pointing to a remote URL.
ErrorDocument 403 http://domain.tld/message.html
Sadly, this method causes a redirect and thus changes the HTTP response code from 403 (Forbidden) to 302 (Found), which is problematic if your goal is to return an error. Also, specifying an ErrorDocument that points to a remote URL is not even allowed for a 401. So the only option is to return a "local" document (e.g. relative to the DocumentRoot), which doesn't work well if you're using virtual hosts and want the custom ErrorDocument to be seamlessly available to lots of them, but not all.
Fortunately, there's a third way.
Apache will let us specify a custom message:
ErrorDocument 403 "No soup for you!"
And there's no reason why the custom message can't be in HTML (with some characters like quotes and newlines escaped). Here's an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
ErrorDocument 403 "\ <html>\ <title>403 Forbidden</title>\ <body>\ <h1>Oops, access is slightly restricted</h1>\ <p>Access to this site is restricted to work nets.</p>\ <ul>\ <li>Maybe use a VPN client, which you can <a href=\"http://domain.tld/path/to/link\">get from here</a>.</li>\ <li>If you can't, let us know and we'll create an exception for your net.</li>\ </ul>\ <p>If you'd like to complain, you can do so <a href=\"http://domain.tld/path/to/link\">here</a>.</p>\ </body>\ </html>" <Location /> Order Deny,Allow Deny from all # Some nets Allow from 123.456.789.012/16 456.789.012.345/24 # Partial net Allow from 10.3 #Another net Allow from 789.012.345.678/30 </Location>
Then we can include the path to the shared config inside a VirtualHost section of any site for which the above directives should be loaded:
1 2 3 4 5 6 7 8 9 10 11
<VirtualHost 123.456.789.012:80> ServerName mysite.domain.tld ServerAdmin email@example.com DocumentRoot /var/www/mysite ErrorLog /var/log/apache2/mysite_error.log CustomLog /var/log/apache2/mysite_access.log combined LogLevel warn ServerSignature On Include "/etc/apache2/shared/restricted-nets.conf" </VirtualHost>
Voilà, a lovely custom HTML message alongside a proper HTTP status code (401, 403, whatever).