Apache HTTP Server Version 2.0
 
	This document refers to the 2.0 version of Apache httpd, which is no longer maintained. Upgrade, and refer to the current version of httpd instead, documented at:
You may follow this link to go to the current version of this document.
This document has not been fully updated to take into account changes made in the 2.0 version of the Apache HTTP Server. Some of the information may still be relevant, but please use it with care.
This document describes an easy way to provide your Apache
				HTTP Server with a set of customized error messages which take
				advantage of Content
					Negotiation and mod_include to return
				error messages generated by the server in the client's native
				language.
By using SSI, all ErrorDocument messages
				can share a homogenous and consistent style and layout, and
				maintenance work (changing images, changing links) is kept to a
				minimum because all layout information can be kept in a single
				file.
Error documents can be shared across different servers, or even hosts, because all varying information is inserted at the time the error document is returned on behalf of a failed request.
Content Negotiation then selects the appropriate language version of a particular error message text, honoring the language preferences passed in the client's request. (Users usually select their favorite languages in the preferences options menu of today's browsers). When an error document in the client's primary language version is unavailable, the secondary languages are tried or a default (fallback) version is used.
You have full flexibility in designing your error documents to your personal taste (or your company's conventions). For demonstration purposes, we present a simple generic error document scheme. For this hypothetic server, we assume that all error messages...
An example of a "document not found" message for a german client might look like this:
![[Needs graphics capability to display]](../images/custom_errordocs.gif)
All links in the document as well as links to the server's administrator mail address, and even the name and port of the serving virtual host are inserted in the error document at "run-time", i.e., when the error actually occurs.
For this concept to work as easily as possible, we must take advantage of as much server support as we can get:
Options, we
					enable the language selection of the most appropriate
					language alternative (content negotiation).LanguagePriority
					directive we define a set of default fallback languages in
					the situation where the client's browser did not express any
					preference at all.mod_include
					(and disallowing execution of cgi scripts for
					security reasons), we allow the server to include building
					blocks of the error message, and to substitute the value of
					certain environment variables into the generated document
					(dynamic HTML) or even to conditionally include or omit parts
					of the text.AddHandler and AddType directives
					are useful for automatically SSI-expanding all files with a
					.shtml suffix to text/html.
				Alias directive, we
					keep the error document directory outside of the document
					tree because it can be regarded more as a server part than
					part of the document tree.<Directory> block
					restricts these "special" settings to the error document
					directory and avoids an impact on any of the settings for the
					regular document tree.src/main/http_protocol.c if you wish to see
					apache's standard messages), an ErrorDocument in
					the aliased /errordocs directory is defined.
					Note that we only define the basename of the document here
					because the MultiViews option will select the best candidate
					based on the language suffixes and the client's preferences.
					Any error situation with an error code not handled
					by a custom document will be dealt with by the server in the
					standard way (i.e., a plain error message in
					english).
				AllowOverride directive tells
					apache that it is not necessary to look for a .htaccess file
					in the /errordocs directory: a minor speed optimization.The resulting httpd.conf configuration would then
				look similar to this:
						LanguagePriority en fr de 
						Alias /errordocs /usr/local/apache/errordocs 
						
						<Directory /usr/local/apache/errordocs> 
						
							AllowOverride none 
							Options MultiViews IncludesNoExec FollowSymLinks 
							AddType text/html .shtml 
							<FilesMatch "\.shtml[.$]"> 
							
								SetOutputFilter INCLUDES 
							
							</FilesMatch> 
						
						</Directory> 
						
						# "400 Bad Request", 
						ErrorDocument 400 /errordocs/400 
						# "401 Authorization Required", 
						ErrorDocument 401 /errordocs/401 
						# "403 Forbidden", 
						ErrorDocument 403 /errordocs/403 
						# "404 Not Found", 
						ErrorDocument 404 /errordocs/404 
						# "500 Internal Server Error", 
						ErrorDocument 500 /errordocs/500 
					
The directory for the error messages (here:
				/usr/local/apache/errordocs/) must then be created
				with the appropriate permissions (readable and executable by
				the server uid or gid, only writable for the administrator).
			
By defining the MultiViews option, the server was
				told to automatically scan the directory for matching variants
				(looking at language and content type suffixes) when a
				requested document was not found. In the configuration, we
				defined the names for the error documents to be just their
				error number (without any suffix).
The names of the individual error documents are now determined like this (I'm using 403 as an example, think of it as a placeholder for any of the configured error documents):
errordocs/403.shtml.lang is created and
					filled with the error text in that language (see below).
				errordocs/403.shtml is created, usually by
					creating a symlink to the default language variant (see below).
				By putting as much layout information in two special "include files", the error documents can be reduced to a bare minimum.
One of these layout files defines the HTML document header
				and a configurable list of paths to the icons to be shown in
				the resulting error document. These paths are exported as a set
				of SSI environment variables and are later evaluated by the
				"footer" special file. The title of the current error (which is
				put into the TITLE tag and an H1 header) is simply passed in
				from the main error document in a variable called
				title.
			
By changing this file, the layout of all generated error messages can be changed in a second. (By exploiting the features of SSI, you can easily define different layouts based on the current virtual host, or even based on the client's domain name).
The second layout file describes the footer to be displayed at the bottom of every error message. In this example, it shows an apache logo, the current server time, the server version string and adds a mail reference to the site's webmaster.
For simplicity, the header file is simply called
				head.shtml because it contains server-parsed
				content but no language specific information. The footer file
				exists once for each language translation, plus a symlink for
				the default language.
			
						for English, French and German versions (default english) 
						
						foot.shtml.en, 
						foot.shtml.fr, 
						foot.shtml.de, 
						foot.shtml symlink to 
						foot.shtml.en
					
Both files are included into the error document by using the
				directives <!--#include virtual="head" -->
				and <!--#include virtual="foot" -->
				respectively: the rest of the magic occurs in mod_negotiation
				and in mod_include.
See the listings below to see an actual HTML implementation of the discussed example.
After all this preparation work, little remains to be said about the actual documents. They all share a simple common structure:
						<!--#set var="title" value="error description title" --> 
						<!--#include virtual="head" --> 
						
							explanatory error text 
						
						<!--#include virtual="foot" -->
					
In the listings section, you can see an example of a [400 Bad Request] error document. Documents as simple as that certainly cause no problems to translate or expand.
Do we need a special handling for languages other than those we have translations for? We did set the LanguagePriority, didn't we?!
Well, the LanguagePriority directive is for the case where the client does not express any language priority at all. But what happens in the situation where the client wants one of the languages we do not have, and none of those we do have?
Without doing anything, the Apache server will usually return a [406 no acceptable variant] error, listing the choices from which the client may select. But we're in an error message already, and important error information might get lost when the client had to choose a language representation first.
So, in this situation it appears to be easier to define a fallback language (by copying or linking, e.g., the english version to a language-less version). Because the negotiation algorithm prefers "more specialized" variants over "more generic" variants, these generic alternatives will only be chosen when the normal negotiation did not succeed.
A simple shell script to do it (execute within the errordocs/ dir):
						for f in *.shtml.en 
						do 
						
							ln -s $f `basename $f .en` 
						
						done
					
As of Apache-1.3, it is possible to use the
				ErrorDocument mechanism for proxy error messages
				as well (previous versions always returned fixed predefined
				error messages).
			
Most proxy errors return an error code of [500 Internal
				Server Error]. To find out whether a particular error document
				was invoked on behalf of a proxy error or because of some other
				server error, and what the reason for the failure was, you can
				check the contents of the new ERROR_NOTES CGI
				environment variable: if invoked for a proxy error, this
				variable will contain the actual proxy error message text in
				HTML form.
The following excerpt demonstrates how to exploit the
				ERROR_NOTES variable within an error document:
			
						<!--#if expr="$REDIRECT_ERROR_NOTES = ''" --> 
						
						<p> 
						
							The server encountered an unexpected condition 
							which prevented it from fulfilling the request. 
						
						</p> 
						
						<p> 
						
							<a href="mailto:<!--#echo var="SERVER_ADMIN" -->" 
							SUBJECT="Error message [<!--#echo var="REDIRECT_STATUS" -->] <!--#echo var="title" --> for <!--#echo var="REQUEST_URI" -->"> 
							Please forward this error screen to <!--#echo var="SERVER_NAME" -->'s 
							WebMaster</a>; it includes useful debugging information about 
							the Request which caused the error. 
							
							<pre><!--#printenv --></pre> 
						
						</p> 
						
						<!--#else --> 
						
							<!--#echo var="REDIRECT_ERROR_NOTES" -->
						
						
						<!--#endif -->
					
So, to summarize our example, here's the complete listing of
				the 400.shtml.en document. You will notice that it
				contains almost nothing but the error text (with conditional
				additions). Starting with this example, you will find it easy
				to add more error documents, or to translate the error
				documents to different languages.
						<!--#set var="title" value="Bad Request"--> 
						<!--#include virtual="head" -->
						
						<p> 
						
							Your browser sent a request that this server could not understand: 
							<blockquote> 
							
								<strong><!--#echo var="REQUEST_URI" --></strong>
							
							</blockquote> 
							
							The request could not be understood by the server due to malformed 
							syntax. The client should not repeat the request without 
							modifications. 
						
						</p> 
						
						<p> 
						
							<!--#if expr="$HTTP_REFERER != ''" --> 
							
								Please inform the owner of 
								<a href="<!--#echo var="HTTP_REFERER" -->">the referring page</a> about 
								the malformed link. 
							
							
							<!--#else --> 
							
								Please check your request for typing errors and retry. 
							
							
							<!--#endif --> 
						
						</p> 
						
						<!--#include virtual="foot" -->
					
Here is the complete head.shtml.en file (the funny
				line breaks avoid empty lines in the document after SSI
				processing). Note the configuration section at top. That's
				where you configure the images and logos as well as the apache
				documentation directory. Look how this file displays two
				different logos depending on the content of the virtual host
				name ($SERVER_NAME), and that an animated apache logo is shown
				if the browser appears to support it (the latter requires
				server configuration lines of the form 
BrowserMatch "^Mozilla/[2-4]" anigif
for browser types which support animated GIFs).
						<!--#if expr="$SERVER_NAME = /.*\.mycompany\.com/" -->
						
							<!--#set var="IMG_CorpLogo" value="http://$SERVER_NAME:$SERVER_PORT/errordocs/CorpLogo.gif" -->
							<!--#set var="ALT_CorpLogo" value="Powered by Linux!" -->
						
						
						<!--#else --> 
						
							<!--#set var="IMG_CorpLogo" value="http://$SERVER_NAME:$SERVER_PORT/errordocs/PrivLogo.gif" --> 
							<!--#set var="ALT_CorpLogo" value="Powered by Linux!" --> 
						
						<!--#endif--> 
						
						<!--#set var="IMG_BgImage" value="http://$SERVER_NAME:$SERVER_PORT/errordocs/BgImage.gif" --> 
						<!--#set var="DOC_Apache" value="http://$SERVER_NAME:$SERVER_PORT/Apache/" --> 
						
						<!--#if expr="$anigif" --> 
						
							<!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_anim.gif" --> 
						
						<!--#else-->
						
							<!--#set var="IMG_Apache" value="http://$SERVER_NAME:$SERVER_PORT/icons/apache_pb.gif" -->
						
						<!--#endif-->
						
						<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> 
						<html> 
						<head> 
						
							<title> 
							[<!--#echo var="REDIRECT_STATUS" -->] <!--#echo var="title" --> 
							</title> 
						
						</head> 
						
						<body bgcolor="white" background="<!--#echo var="IMG_BgImage" -->"> 
						
							<h1 align="center"> 
							[<!--#echo var="REDIRECT_STATUS" -->]
							<!--#echo var="title" --> 
							<img src="<!--#echo var="IMG_CorpLogo" -->" 
							  alt="<!--#echo var="ALT_CorpLogo" -->" align="right"> 
							</h1> 
							
							<hr />
							<!-- ======================================================== --> 
							<div>
						
					
and this is the foot.shtml.en file:
						
							</div> 
							<hr /> 
							
							<div align="right"> 
							
								<small>Local Server time:
								<!--#echo var="DATE_LOCAL" --></small> 
							
							</div> 
							
							<div align="center">
							
								<a href="<!--#echo var="DOC_Apache" -->"> 
								<img src="<!--#echo var="IMG_Apache" -->" border="0" align="bottom" 
								  alt="Powered by <!--#echo var="SERVER_SOFTWARE" -->"></a> 
								<br />
								<small><!--#set var="var" value="Powered by $SERVER_SOFTWARE -- 
								File last modified on $LAST_MODIFIED" --> 
								<!--#echo var="var" --></small> 
							
							</div> 
							
							<p>If the indicated error looks like a misconfiguration, please inform 
							<a href="mailto:<!--#echo var="SERVER_ADMIN" -->" 
							subject="Feedback about Error message [<!--#echo var="REDIRECT_STATUS" -->] 
							<!--#echo var="title" -->, req=<!--#echo var="REQUEST_URI" -->"> 
							<!--#echo var="SERVER_NAME" -->'s WebMaster</a>.
							</p>
						
						
						</body>
						</html>
					
If you have tips to contribute, send mail to martin@apache.org