Wondering about the difference between doing:
location / {
try_files $uri $uri/ =404;
}
And doing:
location / {}
They both seem to serve files\folders only if they exist, or returning 404 error page if they don't.
Although there is no difference in nginx behavior between these configurations (except for logging the 404 Not Found
errors in the error log, see below), they do differ in terms of performance. In short, using the try_files $uri $uri/ =404;
directive will be less reliable and will lead to two additional stat()
system calls. Below is an excerpt from my correspondence with one of the nginx developers, Valentin Bartenev:
The
try_files
directive operates in a separateNGX_HTTP_PRECONTENT
phase and performs astat()
on each of its rules until it finds an available element and stays in the current location, or it executes the command specified by its last parameter. Additionally, it does not check for the presence of an index file if the path ends with a slash, but it will perform a separatestat()
on the directory.If it remains in the current location, the static module knows nothing about already executed
try_files
and will then performopen()
and a more efficientfstat()
again.For this reason, instead of using a construction like:
try_files $uri @backend;
it is more efficient and reliable to use:
error_page 404 = @backend;
In the presence of a file, in the first case we get:
stat() -> open() -> fstat()
while in the second case:
open() -> fstat()
Moreover, in the first case, between
stat()
andopen()
, the file could be deleted, and the configuration would not work as expected: instead of a redirection, you would get an HTTP 404Not Found
error.
The try_files
directive itself has almost nothing to do with how the response is actually generated. The response is generated by modules that are invoked during the next request processing phase, NGX_HTTP_CONTENT_PHASE
(for most configurations, this means only the index and static modules). The index module checks whether the request URI corresponds to a physical directory and may perform an internal redirect to an index file within that directory. The static module is responsible for serving static content.
The only way the try_files
directive can affect the response is by modifying the current URI according to the first parameter that passes an existence check — although this doesn't apply in the case of try_files $uri $uri/ =404;
.
Except for two extra stat()
system calls that would have been better avoided, the only difference when using this directive is that when the requested file or directory is missing, no corresponding error message is written to the error log (since the request processing will be terminated during the NGX_HTTP_PRECONTENT_PHASE
and won't reach the next NGX_HTTP_CONTENT_PHASE
, where index or static modules could log such an error). Without the try_files
directive, the same behavior can be achieved using the log_not_found off;
directive. However, logging such messages can actually be useful — for example, to detect HTML layout errors or to monitor and block attackers probing your site for security breaches, using tools like Fail2ban.