How to Set Up Server-Side Includes (SSI) in Apache

How to set up server-side includes (SSI) in Apache

How to set up server-side includes (SSI) in Apache

Long before I ever touched a JavaScript framework, I was maintaining a static HTML site where every page repeated the same header and footer by hand. The day I discovered Server-Side Includes, I stopped copy-pasting navigation markup across dozens of files and let Apache do the assembling for me. It’s an old technology, but I still reach for it on small static sites where a full build pipeline would be overkill.

In this post I’ll cover what SSI is, why I still use it, and exactly how I configure it in Apache.

What Is Server-Side Includes (SSI)?

SSI is a simple interpreted language embedded directly inside HTML comments that Apache processes before it sends the page to the browser. A directive looks like this:

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

When Apache serves the file, it swaps that directive for the actual content of header.html — the browser never sees the directive at all, only the final assembled HTML.

Why I Still Use SSI Today

Prerequisites

Step 1: Enable the Include Module

SSI processing runs through mod_include.

Debian/Ubuntu:

sudo a2enmod include
sudo systemctl restart apache2

RHEL/CentOS: I confirm the module is loaded in httpd.conf:

LoadModule include_module modules/mod_include.so

Step 2: Enable SSI Processing for a Directory

I edit the virtual host or directory block to allow SSI execution:

<Directory /var/www/html>
    Options +Includes
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml
</Directory>

I reload Apache after changes:

sudo apachectl configtest
sudo systemctl reload apache2

Optional: Processing .html Files as SSI

If I want existing .html files to support SSI without renaming everything to .shtml (there’s a performance trade-off I get into below):

AddOutputFilter INCLUDES .html

Step 3: My First SSI File

/var/www/html/includes/header.html:

<header>
    <h1>My Static Site</h1>
    <nav><a href="/">Home</a> | <a href="/about.shtml">About</a></nav>
</header>

/var/www/html/index.shtml:

<!DOCTYPE html>
<html>
<head><title>Home</title></head>
<body>
    <!--#include virtual="/includes/header.html" -->
    <p>Welcome to my site. Today's date is <!--#echo var="DATE_LOCAL" --></p>
    <!--#include virtual="/includes/footer.html" -->
</body>
</html>

Load the page in a browser and the header and footer show up as if they’d always been part of the file.

Common SSI Directives I Use

Include a file

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

virtual is relative to the document root; file is relative to the current file’s directory. I stick with virtual for portability.

Echo a variable

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

Set a variable

<!--#set var="name" value="Ahmad" -->
<p>Hello, <!--#echo var="name" -->!</p>

Execute a command (I use this sparingly and carefully)

<!--#exec cmd="uptime" -->

Conditional logic

<!--#if expr="$QUERY_STRING = /admin/" -->
    <p>Admin view</p>
<!--#else -->
    <p>Public view</p>
<!--#endif -->

Show file modification time

<!--#flastmod virtual="index.shtml" -->

Show file size

<!--#fsize virtual="/downloads/manual.pdf" -->

Real-World Use Cases

Security Best Practices I Follow

SSI’s exec directive is powerful, and I treat it with real caution. If a directory allows both file uploads and SSI exec, someone who uploads a .shtml file could run arbitrary shell commands on the server.

Performance Optimization

Mistakes I’ve Made

Troubleshooting

SSI directives appear as literal text in the browser I check that mod_include is enabled and AddOutputFilter INCLUDES targets the right file extension.

500 Internal Server Error on SSI pages I check the error log:

sudo tail -f /var/log/apache2/error.log

Usually a referenced include file doesn’t exist, or exec is disabled but being called.

Includes not updating after editing the source file I clear any browser or intermediate proxy cache; SSI itself re-processes on every request by default.

FAQs

Is SSI still relevant in 2026? For small static sites and legacy systems, yes, in my experience. For anything beyond simple content reuse, I reach for a static site generator or a real backend framework instead.

Can SSI replace a templating engine like PHP or a JS framework? No. It’s intentionally limited to basic includes, variable substitution, and simple conditionals — no loops, no complex data structures, no database connectivity.

Does SSI hurt page load performance for visitors? Minimal for small includes, but every SSI-enabled request needs server-side processing rather than being served as pure static content, which is slightly slower at scale.

Summary and Key Takeaways

References

Exit mobile version