SSI Directives

To enable Apache SSIs, edit access.conf and add Includes to the Options directive.
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you (or at least, not yet).

Options Indexes FollowSymLinks ExecCGI Includes
  Then edit srm.conf and uncomment the AddType and AddHandler as illustrated below.  
# To use server-parsed HTML files
AddType text/html .shtml
AddHandler server-parsed .shtml
  Note: .shtml file extension is only a convention. Your SSIs file can have any extension, including .html but this would cause all .html files to be parsed by Apache, which could cause considerable process overhead on you system.

You might also consider adding index.shtml to the DirectoryIndex directive in srm.conf.

# DirectoryIndex: Name of the file or files to use as a pre-written HTML
# directory index.  Separate multiple entries with spaces.

DirectoryIndex index.html index.shtml
  which will enable Apache to use index.shtml as the index page to any particular directory.

Remember:Re-start Apache after you have changed the configuration.


Apache Directives

SSI Examples

In no particular order.....


File last mod(ified)... The date/time of the last modification of a file.

The      "Apache RTFM last updated ....."      information displayed at the bottom of each page of the RTFM is generated by the SSI directive:

<!--#config timefmt="%A %B %m/%d/%y"-->
Apache RTFM last updated <!--#flastmod virtual="rtfm.shtml"-->

  Everytime I update or amend the Apache RTFM, I edit rtfm.shtml to insure the date is changed to reflect the last modified date.


In the above example, I used the config option to set the date format. If I hadn't specified exactly what I wanted for the date, the results would have looked like this.
Apache RTFM last updated Saturday, 21-Oct-2006 11:24:29 BST
  Here is all the timefmt options and their output.  
Day of the week abbreviation <!--#config timefmt="%a"--> Sat
Day of the week <!--#config timefmt="%A"--> Saturday
Month name abbreviation <!--#config timefmt="%b"--> Oct
Month name <!--#config timefmt="%B"--> October
Date (1 and not 01) <!--#config timefmt="%d"--> 21
Date (%m %d %y)
<!--#config timefmt="%D"--> 10/21/06
Date <!--#config timefmt="%e"--> 21
24-hour clock <!--#config timefmt="%H"--> 11
12-hour clock <!--#config timefmt="%I"--> 11
Decimal day of the year <!--#config timefmt="%j"--> 294
Month (number) <!--#config timefmt="%m"--> 10
Minutes <!--#config timefmt="%M"--> 24
AM|PM <!--#config timefmt="%p"--> AM
Time as %I:%M:%S AM|PM <!--#config timefmt="%r"--> 11:24:29 AM
Seconds <!--#config timefmt="%S"--> 29
24 hr time as %h%m%s <!--#config timefmt="%T"--> 11:24:29
Week of year <!--#config timefmt="%U"--> 42
Day of week <!--#config timefmt="%w"--> 6
Year of century <!--#config timefmt="%y"--> 06
Year <!--#config timefmt="%Y"--> 2006
Time Zone <!--#config timefmt="%Z"--> BST
  NT users should note the following formats appear to be broken on the 1.3b3 version of Apache.  
Date (%m %d %y)
<!--#config timefmt="%D"-->
Date <!--#config timefmt="%e"-->
Time as %I:%M:%S AM|PM <!--#config timefmt="%r"-->
24 hr time as %h%m%s <!--#config timefmt="%T"-->

flastmod re-visited

In the example below, we have specified virtual
<!--#config timefmt="%A %B %m/%d/%y"-->
Apache RTFM last updated <!--#flastmod virtual="rtfm.shtml"-->

  fastmod can user either:
  • virtual or
  • file
The distinction is subtle. File allows you to specify a file relative to the current document, but ../ is not allowed. Virtual allows you to specify a file relative to Apache's document hierarchy. That doesn't help much! Let's try an example or two. Assume that Apache is installed in /var/apache and the DocumentRoot is /var/apache/htdocs.
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.

DocumentRoot "/var/apache/htdocs"
  In htdocs, we have the directory rtfm which contains foo.shtml and bar.shtml. In foo.shtml we want to display the last modified date of bar.shtml. bar.shtml can be referenced relative to foo.shtml with the file directive.  
<!--#flastmod file="bar.shtml"-->
  or we can reference it via the Apache document hierarchy using virtual  
<!--#flastmod virtual="/rtfm/bar.shtml"-->
  What does this mean for me? (other than virtual requires more typing!) Suppose you want get the last modified date for a file in the directory apache from foo.shtml. You could try:  
<!--#flastmod file="../apache/bar.shtml"-->
  and you would get:
[an error occurred while processing this directive] 
  since you cannot use "../" with either virtual or file. You could get the information by using:  
<!--#flastmod virtual="/apache/bar.shtml"-->

More SSI Examples


echo prints one of the SSI or CGI variables. It's format is:
<!--#echo encoding="encode_type" var="an_envirnoment_varialbe"-->
  From version 1.3.12, Apache has included an encoding option to the echo SSI directive that specifies how Apache should encode special characters contained in the variable before they are output. none specifies no encoding. url indicates the %-encoding as used in URL's. The default in entity which encodes any special characters (<>&....) Only the special characters defined in ISO-8859-1 are encoded. To be effective the encoding pragma must precede the var pragma.

The SSI variables, meaning and their contents are:
The name of the current document <!--#echo var="DOCUMENT_NAME"--> all_ssi.shtml
The virtual path to the file <!--#echo var="DOCUMENT_URI"--> /apache/all_ssi.shtml
The virtual path to the file <!--#echo var="QUERY_STRING_UNESCAPED"--> (none)
Current date and time in the local time zone <!--#echo var="DATE_LOCAL"--> BST
Current date and time in Greenwich Mean Time <!--#echo var="DATE_GMT"--> GMT
Last modification date and time for current file <!--#echo var="LAST_MODIFIED"--> BST
  The format of DATE_LOCAL, DATE_GMT, AND LAST_MODIFIED can be controlled by the timefmt pragma of config i.e.  
<!--#config timefmt="%A %B %m/%d/%y %H:%M:%S"-->
  would produce:  
<!--#echo var="DATE_LOCAL"--> Tuesday October 10/24/17 10:03:09
<!--#echo var="DATE_GMT"--> Tuesday October 10/24/17 09:03:09
<!--#echo var="LAST_MODIFIED"--> Saturday October 10/21/06 11:24:29


How big is that document?
<!--#fsize virtual="index.shtml"-->
  The size of index.shtml is: 3.1K

or if we would like to know in bytes:

<!--#config sizefmt="bytes"-->
  The size of index.shtml in bytes is: 3,151

It appears the default for fsize is abbrev

<!--#config sizefmt="abbrev"--> is the default.


We have already seen config used for timefmt and sizefmt You can also configure the error message Apache will display, if you make a mistake with SSIs. Instead of getting....
[an error occurred while processing this directive] 
  The errmsg can be set by config to display your own customised message.  
<!--#config errmsg="SSI Error, contact 
<a href=\"\">webmaster@jlk.netlt;/a>"-->
  I have wrapped the line for legibility, but you get the idea. When an SSI error occurs you would see  
SSI Error, contact

Running Commands with SSI

SSIs can be used to include content from virtually any command that can be run on your operating system. Want to display, who is working logged on you OS? try....
<!--#exec cmd="/usr/bin/who"-->
  Format it between a couple of <pre></pre> pairs and you get:  
king     ttyp0   Apr 14 10:14   (picard)
tracey   ttyp1   Apr 14 08:52   (
king     ttyp2   Apr 14 10:14   (picard:0.0)
irfan    ttyp3   Apr 14 23:23   (
erlend   ttyp4   Apr 15 11:19   (striker)
tonys    ttyp6   Apr 15 12:13   (
ccampbel ttyp7   Apr 15 14:58   (blob)
jkissel  ttyp8   Apr 15 15:49   (jaunty)
  Alternatively, we can run our script  

print "Content-type: text/html\n\n";
print "<html><head><title>hello world</title></head>";
print "<body><h1>Hello World</h1></body></html>";
  in-line and combine it with this document by including the following:  
<!--#exec cgi="/cgi-bin/"-->
  with predicable results  
[an error occurred while processing this directive]
  Useful? Well maybe. Dangerous? Yes and no depending on how much freedom you give you users, and how well you have your security screwed down.

You can enable server side includes, but selectively disable exec with the following.

# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you (or at least, not yet).

Options Indexes FollowSymLinks IncludesNOEXEC
  You might want to user either <Directory> or <Location> to limit which directories or locations have access to SSIs.


The include SSI directive allows you to:

boilerplate your html!

Wow!...but what does this do for me?

With SSIs and include you can set up a standard template for you web pages which could (suggestion) include

  • A standard header
  • A set of navigation buttons
  • A standard footer
Big deal!

Well it is if you decide to change you "house style" and you have 50, a 100, or 1000 html document which you need to edit. If you had used include you could make the change by editing:

  • your standard header include file
  • your navigation buttons include file
  • your standard footer include
and you all you documents would then display you new "house style".

"Right! You convenced me. How does this work?"

<!--#include file="some/header/file"-->
<!--#include virtual="/house_stds/std_header_file"-->
  Almost every document in the Apache RTFM looks like:  
<!--#include file="rtfm_header.shtml" -->

<!--#include file="your new html file.html" -->

<!--#include file="rtfm_footer.shtml" -->
  I confess, that there is a little more to each one, but I'll cover thoses differences in the next section.

The important points are the inclusion of a standard header and footer file. If I want to change the look of the Apache RTFM, I can by editing these two files, and every file in the RTFM will show these changes.

I'm confussed! You have rtmf_header.shtml and then use "your new html file.html". Why?

I use some SSI directives and some eXtender SSIs in the header and footer, one of which I mentioned in the section on flastmod and I want Apache to treat these files as SSI files and process them. The main bulk of the RTFM is just html, so to reduce the load on the server, I use an html file extension.

You can imply from this, that

  • SSI document can include other SSI documents
    • and they can alson include SSI documents
      • which can intern include SSI documents
        • and so can these.......

I just thought, that being an RTFM, I shouldn't imply this, but tell you it explicitly. ;-) (this is not a typo, it's a smiley)

One thing more that SSIs can do for you. If you look at the main RTFM index page, you will see links to.

  • All the pages in this section

Html is great for browsing, breaking up large documents into easily digestable sections, but what do you do if you want to get all the sections in a single document to (heavens forbid) print a copy?

Just create a SSI document with all the .html pages included, plus the header and footer (once) and you can get all the sections/sub-sections in one document.

This may not impress you, but IMOSHO, I think it's a great feature.

eXtended SSIs

Extender SSIs add three additional pragmas to SSIs.


<!--#printenv -->
  which just dumps out the envrionment. Note: Apache 1.2 or better.  
HTTP_USER_AGENT=Mozilla/4.0 [en] (WinNT; I)
HTTP_ACCEPT=image/gif,image/x-xbitmap, image/jpeg, image/pjpeg, */* 
HTTP_ACCEPT_CHARSET=iso-8859-1,*,utf-8 SystemRoot=C:\WINNT
DATE_LOCAL=Thursday, 16-Apr-1998 11:43:58
British Summer Time DATE_GMT=Thursday, 16-Apr-1998 10:43:58 GMT
LAST_MODIFIED=Thursday, 16-Apr-1998 11:43:56 British Summer Time
DOCUMENT_NAME=xssi.shtml Title=eXtended SSI 
  which you may or may not find interesting. But more importantly, XSSIs include conditional html.

Let me repeat that.

XSSIs provide conditional html!

Yes, you can detect whether I'm using Netscape or IE4 and display a different page for each of them without writing cgi scripts, JavaScripts or Jscripts, JavaApplets or ActiveX controls.

Now a message from the author

Please Don't!

Anyone who slaps a "this page is best viewed with Browser X" label on a Web page appears to be yearning for the bad old days, before the Web, when you had very little chance of reading a document written on another computer, another word processor, or another network.
[Tim Berners-Lee in Technology Review, July 1996]

So much for you taking notice of my opinions. How do we do this conditional html?

Flow Control Elements

<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->
  where test_condition is  
string     true if string is not empty 
string1 = string2 
string1 != string2 
string1 < string2 
string1 >= string2 
string1 < string2 
string1 >= string2 
Compare string1 with string 2. 
If string2 has the form /string/ then it is compared 
as a regular expression. Regular expressions have the 
same syntax as those found in the Unix egrep command. 
( test_condition ) 
     true if test_condition is true 
! test_condition 
     true if test_condition is false 
test_condition1 && test_condition2 
     true if both test_condition1 and test_condition2 are true 
test_condition1 || test_condition2 
     true if either test_condition1 or test_condition2 is true
  and finally you can set your own variables!.


<!--#set var="Title" value="Apache RTFM!" -->
  Which bring be to a complete example, namely the Apache RTFM standard template.  
<!--#set var="Title" value="Your Title Goes Here" -->
<!--#include file="rtfm_header.shtml" -->

<!--#include file="you new html file.html" -->

<!-- set, delete, or modify as required -->
<!--#set var="Previous" value="<a href=\"????.shtml\">Previous file</a>" -->
<!--#set var="Next" value="<a href=\"????.shtml\">Next File</a>" -->

<!--#include file="rtfm_footer.shtml" -->
  The rtfm_header.shtml looks like  
	<!--#echo var="Title"-->
  and the rtfm_footer.shtml  
	<hr width=50%>
	<!--#if expr="\"$Previous\" != \"\" " -->
		<!--#echo var="Previous" -->
	<!--#endif -->
	<a href="rtfm.shtml">RTFM Index</a>
	<!--#if expr="\"$Next\" != \"\" " -->
		<!--#echo var="Next" -->
	<!--#endif -->
	<hr width=50%>

	<!--#config timefmt="%A %B %d %Y"-->

	<a href="/misc/copyright.html">Copyright</a> © 
	1998 Open Source Migrations ltd. All Rights Reserved.<br>
	Apache RTFM last updated <!--#flastmod virtual="rtfm.shtml"-->
  So what's it all do?

First we get the title of each document printed. We set the title for each document in the template file.

<!--#set var="Title" value="eXtended SSI" -->
<!--#include file="rtfm_header.shtml" -->
  And in the rtfm_header.shtml file  
	<!--#echo var="Title"-->
  Prints it out the doucment title in the correct context.

Next we use want to create a mini-navigation menu in the footer. The lines

<!--#set var="Previous" value="<a href=\"include_ssi.shtml\">
Including files with SSIs</a>" -->
  In the template file set up the footer information so we can point at the previous document in this section.

The footer file then conditionally displays the parts of the menu we have setup in the template.

	<!--#if expr="\"$Previous\" != \"\" " -->
		<!--#echo var="Previous" -->
	<!--#endif -->
  In the footer we check to see of $Previous is not equal to "" (an empty string) If this is TRUE, the footer prints out a link to the previous section. The same type of test is used for creating a link to the Next section.

The pragma expr="....." must contain "'s, but there might be spaces in the string $Previous so we enclose in in quotes, but since there are already inside a set of quotes (expr="...."), we need to "escape" these inner quotes.

\"$Previous\"  and String2

Just for fun

SSI Variables

Just a few observations on variables and SSIs.

You don't use a $ with #echo

<!--#echo var="$HTTP_HOST"-->
  where as
Host name is: <!--#echo var="HTTP_HOST"-->
  gives you
Host name is:
  but you do need a $ elsewhere  
<!--#set var="myvar" value="HTTP_HOST" -->
Host name is: <!--#echo var="myvar" -->
Host name is: HTTP_HOST
  where as...
<!--#set var="myvar" value="$HTTP_HOST" -->
Host name is: <!--#echo var="myvar" -->
Host name is:
  This might be obvious to everyone else, but it did cause some confussion when I first started working with SSIs.

You can insert a $ into a string by escaping it with a \ If you need to check the contents of a string (say $foo) matches the string '$bar' ('$' + 'b' + 'a' + 'r') you can with:

<!--#if expr="$foo = \$bar" -->
  And finally if you need to concatenate two strings where there might be an ambiguous result, you can acomplish this by enclosing the variables to be de-reference with {} Assume that $foo is equal to "the quick" and $bar is equal to "brown fox". The can be safely oncatenated by...  
<!--#set "myvar" value="${foo}some other text${bar}" -->


The XBitHack provides an alternative method of enabling SSIs on Unix servers. This doesn't seem to work with 1.3b6 on NT. If you know differently, please let me know. The XBitHack causes Apache to check the execute priviledges for a particular html file. If they are set, Apache will parse the file looking for SSI directives.

XBiitHack has there settings.

  • off The execute bit is not checked, so no SSIs
  • on Any file with +x premissions will be treated as a server-parsed (SSI) document
  • full Like all but the group-execute bit ( +gx ) is tested. If set, then the last modified time of the file is returned as "Last-modified". If not set, the no "Last-modified" date is returned.

SSI Gotachas!

Trailing Slash .../

Watch out for a trailing slash /. If you add a trailing slash to the url for a page, you will break SSI. i.e. The reference for this page is:
  but if you add a trailing slash
  all hell will break loose with SSIs. Just follow the link above with the trailing slash to see what is looks like. This link will be back to the original document.

Comment terminator

You should put a space between the SSI token and the comment terminator. i.e.
<!--#echo var="HTTP_HOST" -->

Properly formatted SSI commands

Don't forget the #
<!--echo var="HTTP_HOST" -->
should be
<!--#echo var="HTTP_HOST" -->
  and to put a space between the start of
comment <-- and the #
<!-- #echo var="HTTP_HOST" -->
should be
<!--#echo var="HTTP_HOST" -->
  Either of these mistakes will not produce an error but you will see the comment if you view the source of you page with your browser.

Remember: if your SSI commands are correctly formatted and you server is correctly configured for SSIs, you will never, never, see the SSI string in the "View Source" output of your browser.

index.shtml ???

Having problems with index.shtml not working? All you get is a listing of the files in the directory! Add the following to your srm.comf
# DirectoryIndex: Name of the file or files to use as a pre-written HTML
# directory index.  Separate multiple entries with spaces.

DirectoryIndex index.html index.shtml

RTFM Index
Tell us what you think!
Copyright © 2006 Open Source Migrations ltd. All Rights Reserved.
Apache RTFM last updated Saturday October 21 2006