Nginx how to; Server Side Include (SSI) debugging

25 Jan 2010

Server Side Includes (SSI) are a great feature of Nginx allowing you to cache core content of a page but dynamically replace any blocks of the page that are dynamic, for example login links / welcome text. But they can sometimes hold some gotchas, so heres a post on debugging SSI or debugging Nginx configs in general.

I spent a morning debugging on Nginx when SSI's weren't acting as expected - they were missing! including the stubs and I was losing markup on the page. When dealing with SSI's here are two key rules:

  • SSI's must be well formed - otherwise funny things happen!
  • Debugging isn't always easy, but patience is key!

SSI's must be well formed

Funny things happen when your SSI syntax is malformed! But finding the cause isn't always easy.

What's wrong with this snippet?

<!--# block name="default_message" -->  <p>Sorry, this feature is currently unavailable</p><!-- endblock --><!--# include virtual="/dynamic/footer-links" stub="default_message" -->

The results of the above snippet is all content / markup after it is truncated!

Debugging SSI's

Firstly, turn off Silent Errors in your config like so:

ssi_silent_errors off;
You should see in the browser any errors outputted as "[an error occurred while processing the directive]" if there has been an error with the SSI.

If you are using a proxy - check the proxy access logs to ensure that the requests are being made by Nginx! If they are ensure that they are rendering the expected output.

Next step is to check what Nginx is doing, turn on debugging and logging of SSI's in your Nginx config:

error_log   /var/log/nginx/error.log debug;    log_subrequest  on;

The error log will now start to report all logic steps and actions for requests made to it - they are quite extensive! You are looking for all SSI includes:

... [debug] 1545#0: *2 ssi include: "/dynamic/user_status_bar/"

If your SSI include isn't listed - then check your markup! It probably is malformed like mine above - I was missing a # from the endblock tag it should have read:

<!--# block name="default_message" -->  <p>Sorry, this feature is currently unavailable</p><!--# endblock --><!--# include virtual="/dynamic/footer-links" stub="default_message" -->

That simple typo cost me a morning, so check your markup! What actually was happening was that Nginx got all the SSI but it couldn't find the endblock and silently errored and discarded the rest of the content.