Score:1

Nginx try_files doesn't work inside server block

ar flag
http {
include mime.types;
default_type application/octet-stream;

server {
    root /websites;
    listen 80;
    server_name localhost;

    # don't work
    try_files /logo.png /logo.jpg /error;

    # works
    rewrite ^/e /error;

    # works
    # return 200 "$request_uri Handled by server block";

    location / {
        default_type text/plain;
        return 200 "Root prefix matched";
    }

    location /error {
        default_type text/plain;
        return 404 "Logo not found";
    }
}

I want to know what is the cause of this evaluation, I couldn't find any reliable explanation neither on documentation nor on forums.

By the way I've experimented the following scenario:

  • Removed location / {} block and it worked as intended. I know that when the request is made to the server it first evaluated by server block and then matched location blocks. But it seems try_files directive is ignored(WHY?!!). If I'm correct the last argument of try_files directive rewrites the URI so it should behave as rewrite directive. Both rewrite and return directives worked as intended, they evaluated every time irrespective to whether there are location block matches or not.

I researched a lot to find reliable information explaining this situation, but I couldn't find. So I'm asking here for the answer or source about Nginx internals someone who knows.

Richard Smith avatar
jp flag
Your assumption that "it first evaluated by server block" is not correct.
Safar Safarli avatar
ar flag
@RichardSmith. Thanks for your attention. Can you please explain why?
Ivan Shatsky avatar
gr flag
@SafarSafarli Besides what is already said by Richard Smith, you should know there is a different request processing phases. Check [nginx development documentation](http://nginx.org/en/docs/dev/development_guide.html#http_phases) or [this article](http://www.nginxguts.com/phases/) for more information. Directives from `ngx_http_rewrite_module` placed at the server level processed during the `NGX_HTTP_SERVER_REWRITE_PHASE` while `try_files` directive processed during the `NGX_HTTP_PRECONTENT_PHASE`.
Safar Safarli avatar
ar flag
@IvanShatsky, Thanks for you attention.
Safar Safarli avatar
ar flag
@IvanShatsky I've read the section of the article you've provided. But I found it a bit tricky to understand, E.g: " `ngx_http_try_files_module` and `ngx_http_mirror_module` register their handlers at this phase..". Calling `ngx_http_try_files_module` as a module is confusing, shouldn't be "directive" word used instead?
Ivan Shatsky avatar
gr flag
@SafarSafarli The `try_files` directive actually resides in its own [`ngx_http_try_files_module`](https://github.com/nginx/nginx/blob/master/src/http/modules/ngx_http_try_files_module.c) rather than [`ngx_http_core_module`](https://github.com/nginx/nginx/blob/master/src/http/ngx_http_core_module.c) (see provided GitHub links to the nginx source code).
Safar Safarli avatar
ar flag
@IvanShatsky, then, why it's put as a directive of core module?https://nginx.org/en/docs/http/ngx_http_core_module.html. It is so confusing
Ivan Shatsky avatar
gr flag
@SafarSafarli I found an answer to your question. It _was_ the directive of core module until a redesign that happens in 2017. Until that `try_files` directive used a special `TRY_FILES_PHASE` that was available exclusively for `try_files` and no other directives. With the redesign new `PRECONTENT_PHASE` was added to nginx request processing workflow and the `try_files` directive implementation was moved to a separate module using that phase. Now any third-party module can use this new `PRECONTENT_PHASE` along with the `nginx_http_try_files_module`.
Ivan Shatsky avatar
gr flag
@SafarSafarli So I think the nginx team just decided not to rewrite the documentation. There is a little difference from the end user point of view. All the same you can't disable neither `nginx_http_core_module` nor `nginx_http_try_files_module` when you build nginx from the sources. You can look at the aforementioned redesign commit to nginx source [here](https://github.com/nginx/nginx/commit/129b06dc5dfab7b4513a4f274b3778cd9b8a6a22).
Score:0
jp flag

See how nginx processes a request. But I will add a couple of caveats that specifically address your question and are easily observed but may not be well documented.

You mention rewrite and return directives, but these belong to the ngx_http_rewrite_module which have there own evaluation rules and do not behave the same as the core directives. You are correct that rewrite and return in server context can execute before the location block is selected.

As you have observed (with the exception of the ngx_http_rewrite_module), the server context acts like the default location, that is, if no other location block matches the request. The presence of an explicit location / { ... } block will always take precedence.

Safar Safarli avatar
ar flag
I got it, but my question is mainly about "try_files" directive. Can you please provide more info about it. In this case in server context. Thanks
Richard Smith avatar
jp flag
I don’t have any more info, as I said this is observed behaviour.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.