Server Side Includes


(Originally published May 8, 2000)



Are you the harried, overworked web-designer who just learned
the boss wants across the board changes to a thousand page website? Go ahead,
look distressed, ask for a raise and then make the changes in just a few
minutes using Server Side Includes. (installation required – batteries not


Note: Not all of the SSI commands will work on your server. It
depends on what type of server you have and the server configuration.


What are Server Side Includes and what can I do with them?

Server-side Includes will run on most, but not all servers. They
were first introduced in the NCSA server; Apache has taken it a step farther
with eXtended Server-side Includes. Unfortunately, they will not run on CERN.

An SSI is a command or directive placed in an HTML file through
the use of a comment line. With a simple SSI command you can update an entire
site design, dynamically add the current time and date or the date a file was
last modified, execute shell and CGI scripts and more! A definite boon to web
developers who are short on funds and time and over worked with a gazillion
pages to manage.

How to enable

Includes can be “turned on” by editing either the
server’s configuration files or adding an .htaccess file to the directory you
want to enable includes in.

  • Server Configuration

If you have access to your
servers configuration files you can enable SSI with a small edit to the
access.conf and srm.conf.

Telnet into your server,
navigating to the directory where your configuration files are located. This
may be something like usr/local/etc/httpd/conf/. Using your favorite text
editor, open srm.conf and locate the following lines:

# If you want to use server side includes, or CGI outside
# ScriptAliased directories, uncomment the following lines.
#AddType text/x-server-parsed-html .shtml
#AddType application/x-httpd-CGI .CGI


You may or may not have the
commented instruction lines, but what you’re looking for are the two lines that
start with AddType. You need to remove the # from in front of

Save your changes and move on to
access.conf. You’ll need to locate the section of this file that deals with
specifying which directory should be set as DocumentRoot. You will probably
find something similar to the section below, although it may have other
settings between the <Directory>and </Directory> tags.

# This should be changed to whatever you set DocumentRoot to.
<Directory /usr/local/etc/httpd/htdocs>
# This may also be "None", "All", or any combination of "Indexes",
# "Includes", or "FollowSymLinks"
Options Indexes FollowSymLinks Includes

If you do not wish to allow
scripts or shell commands to be run add IncludesNOEXEC to the
options line. This will allow SSIs but not CGI or shell commands.

Note: In the latest version Apache there is one file that
contains all of the config stuff.. the httpd.conf. You can make all of the
above edits in this one file.
  • .htaccess

If you don’t have access to your
server config files, all is not lost. Create a file with your favorite text
editor, naming it .htaccess. (Yes, the (.) is important. It tells your server
that this is a hidden file that can’t be seen by the casual snoop). Add the
following three lines to your .htaccess file.

Options Indexes FollowSymLinks Includes
AddType application/x-httpd-CGI .CGI
AddType text/x-server-parsed-html .shtml


.htaccess should be uploaded to
the directory you want to protect. All sub-directories inside that directory
will also be protected. If you wish to exclude CGI or shell commands on a per
directory basis you can add the IncludesNOEXEC to the
options line in the .htaccess file.

Why .shtml? Can’t I use .html?

A file that contains includes
must be parsed by the server. This puts an extra load on the server but unless
your site receives [millions] of visitors a day it’s unlikely you’ll notice a
slow-down in load time. Still, if you’re not using includes to add the headers
and footers to your entire site there’s really no need to parse every single
page. If your plan is to just add a few includes to special pages, give them a
file extension of .shtml and the server will parse only those pages. On the
other hand, if you have an existing site of multiple pages, plan to use
includes to add headers and footers and don’t look forward to renaming all of
your files to .shtml you can add the line

AddType text/x-server-parsed-html .html

to your .htaccess file instead.
All of your pages will be parsed, but they’ll need to be anyway to grab those



SSI directives follow this format:

<!--#directive parameter="value"-->


Ok, so that’s cool, but what does it mean? What’s a directive,
what’s a parameter and how do you know what the value is? The directive is an
instruction given to a computer, in this case our web server, to perform a
certain task. The parameter is what the instruction will be performed on.
The value is the result you want to get from the task that was performed on the
parameter named. Huh? Confused yet?

An SSI command starts with <!–#. Note there is no
space between
<!– and #. If you add a space your server will assume the SSI command is
simply a comment and will therefore print nothing, not even an error message.
Next comes one of six directives followed by a parameter, an equals sign and
the value. There should be no spaces on either side of the = and the value
should be enclosed in double quotes (“). The value string should be
followed by a space and then the closing tag, (–>).

The config directive


The config directive modifies the default SSI behavior.

errmsg sets a
default error message. This include must come before other includes in your
html file in order for it to return the modified error message. Any includes
that are above the errmsg will return the default error message rather than
your custom message. The error is logged in the server’s error log.

<!--#config errmsg="Another include messed up. 
Please email -->


timefmt defines
the format to use for times and dates. config timefmt must come before
the echo
directive for it to work. This is a string compatible with the strftime library
call under most versions of UNIX.

<!--#config timefmt="%A, %B %d, %Y"-->
<!--#echo var="LAST_MODIFIED" -->

appears as:

Wednesday, April 12, 2000

I know, I know. All those %A %B
%d look like gobble-de-gook. For a quick and painless explanation check the
handy Time/Dates Format table.
Print out this friendly version and keep
it taped to your desktop. (No…. not that desktop, the other one).

determines whether the file size is displayed in bytes or as kilobytes or
megabytes. To display bytes, use a value of “bytes”. Set the value to
“abbrev” for kilobytes or megabytes. Again, the config sizefmt
must come before the fsize directive for the command to work.

<!--#config sizefmt="bytes" -->
<!--#fsize file="index.html" -->





An include inserts the text (or images) of another document into
the parsed document. If you learn nothing else about SSI, learn includes. If
you’ve been creating web pages for very long you’ve already run into the
problem of having to change multiple pages every time you change your site
design, your header/footers, or your navigation. Not a fun job. Or, you could
inherit a web-site with 2000+ pages like I did… all hardcoded. Come time to
change that copyright date and you’ve got a big problem. This is where includes
come in so handy. Change just one file, the include, and your entire site is
instantly updated!

The include has two parameters, use the wrong one to update a site
with multiple directories and you’ll have multiple error messages instead of
instant update.

virtual gives a
virtual path to a document on the server.

<!--#include virtual="/includes/header.html" -->

To keep things organized, you can
create a directory at the root level called includes to house all of
your included files. The include parameter is telling the server to include a
‘virtual’ file, one located in a directory other than the one the document
being parsed is in. The value tells the server that the include is located in a
directory called ‘includes’, located at the root level. Using this method, you
can create all of your HTML pages with the same include, place them in various
directories and sub-directories, and the server will be able to find your
include; no error messages.

If you plan to use a single directory for all of your includes,
it would be a good idea to protect it from spiders and bots with a
robots exclusion
file, especially if you give your includes an .html extension. Leaving it
wide open would result in the files in the directory being indexed.

Now, if you plan to add a DOCTYPE
<TITLE> and META tags to your pages, and I suggest you do, you’ll quickly
find you’ve got a different problem. If you include a single header file on all
of your pages they will all carry the same TITLE and META tags. Not
good. There’s a way around that little problem though; use two includes, one
for the data above the TITLE, and a second one for everything below the META

Include #1, which I usually call
header1 contains the doctype and the opening html and head tags. No, you don’t
have to use a special include for this, but what if you decide to convert your
2000 page website from HTML 4.0 Transitional to HTML 4.0 Strict…

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

Include # 2, which I call
header2, contains the closing HEAD tag, the BODY tag and everything else that
you want in your header, but not the main content of your page.

<BODY bgcolor="#FFFFFF">
...all HTML, text, navigation or 
images that make up the page header...

Your HTML document contains the include
to header #1, TITLE, the full path to your style sheet, META tags, and the
include to header #2. The main page content comes below the include for
header2. For those copyright notices as well as bottom of the page navigation
(or anything else you want to include), you can add a footer include after the
main body content. So your entire web page template would look something like

<!--#include virtual="/includes/header1.html" -->
  <TITLE>Your Page Title</TITLE>
<LINK      rel     =  STYLESHEET
  href    = ""
  Type    = "text/css"    >
<META   NAME        = "Description"
  CONTENT = " Description of page">
<META      NAME     = "Keywords"
  CONTENT  = "keywords for page"
<!--#include virtual="/includes/header2.html" -->
....plug main page content in here...
<!--#include virtual="/includes/footer.html" -->

Header and footer includes can
save hours and hours of labor when it comes to site updates. But what if you’d
like some dynamic content in that header, say maybe a last modified date. No
problem. Save your includes with the HTML extension and you can include an
include in an include. Huh?

file gives a
pathname relative to the current directory. ../ cannot be used in this
pathname, nor can absolute paths be used.

<!--#include file="header.html" -->

With this method you would need a
file called header.html in each directory. That can be almost as hectic
as having to update individual pages whenever you make a change to your site.

On the other hand, if you’re
using the include file to update say a news brief that appears only on one
page, then this could be rather handy as well. You might not want to allow
someone not versed in HTML to update the news section of your index page, but
would be very comfortable letting them update a separate text file that will be
included in the HTML document.


Environment Variables with echo


Echo prints the value of one of the environment variables.

the file name of the current document.

<!--#echo var="DOCUMENT_NAME" -->
displays as:


the virtual path to the current document.

<!--#echo var="DOCUMENT_URI" -->

Ever go crazy trying to copy the “big guys” and have the full URL of your pages displayed on each and
every page in your site? You won’t last long if you’re hardcoding this
information; do it with an include and simplify your life! Precede the include
with your domain name to display the full URL of any page.

http://YourDomain<!--#echo var="DOCUMENT_URI" -->

unescaped version of any search query the client sent, with all shell-special
characters escaped with \.

<!--#echo var="QUERY_STRING_UNESCAPED" -->

and times are subject to the server timezone unless you’ve configured your
server to show a different timezone. Default output of DATE_LOCAL is fairly
blah, ranging to ugly but the good news is you’re not stuck with the default
output. By combining the variable with config timefmt you can specify
almost any output you please.

Consider the following two
examples. The first is the default output of DATE_LOCAL.

<!--#echo var="DATE_LOCAL" -->
displays as:
Saturday, 15-Apr-2000 12:24:42 MDT

Not exactly what you wanted, so
let’s customize it a bit. The example below uses the config directive to
specify a more pleasing output. Text is added to the include giving us a line
that flows like a sentence rather than just sticking the information up there
for the world to see.

<!--#config timefmt="%A, the  %d of  %B, in the year  %Y" -->
<!--#echo var="DATE_LOCAL" -->
displays as:
Saturday, the 15 of April, in the year 2000

DATE_GMT works the same as DATE_LOCAL, except that it returns Greenwich Mean

<!--#echo var="DATE_GMT" -->

date the current file was last modified. This is another trick the “big
guys” use. Don’t worry yourself to death trying to remember to hand change
your last modified date, let SSI take care of it for you! Simply add the
following line to your HTML pages.

<!--#echo var="LAST_MODIFIED" -->



CGI Environment Variables

CGI Environment Variables

In addition to the SSI Environment Variables,
the CGI Variable set is also available.


The name and version of the server software

<!--#echo var="SERVER_SOFTWARE" -->


The server’s hostname, DNS alias, or IP address

<!--#echo var="SERVER_NAME" -->


The revision of the CGI specification to which this server complies

<!--#echo var="GATEWAY_INTERFACE" -->


The name and revision of the information protocol this request came in with,
ie. HTTP/1.0

<!--#echo var="SERVER_PROTOCOL" -->


The port on which the server is answering

<!--#echo var="SERVER_PORT" -->


The method by which the document was requested. This is GET, HEAD, POST for

<!--#echo var="REQUEST_METHOD" -->


Scripts can be accessed by their virtual pathname, (relative to the base
directory), followed by extra information, as given by the client, at the end
of this path.

<!--#echo var="PATH_INFO" -->


The server translates the PATH_INFO from virtual-to-physical location.

<!--#echo var="PATH_TRANSLATED" -->


This is the virtual path to the script being executed.

<!--#echo var="SCRIPT_NAME" -->


This is the text at the end of a URL that has a ? in it, e.g.

<!--#echo var="QUERY_STRING" -->

Great, but that’s
just a URL. How do I use it you ask. Here’s a little example, not much good for
anything, but kinda cool if you’ve never seen it before.

Add a link to
color.html on one page, using the syntax below.

<a href="color.html?red">color</A>

Create color.html
putting the following include into it. That’s right, the directive goes into
the page being linked to rather than the page being linked from.

<!--#set var="color" value="$QUERY_STRING" -->


<font size="+2" face="Arial,Helvetica" color=
"<!--#echo var="color" -->">
<!--#echo var="QUERY_STRING" --></font>



If you were to go directly to color.html without clicking on the link you would see nothing at all. The content of the page, in this case one word only is the string after the ? in the URL. If the URL had been <A HREF=”color.html?green”> you would see the word green instead of red.

    CGI Environment Variables cont. REMOTE_HOST The hostname of the client making the request.

<!--#echo var="REMOTE_HOST" -->



The IP address of the client making the request.

<!--#echo var="REMOTE_ADDR" -->



The authentication method used to validate the user.

<!--#echo var="AUTH_TYPE" -->


If a page is protected, this is the name the user has authenticated as.

<!--#echo var="REMOTE_USER" -->


For servers that support the RFC 931 identification, this variable returns the
client user name retrieved from the server. REMOTE_USER should be limited to
logging only.

<!--#echo var="REMOTE_IDENT" -->


This is the content type of the data for queries which have attached information
such as HTTP POST and PUT.

<!--#echo var="CONTENT_TYPE" -->


The length of the attached information as given by the client.

<!--#echo var="CONTENT_LENGTH" -->



A list of MIME types which the client will accept. List items should be
separated by commas.

<!--#echo var="HTTP_ACCEPT" -->



The browser software the client is using. The return on this takes the format
of software/version library/version, e.g. Apache/1.2.6 FrontPage/3.0.4

<!--#echo var="HTTP_USER_AGENT" -->



URL of the document that contained the link to the page.

<!--#echo var="HTTP_REFERER" -->



Printing page stats


fsize prints the size of the specified file. The format in which
the command is displayed can be specified by using fsize in conjunction with
the config sizefmt parameter. Fsize is similar to the include command in that
it accepts both a file or virtual parameter. (Remember… virtual means you can
print the date of a file located anywhere on the server, not just the file you
are currently working on.

<!--#fsize   file="index_working.html" -->


flastmod prints the date that a specified file was last modified.
The format in which the date is displayed can be specified by using flastmod in
conjunction with the config timefmt parameter. Flastmod is similar to the
include command in that it accepts both a file or virtual parameter.
(Remember… virtual means you can print the date of a file located anywhere on
the server, not just the file you are currently working on.

<!--#config timefmt="%A, the  %d of  %B, in the year  %Y" -->
<!--#flastmod file="file.html" -->


Here’s a neat trick for showing
last modified dates on all of the links on an index. Simply add the following
line with the proper path after each link!

<!--#config timefmt=" %B  %d, %Y" -->
<A HREF="/directory/file.html">File</A>
<!--#flastmod virtual="/directory/file.html" -->
<A HREF="/another_directory/another_file.html">Another File</A>
<!--#flastmod virtual="/another_directory/another_file.html" -->

Displays the following:

File April 19, 2000

Another File January 08, 2000

Looks like a lot of work for two
little links, but multiply it by 20 or so and then figure your 20 pages change
on a frequent basis. Doesn’t take long to see the merits of using flastmod to
update the modification dates on that index page.


This command executes a CGI script or a shell command. It must be
activated to be used. Valid tags are:

cmd will
execute the given string using /bin/sh. The IncludesNOEXEC Option disables this

cgi executes
a cgi script. The following command would place a counter on a page, providing
the script resides in the cgi-bin on the server.

<!--#exec cgi="/cgi-bin/" -->


That’s a pretty quick run-down on Server Side includes and there’s
a whole new world out there waiting for us in the form of Apache’s eXtended
Server Side Includes!

Additional Resources:



Leave a Reply