Updated: 4 November 2026 · Applies to: Apache 2.4.68 with mod_include and nginx 1.26.3 (Debian 13), tested; AlmaLinux 10.2 httpd defaults checked; cPanel Apache Handlers according to cPanel
Apache only runs Server Side Includes (SSI) in files it is told to parse, and by default that is not .html. To make .html files run SSI on Apache, put these lines in the .htaccess file of the folder (or in the virtual host):
Options +Includes AddType text/html .shtml AddOutputFilter INCLUDES .html .shtml
Then include a file in any page with <!--#include virtual="/includes/header.html" -->. On nginx, add ssi on; to the location that serves the pages. The steps, the syntax rules and the errors you may meet are below. For what SSI is and when it makes sense, see What Are Server Side Includes (SSI) and When to Use Them.
1. Write the include directive
An SSI directive looks like an HTML comment, so a server that does not parse it simply sends it on and the browser hides it. In our tests on Apache 2.4.68 and nginx 1.26.3:
- It must start with
<!--#with no space:<!-- #include ... -->was left as a plain comment. - Put the value in double quotes, as in the examples.
- The space before
-->is the documented form."header.html"-->without the space also worked on both servers, but keep the space.
There are two ways to name the file:
<!--#include virtual="/includes/header.html" -->: a URL path. With a leading/it starts at the site's document root (for examplepublic_htmlon cPanel, or the folder of an addon domain); without it, it is relative to the current page. Use this one by default.<!--#include file="footer.html" -->: a file in the same folder as the page, or below it. Apache refuses../and absolute paths here.
A small test page, /ssi/index.html:
<!--#include virtual="/includes/header.html" --> <p>Main content</p> <!--#include file="footer.html" --> <p>Today: <!--#config timefmt="%d %B %Y" --><!--#echo var="DATE_LOCAL" --></p> <p>Page changed: <!--#flastmod file="index.html" --></p>
2. Enable SSI for .html files on Apache
- On your own server, make sure mod_include is loaded. On Debian and Ubuntu run
a2enmod includeand reload Apache. On AlmaLinux 10.2, httpd loads it by default (/etc/httpd/conf.modules.d/00-base.conf) andhttpd.confalready parses.shtmlfiles withAddOutputFilter INCLUDES .shtml. - Create or edit
.htaccessin the folder with the pages (or inpublic_htmlfor the whole site) and add the three lines from the top of this article.AddOutputFilter INCLUDES .htmltells Apache to parse.htmlfiles;Options +Includesallows SSI in that folder. - Load the page in a browser. Lab result for the test page:
<header>Site header</header> <p>Main content</p> <footer>Site footer</footer> <p>Today: 12 October 2026</p> <p>Page changed: 12 October 2026</p>
On your own server, .htaccess only works if the virtual host allows it. With Debian's default AllowOverride None, Apache ignored the file and sent the directives unparsed. With AllowOverride FileInfo alone, every page in the folder returned 500 Internal Server Error and the error log said .htaccess: Options not allowed here. This line in the <Directory> block was enough:
AllowOverride FileInfo Options=Includes,IncludesNOEXEC
3. Parse only some .html files with XBitHack
Apache's own SSI guide advises against parsing every .html file, because the server then reads through every page, including pages without any SSI. XBitHack parses only files that have the owner execute bit set:
Options +Includes XBitHack on
chmod 744 index.html # parsed chmod 644 about.html # sent as it is
In the lab, the same page was parsed at mode 744 and left unparsed at 644. Parsed pages are sent without a Last-Modified header, which makes browser and proxy caching weaker. With XBitHack full and the group execute bit set as well (chmod 754), Apache sent Last-Modified again. Only do that for pages whose output does not change on every request.
4. cPanel: Apache Handlers
According to cPanel, cPanel > Advanced > Apache Handlers applies a built-in handler to new extensions: enter server-parsed as the handler and .html as the extension, then click Add. cPanel also says .shtml is one of the extensions Apache already handles. The matching .htaccess form, which worked in our Apache test together with Options +Includes, is:
Options +Includes AddHandler server-parsed .html
Apache keeps server-parsed for backwards compatibility; AddOutputFilter INCLUDES is the current form. The cPanel steps are also in How to use .html files to run SSI? If you are on shared hosting and the directives still appear unparsed in the page source, ask your host whether SSI is allowed on your plan (see Do you support SSI (server side include) on html pages?).
5. Enable SSI on nginx
nginx does not read .htaccess, so this needs access to the server configuration, for example on a VPS. The SSI module is built into standard nginx builds, including the Debian 13 package we tested:
server {
...
location / {
ssi on;
}
}
Run nginx -t and systemctl reload nginx. The default ssi_types is text/html, so .html files are covered. nginx documents the form <!--# include virtual="/includes/header.html" --> (with a space after #); the Apache form without the space also worked. Differences we saw with the same test page:
include virtual,include file,config timefmtandecho var="DATE_LOCAL"worked.flastmodis not an nginx command: the page showed[an error occurred while processing the directive]and the log saidinvalid SSI command: "flastmod".file="../includes/header.html"failed withunsafe URIin the log.- A missing include did not show an error message: nginx inserted the body of its 404 page into the page. Use the
stubparameter to show something else.
Troubleshooting
- The directive is still in the page source: SSI is not active for that file. Check the extension,
Options +Includes,AllowOverrideand that mod_include is loaded (orssi on;on nginx). - [an error occurred while processing this directive] (Apache): the include failed. The error log names the reason, for example
The given path was above the root pathforfile="../...", orsubrequest returned 404for a missing file. - 500 error after adding .htaccess:
Optionsis not allowed byAllowOverride. - Security: if other people can edit your pages, use
Options +IncludesNOEXECinstead of+Includes. According to Apache, that turns off#exec, which runs commands as the web server user.
To edit .htaccess on cPanel, see How to Edit .htaccess File via the cPanel File manager?
Official documentation: Apache mod_include, nginx SSI module and cPanel Apache Handlers.