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 example public_html on 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

  1. On your own server, make sure mod_include is loaded. On Debian and Ubuntu run a2enmod include and reload Apache. On AlmaLinux 10.2, httpd loads it by default (/etc/httpd/conf.modules.d/00-base.conf) and httpd.conf already parses .shtml files with AddOutputFilter INCLUDES .shtml.
  2. Create or edit .htaccess in the folder with the pages (or in public_html for the whole site) and add the three lines from the top of this article. AddOutputFilter INCLUDES .html tells Apache to parse .html files; Options +Includes allows SSI in that folder.
  3. 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 timefmt and echo var="DATE_LOCAL" worked.
  • flastmod is not an nginx command: the page showed [an error occurred while processing the directive] and the log said invalid SSI command: "flastmod".
  • file="../includes/header.html" failed with unsafe URI in the log.
  • A missing include did not show an error message: nginx inserted the body of its 404 page into the page. Use the stub parameter 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, AllowOverride and that mod_include is loaded (or ssi 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 path for file="../...", or subrequest returned 404 for a missing file.
  • 500 error after adding .htaccess: Options is not allowed by AllowOverride.
  • Security: if other people can edit your pages, use Options +IncludesNOEXEC instead 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.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Managed dedicated servers

our engineers look after the server for you, from $135 a month.

Was this answer helpful?

Still stuck? Open a ticket