Apache HTTP Server Version 2.4

Server Side Includes (SSI) provide a way to add dynamic content to existing HTML documents without requiring a full application framework. They are particularly useful for inserting common elements — headers, footers, navigation, timestamps — into otherwise static pages.
| Related Modules | Related Directives |
|---|---|
SSI lets you drop simple directives into your HTML files that the server evaluates before sending the page to the client. This is a lightweight way to keep shared content (like a site-wide footer or a "last modified" timestamp) in one place, without needing a template engine or application server.
This document covers configuring httpd to permit SSI, basic SSI directives for common tasks, and some more advanced techniques including variables and conditional expressions.
SSI directives are HTML comments with a specific syntax that
mod_include recognizes and evaluates before the
page is sent to the client. They look like this:
<!--#echo var="DATE_LOCAL" -->
When the page is served, this fragment is replaced with its value:
Thursday, 18-Jun-2026 14:22:07 EDT
Because the directives are embedded in HTML comments, if SSI is not enabled, browsers ignore them (though they remain visible in the page source).
To enable SSI processing, add the following directive to your
httpd.conf file or to a .htaccess
file:
Options +Includes
This tells httpd to parse files for SSI directives. Since most
configurations contain multiple Options directives that can override each other, apply
this to the specific directory where you want SSI enabled.
You also need to tell httpd which files to parse. There are two common approaches.
The first is to designate a file extension (typically
.shtml) for SSI-enabled pages:
AddType text/html .shtml AddOutputFilter INCLUDES .shtml
The disadvantage here is that adding SSI to an existing page
requires renaming the file (and updating all links to it) to use
the .shtml extension.
The second approach uses the XBitHack directive:
XBitHack on
XBitHack tells
httpd to parse any file that has its execute bit set. To enable
SSI on an existing page, make the file executable:
chmod +x pagename.html
Avoid configuring httpd to parse all .html
files for SSI directives. This forces the server to read through
every HTML file it serves, even those without any SSI content,
which adds unnecessary overhead.
On Windows, there is no execute bit, so the
XBitHack approach is
not available. Use the file-extension method instead.
By default, httpd does not send the last-modified date or content-length headers on SSI pages, since these values are difficult to calculate for dynamic content. This can prevent caching and result in slower perceived performance. Two approaches can help:
XBitHack Full, which tells httpd to
determine the last-modified date from the originally requested
file, ignoring the modification dates of included files.mod_expires to set an explicit
expiration time, letting browsers and proxies know the content
is safe to cache.SSI directives use the following syntax:
<!--#function attribute=value attribute=value ... -->
If SSI is correctly configured, the directive is replaced with its output. If not, it remains as an HTML comment — invisible to the end user but present in the source.
<!--#echo var="DATE_LOCAL" -->
The echo function outputs the value of a variable.
Standard variables include the full set of environment variables
available to CGI programs, plus variables you define with
set.
To customize the date format, use the config
function with the timefmt attribute:
<!--#config timefmt="%A %B %d, %Y" -->
Today is <!--#echo var="DATE_LOCAL" -->
This document last modified <!--#flastmod file="index.html" -->
This function is also subject to timefmt
configuration.
SSI can include the output of a CGI program directly in the page:
<!--#include virtual="/cgi-bin/counter.pl" -->
The following are practical examples of common SSI use cases.
A common use of SSI is to display a "last modified" timestamp
on each page. The following code uses the
LAST_MODIFIED variable so you can paste the same
snippet into any file without changing the filename:
<!--#config timefmt="%D" -->
This file last modified <!--#echo var="LAST_MODIFIED" -->
For details on timefmt format strings, see the
documentation for strftime in your system's C
library reference.
On a site with more than a few pages, maintaining a consistent header or footer across all pages can be tedious. SSI solves this by letting you keep shared content in a single file and include it everywhere:
<!--#include virtual="/footer.html" -->
The include function accepts two attributes:
file specifies a path relative to the current
directory (it cannot be an absolute path or contain
../), while virtual specifies a URL
relative to the document being served (it can start with
/ but must be on the same server).
SSI directives inside included files are evaluated normally,
and includes can be nested. This means you can put a
LAST_MODIFIED timestamp in your footer file, and
it will be evaluated in the context of each page that includes
it.
In addition to timefmt, the config
function supports two other attributes.
The errmsg attribute changes the error message
displayed when an SSI directive fails. The default is:
[an error occurred while processing this directive]
You can replace it with something more appropriate for your site:
<!--#config errmsg="[Content unavailable]" -->
The sizefmt attribute controls how file sizes
are formatted: bytes for a full byte count, or
abbrev for an abbreviated form in KB or MB.
The exec function can run a shell command and
include its output in the page. On Unix-like systems, the
command is executed via /bin/sh; on Windows, via
the command shell.
<pre> <!--#exec cmd="ls" --> </pre>
The exec feature is a significant security risk. It
executes arbitrary commands with the permissions of the web
server process. If users can edit content on your site, ensure
this feature is disabled by using IncludesNOEXEC
instead of Includes in the Options directive.
Beyond simple content inclusion, SSI supports variables and conditional expressions, making it possible to generate different content based on the request context.
The set directive defines variables for use later
in the page:
<!--#set var="name" value="Rich" -->
Variables can reference other variables (including
environment variables) using the dollar
sign ($) prefix:
<!--#set var="modified" value="$LAST_MODIFIED" -->
To include a literal dollar sign, escape it with a backslash:
<!--#set var="cost" value="\$100" -->
When a variable name might be ambiguous within a longer string, use braces to delimit it:
<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->
mod_include provides if,
elif, else, and endif
constructs for building conditional logic. This lets you
generate different output from a single physical page.
The structure is:
<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->
A test_condition can compare values or test whether a
variable is non-empty. See the mod_include
documentation for the full list of comparison operators.
For example, to display different greetings based on the time of day:
Good
<!--#if expr="%{TIME_HOUR} <12" -->
morning!
<!--#else -->
afternoon!
<!--#endif -->
Any variable — user-defined or from the environment — can be used in conditional expressions. See Expressions in Apache HTTP Server for full details on the expression evaluation engine.
Combined with httpd's ability to set environment variables
using SetEnvIf and
related directives, conditional SSI can handle a wide variety of
dynamic content scenarios without a full application
framework.
For sites that are mostly static but need a few dynamic
touches, SSI avoids the overhead of setting up a full
application stack. It requires only mod_include
and a few lines of configuration to get started.