Home
Interests
Photos
Favorites

Apache Server Side Includes
August 2004

by Russell J. T. Dyer

A simple alternative to using PHP (or some other programming language) and its API to generate dynamic Web content is Server Side Includes (SSI) with Apache. SSI can be useful when you want to insert a small amount of content into a Web page from an external source. For instance, you could use SSI to add text from a file or to add the date of a document to a Web page. You could also use SSI to insert the results of running a system command to a page. In this installment in my Apache series, I will explain Server Side Includes and some related Apache directives, and I'll also provide examples of how they might be used.

Something Simple

I'll start with something simple to show how SSI works. Suppose an office manager wants to write a note to the employees every morning. It's always just a short paragraph to motivate employees. Suppose further that the manager wants this paragraph to appear at the top of the home page of the office intranet site, a page that all of the employees' Web browsers have as their starting page. This could be handled in many ways, but I'll use SSI for this example. The manager will edit a text file that he copies from his computer each morning to a Samba shared directory on the Apache server (e.g., /var/www/html/manager), which only he can access internally. I will have to watch the security settings on such a directory, but that's a different discussion. I can then add the following line near the top of the main page (index.html) of the intranet site, somewhere just after the opening <body> tag:

<!--#include virtual="/manager/morning.txt" -->

By default, an SSI entry starts with a <!--# and ends with a -->, as shown here. The advantage of these opening and starting tags is that if SSI is not enabled in Apache, then the Web browser will consider the entry to be a hidden comment and won't display it in the browser window. It will be contained in the page's source code though, so it's not totally hidden. The basic syntax of an SSI item is as you see it here: an opening tag with the type of Include given (e.g., include), then some attributes and their values, and then an ending tag. There's not a space after the pound-sign, but there are spaces after the element name, between attributes, and before the closing tag. Values may be given within double-quotes or single-quotes.

Presumably, the results of the above Include will paste the text contained in the file morning.txt, located in the manager's sub-directory on the Apache server, at the position in the Web page in which it is included. This will work only if the Apache module mod_include is loaded and if Apache has been set up to allow for Includes, or if the .htaccess file located in the directory of the Web page allows it.

Allowing Includes

Apache doesn't check every single document for SSI elements before sending it to clients, such as Web browsers. To do so would slow down a Web site. Unless instructed otherwise, Apache assumes that there are no SSI elements in any documents. However, you can tell Apache to watch for certain attributes regarding documents so that it will know which ones contain SSI elements. One method and convention is to name such files with the ending of .shtml instead of the usual .html. This requires a few directives in either Apache's main configuration file (httpd.conf) or in the .htaccess file in the directory that holds such documents. See Apache Basics for information on configuring these files.

Options +Includes
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml

The Includes option in the first line above allows Includes. By placing a plus-sign in front of the Includes option, it's added to any other options that may be set elsewhere. If not, the other options could be removed by this line. The next directive instructs Apache that files ending with .shtml are text/html files. The last directive says that files with these filename endings contain Server Side Includes and need to be processed before sending a requested document to a client.

The method of using a file name's extension as an indication that a file contains Server Side Includes works fairly well. However, there may be times when you want temporarily to add an Include to an existing HTML document that already has many links to it from other documents. It could be cumbersome to change all the links to such a document temporarily to reflect a new filename. An alternative method to identify documents that contain SSI elements is to change the permission of SSI files and to use the XBitHack directive. This directive instructs Apache to check whether the execute bit is set for a file for its owner. To use this feature, the following directives would be entered into either httpd.conf or the .htaccess file in the directory that contains SSI files:

Options +Includes
XBitHack on

It would be unusual and unnecessary for an HTML file to be set intentionally as executable since they are typically simple text files. So it stands to reason (with respect to the XBitHack directive) that if an HTML file is set as executable, then something inside of it may need to be executed by Apache. Incidentally, to add execute privileges to a file, you could enter something like the following at the command line:

chmod u+x index.html

This adds execute privileges for the user or owner of the file index.html without changing any other privileges associated with the file.

Basic SSI Elements

Currently, there are a few SSI elements available for use. One is the include, which we used in the example given earlier. With an include element, the text from another document may be inserted at the point in which it is given. Additionally, an include can be used to incorporate the results of a CGI script. There are two attribute possibilities with the include element: file and virtual. They basically do the same thing, except that file is limited to documents in the current directory and sub-directories of it absolute paths and relative paths that include the parent directory are not permitted. With virtual, you may specify any URL file path as long as it's located within the Apache document root (e.g., under /var/www/html) or otherwise permitted by your Apache configuration file.

There are a couple pf SSI elements that may be used for obtaining information on files. If you would like to retrieve the size of a given file or the "data and time" that it was last modified, you can use the fsize and the flastmod elements, respectively. Below is an example of how you might use them along with some examples of a couple of other Include elements:

<!--#set var="myfile" value-"bigfile.tar.gz" --> <br/>
File Name: <!--#echo var="myfile" --> <br/>
File Size: <!--#fsize virtual="$myfile" --> <br/>
Last Modified: <!--#flastmod virtual="$myfile" --> <br/>

The first Include above uses the set element to set up an SSI variable. The name of the variable is given with the attribute var. The value of the variable is specified in the attribute value. In this case, we're creating a variable called myfile that contains the name of the file for which we want to get information in the next three Includes. The second Include displays the file name using the echo element. Since this Include expects a variable to be given in the attribute var, a dollar-sign prefix isn't added to identify it as a variable. The next Include retrieves the file size of the document given as the value for virtual, which is contained in the variable, this time with a dollar-sign prefix. A variable does not have to be given, incidentally. The file name could be given instead. The final line provides the date and time that the file was last modified. The results of the above Includes follow:

File Name: bigfile.tar.gz
File Size: 973k
Last Modified: Sunday, 08-Aug-2004 18:55:29 CDT

If you would prefer a different format for the file size information, you can change it with the config element and the sizefmt attribute. You can also change the date and time format from the default format shown above by using the same Include element, but with the timefmt attribute. You could do something like this:

<!--#config timefmt="%x %T" -->
<!--#config sizefmt="bytes" -->
File Size: <!--#fsize virtual="$myfile" --> <br/>
Last Modified: <!--#flastmod virtual="$myfile" --> <br/>

The time formatting codes are based on strftime() from the C programming language. The alternative value for sizefmt is abbrev, which abbreviates kilobytes as k and megabytes as M. Here are the results of the previous Includes with the set element for the variable myfile still in place:

File Size: 996,072
Last Modified: 08/08/2004 18:55:29

The SSI time format can be changed globally using the SSITimeFormat directive. If I want to change the format to the same as in the previous excerpt, I could enter the following in http.conf:

SSITimeFormat "%x %T"

Don't forget to restart Apache after adding new directives to its configuration file so that they will take effect.

Executing Scripts and Commands

In addition to inserting text files and other simple bits of information into a Web page, an SSI element can call for the execution of a CGI script or a system command. To run a CGI script with an Include, the Apache module mod_cgi needs to be loaded (it usually is by default) and the directory that contains the script (e.g., cgi-bin) must be allowed to execute scripts by the Apache configuration file. CGI scripts may be executed by using either an exec element or an include element. Both work the same, except that exec doesn't allow key/value arguments to be passed to a script. Therefore, the include element with the virtual attribute is preferred, especially when running CGI scripts.

As an example, suppose that I want to execute a CGI script within a Web page that inserts a quote of the day. I could add something like the following to the page:

<!--#include virtual ="/cgi-bin/quote_of_day.cgi?user=${REMOTE_USER}"
-->

In this example, the script will be executed with the CGI variables passed to it. An environment variable for the user name of the client is given here. All of the standard CGI environment variables are allowed. They just need to be wrapped in curly braces and prefixed with a dollar-sign as shown above. The idea of passing this particular value to the script is that a different set of daily quotes may be drawn from depending on the user.

To execute a system command, I could use either the exec or the include element. As an example, suppose that I want to set up a Web page for a systems administrator to be able to execute a particular Perl program to fix a common problem with files on the office's FTP site. The sys admin wants this feature in a secure Web page for when she's traveling without her laptop computer. She wants to check server information on one page and, if needed, execute the Perl program through another. This can be done by adding the following to the page that will execute the program:

<!--#exec cmd="perl /admin/fix_ftp.plx" -->
<tt>
<!--#exec cmd="/bin/ls -tlH /home/ftp/pub
| perl -pe 's/\n/<br\/>/; s/\s/&nbsp;/g;'" -->
</tt>

With the SSI element exec, a program can be executed that has a file name extension (e.g., .plx) that Apache wouldn't recognize as an executable program. It just accepts the Include's instructions. In the first line above, the Include calls for the execution of a Perl program. To see the results of the program that was run, the second Include above runs the ls command with options (-t to sort by time of file; -l for a long, detailed listing; -H for human notation of file sizes) and a file path to see the contents of the FTP directory. The results of the ls command are piped to Perl to process for Web formatting: Perl executes a substitute statement (i.e., s/.../.../) that replaces new-lines characters (i.e., \n) with HTML break tags (i.e., <br/>). The second substitution replaces all spaces (i.e., \s) with HTML non-breaking spaces (i.e., &nbsp;).

Security

If an SSI can execute a system command or some other program outside of the document root, then this raises a security concern. I may want to allow Includes only in very secure directories. Depending on the situation, I may not want to allow executable Includes. This can be done with the IncludesNOEXEC option to the Options directive in the Apache configuration file. It would look like so:

Options +IncludesNOEXEC

Not only will this stop the execution of commands, but it will also prevent CGI scripts that are allowed to be executed directly from being executed through an Include.

Conclusion

There are a few more variables and some other directives associated with SSI that I didn't mention. There are also some flow-control elements (e.g., if and elif); however, I've covered the bulk of SSI here. When and where you use SSI depends on your situation. How you make use of SSI is left up to your imagination.

Russell Dyer is a Perl programmer, a MySQL developer, and a Web designer living and working on a consulting basis in New Orleans. He is also an adjunct instructor at a technical college where he teaches Linux and other open source software. He can be reached at russell@dyerhouse.com.

Copyright 2004 CMP Media LLC, Privacy Policy

Questions or problems regarding this web site should be directed to abeckman@outdoorssite.com.

Copyright 2008 Art Beckman. All rights reserved.

Last Modified: March 9, 2008