When using the include
command in SSI in an NGINX config, the $status
variable will always return 200 (and any maps using $status
also return whatever value is mapped to it) instead of the actual response code.
Interestingly, this does not happen for other variables like $request_id
or $remote_addr
.
map $status $status_text {
...
200 'OK';
503 'Service Unavailable';
...
}
error_page 502 503 504 /errorpages/503.html;
error_page 401 403 /errorpages/403.html;
location /errorpages/ {
ssi on;
root /var/www/;
}
#### 403.html ####
<!--# include file="footer.html" -->
#### footer.html ####
HTTP details: <!--# echo var="status" default="" --> <!--# echo var="status_text" default="" -->
I would've expected the error page to use the actual response code configured in error_page
as well as what is actually returned.
I've attempted to use =502
and =
in the error_page
configuration, but neither make a difference.
When you use the include
SSI instruction, nginx retrieves the contents of the included file using the subrequests internal mechanism.
Subrequests are primarily used to insert output of one request into another, possibly mixed with other data. A subrequest looks like a normal request, but shares some data with its parent. In particular, all fields related to client input are shared because a subrequest does not receive any other input from the client.
In your case, when requesting the footer.html
file, nginx uses a subrequest with the URI /errorpages/footer.html
. By default, subrequests are not logged in the access log. However, for debugging purposes, you can enable their logging using the log_subrequest
directive.
Nginx variables exist only within the request processing context. Some variables, like $request_id
, $remote_addr
, and even $request_uri
, are shared between the main request and all subrequests. However, $uri
variable, response-related variables (including the $status
) and user-defined variables are unique to each subrequest.
Sharing such variables between subrequests and the main request can be a non-trivial task. For example, the widely used auth_request
directive, which utilizes subrequest results for access control, has a dedicated auth_request_set
companion directive for this purpose.
Fortunately, you have an option to do the same using SSI engine internal variables:
#### 403.html ####
<!--# set var="result" value="$status" --><!--# set var="result_text" value="$status_text" -->
<!--# include file="footer.html" -->
#### footer.html ####
HTTP details: <!--# echo var="result" default="" --> <!--# echo var="result_text" default="" -->
If you want to use the result
SSI variable only when it is defined and fall back to the status
variable otherwise, you can achieve this using SSI conditional expressions:
#### footer.html ####
<!--# if expr="$result" -->
<!-- result variable is defined and not empty, do nothing -->
<!--# else -->
<!--# set var="result" value="$status" -->
<!--# set var="result_text" value="$status_text" -->
<!--# endif -->
HTTP details: <!--# echo var="result" default="" --> <!--# echo var="result_text" default="" -->