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:

cat /etc/apache2/shared/restricted-nets.conf
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 webmaster@domain.tld
        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).

Leave a comment

NOTE: Enclose quotes in <blockquote></blockquote>. Enclose code in <pre lang="LANG"></pre> (where LANG is one of these).