SSI, Server Side Includes, can be very useful to webmasters and visitors alike. They are easily set up in an .htaccess file and require little to no maintaining.. the term "Set it and Forget it" applies here. Before we look at how to implement SSI, and dig into the Apache module that makes them possible, lets look at few uses for SSI so you can quickly determine if you would like to read further.
In your /uploads/.htaccess
# turn on auto-indexing and turn off SSI's ability to exec Options None Options SymLinksIfOwnerMatch Indexes IncludesNOEXEC # we need to make sure files are displayed when requested, not executed or parsed AddType text/plain .ini .sh .bsh .bash .csh .var .asc .md5 .sha .sha1 .cgi .pl .php .inc .asp .exe .bin DefaultType text/plain # turn on auto-indexing, with askapache-optimized options IndexOptions FancyIndexing SuppressColumnSorting SuppressHTMLPreamble IconHeight=22 IconWidth=20 IndexOptions IgnoreClient NameWidth=40 DescriptionWidth=* XHTML FoldersFirst # don't show these files and folders IndexIgnore .htaccess .ht* *_notes *.log feed inc HEADER.html FOOTER.html feed*.gif # the SSI files used for the header and footer HeaderName /ssi/HEADER.html ReadmeName /ssi/FOOTER.html # used to determine the time and for SSI output SetEnv TZ America/Las_Vegas SetEnv SERVER_ADMIN webmaster@askapache.com
In your /ssi/.htaccess
# makes files ending in .html be filtered through the INCLUDES filter before being sent to client AddOutputFilter Includes html
My HEADER.html
<!--#set var="PAGETITLE" value="-- s.askapache.net" --> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title><!--#echo encoding="none" var="REQUEST_URI" --> <!--#echo encoding="none" var="PAGETITLE" --></title> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" href="https://www.askapache.com/s/s.askapache.net/c/error.css" /> <link rev="made" href="mailto:<!--#echo encoding="url" var="SERVER_ADMIN" -->" /> </head> <body> <h1><a href="https://www.askapache.com/" title="AskApache Home" accesskey="1"> <img src="https://www.askapache.com/nlogo.jpg" height="75" alt="AskApache" /> </a> <!--#echo encoding="url" var="REQUEST_URI" --> <!--#echo encoding="none" var="PAGETITLE" --></h1> <hr />
My FOOTER.html
<p>Find the information you are looking for on the <a href="https://www.askapache.com/">AskApache Home page</a> or the "> AskApache search page.</p> <hr /> <address> <small>:<!--#echo encoding="none" var="UNIQUE_ID" --> E:<!--#echo encoding="none" var="REDIRECT_STATUS" -->,v 1.30 <!--#config timefmt="%c" --><!--#echo var="DATE_LOCAL" --></small><br /> <small><!--#echo var="SERVER_SOFTWARE" --></small><br /><br /> s.askapache.net -- AskApache | <a href="https://www.askapache.com/about/">Webmaster</a> | Copyright © 2009 AskApache<br /> </address> <!--#if expr=" = 10.10.10.10" --> <pre ><!--#printenv --></ pre> <!--#endif --> <script src="https://www.askapache.com/s/s.askapache.net/j/apache-0780.js" type="text/javascript"></script> <script type="text/javascript">var pageTracker = _gat._getTracker("UA-7"+"321"+"53-38"); pageTracker._initData();pageTracker._trackPageview();</script> </body> </html>
Notice the email note which has the subject prefilled? Thats one of the main uses for SSI, you can add forms to your errordocuments and get notified of problems which mean you can fix them.
Add this to your /.htaccess
for each ErrorDocument
you make.
ErrorDocument 503 /errordocs/503.html
My /errordocs/.htaccess
# turn on symlinks for rewrites and turn off SSI's ability to exec Options None Options SymLinksIfOwnerMatch IncludesNOEXEC # makes files ending in .html be filtered through the INCLUDES filter before being sent to client AddOutputFilter Includes html # this internal apache variable prevents your errordocs from allowing keep-alive connections SetEnv nokeepalive # used to determine the time and for SSI output SetEnv TZ America/Las_Vegas SetEnv SERVER_ADMIN webmaster@askapache.com
My /errordocs/503.html
<!--#set var="TITLE" value="Service Temporarily Unavailable" --> <!--#include virtual="/errordocs/TOP/" --> <p>The server is temporarily unable to service your request due to <strong>maintenance downtime</strong> or super-crazy-extreme capacity problems. Please try again later... Or <a href="mailto:<!--#echo encoding="url" var="SERVER_ADMIN" -->">send me an email</a> and let me know about it..</p> <!--#include virtual="/errordocs/BOTTOM/" -->
My /errordocs/TOP.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title><!--#echo encoding="none" var="REQUEST_URI" --> <!--#echo encoding="none" var="TITLE" --></title> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" href="https://www.askapache.com/s/s.askapache.net/c/error.css" /> <link rev="made" href="mailto:<!--#echo encoding="url" var="SERVER_ADMIN" -->" /> </head> <body> <h1><a href="https://www.askapache.com/" title="AskApache Home" accesskey="1"><img src="https://www.askapache.com/nlogo.jpg" height="75" alt="AskApache" /> </a> <!--#echo encoding="url" var="REQUEST_URI" --> <!--#echo encoding="none" var="TITLE" --></h1> <hr />
My /errordocs/BOTTOM.html
<p>If this should not be an error please <a href="mailto:webmaster@askapache.com?subject=ID#<!--#echo encoding="none" var="UNIQUE_ID" -->">email</a> me right away.</p> <!--#if expr="" --> <p>You came from <!--#echo var="HTTP_REFERER"--></p> <!--#endif --> <p>If you still have a question, please try to find the information you are looking for on the <a href="https://www.askapache.com/">AskApache Home page</a> or the <a href="https://www.askapache.com/search/">AskApache search page</a>.</p> <hr /> <address> <a href="https://www.askapache.com/about/">Webmaster</a> :<!--#echo encoding="none" var="UNIQUE_ID" --> Error-<!--#echo encoding="none" var="REDIRECT_STATUS" -->,v 1.30 <!--#config timefmt="%c" --><!--#echo var="DATE_LOCAL" --><br /> <!--#echo var="SERVER_SOFTWARE" --> </address> <!--#if expr=" = 10.10.10.10" --> <pre ><!--#printenv --></ pre> <!--#endif --> </body> </html>
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*?=?(http|ftp|ssl|https):/.* HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*??.* HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*.(asp|ini|dll).* HTTP/ [NC] RewriteRule .* - [F] ErrorDocument 403 /errordocs/f-off.html
Example /errordocs/f-off.html
View it Live (Not Responsible for mental or physical harm caused by fright)
Ok now that we have the real-world usage out of the way, lets dig in a bit to the actual module mod_include, which if you want you can view the source code here.
Server Side Includes are implemented by the INCLUDES filter. For backwards compatibility, the server-parsed handler also activates the INCLUDES filter. As well, Apache will activate the INCLUDES filter for any document with mime type text/x-server-parsed-html or text/x-server-parsed-html3 (and the resulting output will have the mime type text/html). If documents containing server-side include directives are given the extension .shtml, the following directives will make Apache parse them and assign the resulting document the mime type of text/html:
AddType text/html .shtml AddOutputFilter INCLUDES .shtml
The following directive must be given for the directories containing the shtml files (typically in a section, but this directive is also valid in .htaccess files if AllowOverride Options is set):
Options +Includes
These are the Directives allowed in .htaccess files that are handled by mod_include. Note that other modules may add additional directives, for instance the exec
SSI Directive is supplied by mod_cgi. This is how mod_cgi registers with mod_include to provide processing of the exec
directive. This is the code required to handle the "exec" SSI directive.
cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); cgi_pfn_reg_with_ssi("exec", handle_exec); static const char * const aszPre[] = { "mod_include.c", NULL };
config
<!--#config [timefmt="..."] [sizefmt="..."] [errmsg="..."] --> <!--#config [echomsg="..."] --> <!--#config errmsg="[It appears that you don't know how to use SSI]" -->
echomsg
echo
element attempts to echo an undefined variable. This overrides any SSIUndefinedEcho
directives.errmsg
SSIErrorMsg
directives.sizefmt
bytes
for a count in bytes, or abbrev
for a count in Kb or Mb as appropriate, for example a size of 1024 bytes will be printed as "1K".timefmt
strftime(3)
library routine when printing dates.echo
<!--#echo [encoding="none|url|entity"] var="..." [encoding="none|url|entity"] var="..." ... -->
var
encoding
Specifies how Apache should encode special characters contained in the variable before outputting them. If set to none
, no encoding will be done. If set to url
, then URL encoding (also known as %-encoding; this is appropriate for use within URLs in links, etc.) will be performed. The default is set to entity
, resulting in entity encoding.
exec
<!--#exec cgi="/cgi-bin/s.cgi" --> <!--#exec cmd="ls" --> <!--#include virtual="/cgi-bin/s.cgi?argument=value" --> <!--#exec cmd="perl /cgi-bin/s.pl args" -->
include
<!--#include virtual|file="..." [virtual|file="..."] ... -->
printenv
<!--#printenv -->
set
<!--#set var="..." value="..." ... --> <!--#set var="modified" value="" --> <!--#set var="name" value="AskApache" --> <!--#set var="date" value="_" -->
flastmod
<!--#flastmod virtual|file="..." [virtual|file="..."] ... -->
fsize
<!--#fsize virtual|file="..." [virtual|file="..."] ... -->
if
<!--#if expr="..." --> <!--#if expr=" && " --></pre> <pre><!--#if expr="test_condition" --> <!--#elif expr="test_condition" --> <!--#else --> <!--#endif -->
elif
<!--#elif expr="..." -->
else
<!--#else -->
endif
<!--#endif -->
START_SEQUENCE
- The ending tag for mod_include to recognize and parse as SSI.ERROR_MSG
[an error occurred while processing this directive]
- On Errors parsing SSI.TIME_FORMAT
%A, %d-%b-%Y %H:%M:%S %Z
- Default Time format for DATEUNDEFINED_ECHO
(none)
- When echoing an undefined variable.DATE_GMT=Sun Mar 8 22:58:56 2009 DATE_LOCAL=Sun Mar 8 15:58:56 2009 DOCUMENT_NAME=FOOTER.html DOCUMENT_ROOT=/root-srv/protected/askapache.com/sec DOCUMENT_URI=/includes/FOOTER.html GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7 HTTP_ACCEPT_ENCODING=gzip,deflate HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.5 HTTP_CACHE_CONTROL=max-age=0 HTTP_CONNECTION=keep-alive HTTP_COOKIE=__qca=12298910-686528-46510; __utmb=50625.1.0.11311 HTTP_HOST=www.askapache.com HTTP_KEEP_ALIVE=300 HTTP_REFERER=https://www.askapache.com/htaccess/ HTTP_USER_AGENT=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729) LAST_MODIFIED=Sun Mar 8 14:53:50 2009 PATH=/bin:/usr/bin:/sbin:/usr/sbin QUERY_STRING= REMOTE_ADDR=24.123.215.58 REMOTE_PORT=4785 REQUEST_METHOD=GET REQUEST_URI=/htaccess/ SCRIPT_FILENAME=/root-srv/protected/askapache.com/sec/includes/FOOTER.html SCRIPT_NAME=/includes/FOOTER.html SCRIPT_URI=https://www.askapache.com/htaccess/ SCRIPT_URL=/htaccess/ SERVER_ADDR=64.111.114.111 SERVER_ADMIN=webmaster@askapache.com SERVER_NAME=www.askapache.com SERVER_PORT=80 SERVER_PROTOCOL=INCLUDED SERVER_SIGNATURE= SERVER_SOFTWARE=Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.63 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 UNIQUE_ID=dnbtH0Bvcm8A2ZHqcAAAAM USER_NAME=