Perl Programmer/Consultant
Remote System Administrator
Free Software
... contact me

 For Web Designers My Blog Mail Delivery Problems? 

SSI for The Rest of Us


This document is copyright © 1998 - 2005 by Art Sackett. Feel free to save it, print it, copy it, and distribute it freely, but do not alter it in any way. If I have missed something or made a factual error, please send the particulars to me via email and I will consider making the appropriate revisions.

Although it is the author's belief that the statements contained within this document are true and correct, use of any of this information is at the user's sole risk. The author does not accept liability for any consequences arising from the use or misuse of this information.


The requisite caveat:

This document is written for those of you who are fortunate enough to be dealing with an Apache or NCSA HTTPd server running under a Unix-like operating system (such as Linux, BSD, FreeBSD, etc.). Some of this will apply if your server was originally written for Unix, and was later ported to some other operating system. Otherwise, it probably won't do you much good.

Introduction

Server Side Includes ("SSI") give us a means by which to alter our HTML documents while they are being served. The copyright and disclaimer at the top of this page was placed there using SSI -- I'm far too lazy to cut and paste things that the server can cut and paste for me. Using SSI, we can do some cool things like tell the user their IP address (yours is 54.237.184.242), the date and time at which a document was served to them in either the server's local time (Friday, 24-Oct-2014 20:43:53 MDT) or in GMT (Saturday, 25-Oct-2014 02:43:53 GMT), or even include the output of a CGI application like a hit counter.

Yes, a lot of this is trivial in most cases. In others, it may not be. I don't care if you desire a little trivial coolness or need a non-trivial solution, I'm going to try to get you going with SSI by the time you're done reading this page. You may still have to contact your ISP, either directly or by consulting their FAQ ("Frequently Asinine Questions"). For that, you are on your own. Well, I'll talk to them for you if you pay me...

SSI is also known as "server parsed HTML". What this means is that the server reads the document and takes some action dependent upon the contents of the document -- or takes no action at all if the contents of the document don't require it. All this happens between the time your visitor activates a link and the time the document gets to them, "on the fly". Reading the document and taking the appropriate action will consume more resources (processor time, memory usage, maybe file system access, etc.) than would just finding the file and sending on its way to the TCP stack, so you don't want to indicate to the server that it ought to be parsing documents that don't need to be parsed. Unless the server is configured to just parse everything as a matter of convenience so users like us don't even have to think about it. (My ISP does this, either because they know I'm not real bright, or because they have some pretty awesome hardware and can better accept the resources hit, is something I haven't asked.)

When SSI is working, the markup you placed in your documents to cause an action will be replaced with the output of that action, so no one will even be aware of your wizardry. So much for fortune and glory, huh?


First Things First

You need to know if your ISP allows you to use SSI, and if so, how to indicate to the server that it ought to parse the document. You may be able to puzzle this out on your own without bothering their tech support folks, or you may not. The first thing to do is to look through the FAQ that they ought to have provided. You might want to bookmark this page before going off on that quest -- I'll be here when you get back.

Okay, you went and looked, right? If you found the answers you need, you might as well skip this part. If not, read on.

Your ISP's site was less than helpful, huh? No worries, we'll try to do their work for them and get the answers we need.

First we're going to run a few tests to see if they have SSI enabled globally, since I prefer to use whatever method(s) the server administrator thinks we ought to be using before resorting to heroic measures that might make them grumpy. On a bad day, a server admin could just decide to close your account without telling you or giving you a second chance. Although this is a rare and drastic measure, there's no sense pushing the issue unnecessarily. (Myself, I consider the server admin the Lord of The Machine, and unless one is a power crazed jerk, his word is Gospel. On the other hand, I have been known to make users unhappy by being a bit too strict in my administration. I've never broken a server, so I do have that in my favor.) If we are not successful in finding a global SSI configuration, we're going to push the issue and hope for the best ;-)

The first thing we need is a test page to mess around with. It has to include some SSI stuff, as well as give us an indication that it's even there. We'll do this with two files, one that is HTML that includes some markup to invoke the SSI mechanism, and the other is a little something to tell us that we have successfully made the thing work. You can cut and paste (if your system is so configured) these things below, or you can create them yourself. In either case, do not copy the row of hashes (#'s) that appear below only to show where the files start and end.

The first is the HTML, which we will name test.html:

###########################################################
<html>
  <head>
    <title>This is our SSI test page</title>
  </head>
  <body>
    <center>
      <h1>SSI Test Page</h1>
      <hr>
      <p>If SSI is working, there will be a line below to tell us so:
      <p>       <!-- here's the important part, get it right! -->
      <!--#include virtual="test.txt" -->
      <p>If there is a line above that reads:<br>
      [there was an error processing this directive]<br>
      check that you saved the file 'test.txt' in the same directory
      as this HTML page. It indicates that SSI is mostly working.
    </center>
  </body>
</html>
###########################################################

And this is the file we're trying to include, which we will name test.txt:

###########################################################

If you can see this line, SSI is now working!

###########################################################

Upload those two files test.html and test.txt to your server and we can begin puzzling out how to get SSI working on your server, if it can be done at all. NOTE: Don't upload the files into your cgi-bin (or cgi) directory. If your ISP is security conscious, they will have disabled SSI in directories that can contain executable files -- it may be that you can use SSI, but our tests will fail because you placed those files into a directory where SSI is not allowed.

Test 1: Do They Parse Everything?

This is the easy test. Just give a look with your browser at that page you just uploaded as test.html. If you get success, they parse everything, you're done, and you may as well skip the rest of this section.

On the other hand, if that didn't work, let's check for XBitHack support:

Test 2: Is XBitHack Supported?

The XBitHack is, well, a hack that allows us to indicate to the server that a given file should be parsed without the need to use the file name extension .shtml. This is handy, because if we later decide to remove that part of the document that will benefit from server parsing, we don't have to choose between updating all of our links (and breaking other people's links to our pages) and wasting server resources parsing a file that won't benefit from it. It works by checking for the user execute bit attached to a file named with the extension .html and parsing any file whose user execute bit is set.

To perform this test, you have to be able to alter the file permissions of files within your directory space. If you have telnet access, or the server is configured to allow you to do these things via an FTP connection, all you need to do is this:

chmod u+x test.html

from within the directory you uploaded our test files to. If you are using a graphical FTP client, you may have another means to accomplish this -- read the appropriate Help file or manual page. (There are far too many FTP clients and server configurations for me to even try to keep up with, so I don't.)

With the user execute bit set, view the file in your browser. You may have to reload the file to make sure that it's not coming from your browser cache. If you get success, make a mental note that the server is configured to use the XBitHack, and skip the rest of this section.

If that didn't work, change the permissions back to what they were before with the command chmod -x test.html and continue on to the next test.

Test 3: Is the Extension .shtml Supported?

This is it: our last test. This is the least savory option, as explained above in Test 2. Change the name of test.html on the server to test.shtml and view it in your browser (don't forget to reload!). If you are greeted with success, well, at least we know how to make SSI work and you can skip the rest of this section. If you are not, it may be possible to sneak SSI into your bag of tricks by making using of the .htaccess file.

Going for Broke: Forcing the Issue

So none of our tests worked. Bummer. Now we're going to play junior sysadmin and see if we can make it work in spite of the real sysadmin's ideas of what is Good, Just, and Right. Remember my guarantee: If you take my advice and it breaks something, you get to keep all of the little pieces. Free advice is worth only what you paid for it.

To limit the scope of our damage, create a new directory on the server named test in the top-most directory where your web accessible documents are stored (usually public_html) and set its permissions to 755 so we can get at it from the web. Move the test files (test.html and test.txt) into it. Give test.html a look with your browser to make sure that we can, in fact, get to it from the web.

We're going to be aggressive and just parse everything that we serve out of this directory. This is probably not how you will want to do things in normal use -- you will want to either use the XBitHack or the extension .shtml to signal to the server that you want a given file parsed. For right now, though, we're primarily concerned with answering the question "Can we even do this?", so we'll just go for it.

On your own machine, create a file named .htaccess -- if your OS is one of those funny things that won't allow this, just call it htaccess and rename it once it's on the server. Into that file, place the following text:

AddHandler server-parsed .html
Options +Includes

Upload this file to the server, into the test directory you created a few moments ago. If you were unable to create it with the leading dot in the file name, change the name of the file on the server to .htaccess.

The Moment of Truth: Point your browser at test.html in its new home and see what happens. With any luck, you will see that line "If you can see this line, SSI is now working!" -- otherwise, you may as well call it quits for now and contact your ISP. It's probably a good idea to blow away that .htaccess file before you do, though. No sense poking them in their apparently hypersensitive ribs.

If you did get SSI working just now, good for you! You'll want to make sure that you don't parse any files that don't need to be parsed -- whether to use the XBitHack (if you can) or the extension .shtml is up to you. I like the XBitHack, you might want to use .shtml just to impress your friends. Live like you want to live.

To use the .shtml extension, change the first line in that .htaccess file you just created so that .html reads .shtml. To take advantage of the XBitHack change to first line to read XBitHack on. Then copy this .htaccess file into the top-most directory of each "tree" that you want it to apply to. If, for example, this is your public_html (or its equivalent) directory, the .htaccess file will apply to every file below it in the structure. NOTE: If you also have a cgi-bin directory or any other directory under public_html that contains executable files, you must disable includes in that directory/those directories! To do this, place another .htaccess file in each of the directories affected, and into that file place the text:

Options -Includes

This will prevent SSI from working in those directories, which will keep evil crackers from opening a security hole -- and will keep you happy and safe. Imagine if a cracker used your account to send threatening email to the President of the United States, how startled you would be waking up in the middle of the night with the Secret Service in your bedroom.

I said "must" a moment ago, and the truth of the matter is that in most cases nothing will be apparently broken if you don't protect those directories that executables live in. But if the day comes when I'm the sysadmin at your ISP and you didn't take my advice, I'm going to come to your house late at night and beat bumps into your head. And into the head of your big mean dog, if you have one.


Forming Markup (Directives) for SSI

In order to ensure that your SSI will work, you will have to follow the conventions for SSI directives. Some servers will give you a little fudge factor, others won't. It's best to make sure you do your job properly so the server can do its job properly, too.

An SSI directive looks a lot like an HTML comment. It starts with a "less than" symbol, followed by an exclamation point, then two hyphens (dashes) and a hash (or "pound sign"). Following the hash is an action, possibly a space and then a modifier, then a quoted argument. After the closing quotation mark comes a space (the space is important!), then two hyphens and a "greater than" symbol. Here's an example:

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

If it were a working example, the above SSI directive would have been replaced with your current IP address (or the address of the proxy server you use to connect to the internet) which just happens to be 54.237.184.242

Things you can do with SSI

SSI is useful for many things. You've already seen how to include another file into your HTML documents -- if you use HTML markup, the browsers that see your site will never know the difference between included markup and things you wrote into the files themselves. No one needs to know that you're as lazy as I am. This can be useful where you have a large number of pages that should each contain some of the same content, such as a header or a copyright statement intended to scare away content thieves.

Environment Variables

Suppose you want to create a "smart" link back to wherever the visitor came from, even if it wasn't your site that brought them here. We're going to reach out and get the environment variable HTTP_REFERER to do just that. (Yes, "referrer" is misspelled in this environment variable. I didn't have anything to do with the HTTP specification!)

We can get the value of environment variables using echo var= to retrieve them. It's important to note that if the variable is not set, you will get either nothing at all or (none) back -- in this example, you will end up with a broken link. To get the URI of the page that brought the user to your extraordinarily cool work:

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

With that information, we can create that cool link -- it looks a lot better "live" than it does when you write it:

    <a href="<!--#echo var="HTTP_REFERER" -->">Back</a>

Which, in action looks just like any other link: Back. (If you entered the URI of this page manually, the preceding link is broken, as I promised earlier. Otherwise, you can see it work by clicking it.) You don't have to concern yourself with whether or not the server will get confused by the nested quotation marks. It won't. I get confused by them sometimes, but I didn't develop your server so we're both in good shape.

Now that we've seen enough of the examples to have a feel for how these things work, here is the list of environment variables that I think you might find handy, with an example of what they look like right now on my server:

Useful Environment Variables: