Why nginx returns 301 status code when trying to open a directory?

I am trying to understand how Nginx works. Now I'm working on index and try_files directives. My config file is this:

events {}
http {
  rewrite_log on;
  error_log /var/log/nginx/localhost.error_log debug;

  server {
    root /app;
    listen 8080;
    index index.html;
    location / {
      try_files $uri $uri/ =404;
    }
  }
}

Also /app/ tree directory is:

/app
|-- abcd.html
|-- file.php
|-- index.html
|-- index.php
|-- sss
|   `-- index.html
|-- style.css
`-- thumb.png

When I try to open localhost:8080 everything works as expected. It first uses location / context. Then uses $uri/ to read the root directory. Then because index file name has been specified, it uses index file in that directory. Also, the log file can show that:

...
2021/10/27 11:37:49 [debug] 1297#1297: *1 test location: "/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 using configuration "/"
...
2021/10/27 11:37:49 [debug] 1297#1297: *1 generic phase: 12
2021/10/27 11:37:49 [debug] 1297#1297: *1 try files handler
2021/10/27 11:37:49 [debug] 1297#1297: *1 http script var: "/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 trying to use file: "/" "/app/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 http script var: "/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 trying to use dir: "/" "/app/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 try file uri: "/"
2021/10/27 11:37:49 [debug] 1297#1297: *1 generic phase: 13
2021/10/27 11:37:49 [debug] 1297#1297: *1 content phase: 14
2021/10/27 11:37:49 [debug] 1297#1297: *1 open index "/app/index.html"
2021/10/27 11:37:49 [debug] 1297#1297: *1 internal redirect: "/index.html?"
...

But when I open localhost:8080/sss, It first responds with a redirection to localhost:8080/sss/, then opens the index file inside the sss/ directory. Here is the logs:

2021/10/27 11:46:07 [debug] 1297#1297: *3 test location: "/"
2021/10/27 11:46:07 [debug] 1297#1297: *3 using configuration "/"
2021/10/27 11:46:07 [debug] 1297#1297: *3 http cl:-1 max:1048576
2021/10/27 11:46:07 [debug] 1297#1297: *3 rewrite phase: 3
2021/10/27 11:46:07 [debug] 1297#1297: *3 post rewrite phase: 4
2021/10/27 11:46:07 [debug] 1297#1297: *3 generic phase: 5
...
2021/10/27 11:46:07 [debug] 1297#1297: *3 try files handler
2021/10/27 11:46:07 [debug] 1297#1297: *3 http script var: "/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 trying to use file: "/sss" "/app/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 http script var: "/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 trying to use dir: "/sss" "/app/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 try file uri: "/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 generic phase: 13
2021/10/27 11:46:07 [debug] 1297#1297: *3 content phase: 14
...
2021/10/27 11:46:07 [debug] 1297#1297: *3 content phase: 18
2021/10/27 11:46:07 [debug] 1297#1297: *3 http filename: "/app/sss"
2021/10/27 11:46:07 [debug] 1297#1297: *3 add cleanup: 000055AA4A146290
2021/10/27 11:46:07 [debug] 1297#1297: *3 http static fd: -1
2021/10/27 11:46:07 [debug] 1297#1297: *3 http dir
2021/10/27 11:46:07 [debug] 1297#1297: *3 http finalize request: 301, "/sss?" a:1, c:1
2021/10/27 11:46:07 [debug] 1297#1297: *3 http special response: 301, "/sss?"
2021/10/27 11:46:07 [debug] 1297#1297: *3 http set discard body
...

Why it didn't respond with the index file inside the sss/ directory, just like the root directory, without external redirection?


Solution 1:

The $uri/ term on a try_files statement works the same way as Nginx default behaviour.

If you provide a URI without a trailing / that points to a directory, Nginx will first append a trailing / using an external redirect (i.e. 301).

If you provide a URI with a trailing / that points to a directory, the index directive will be invoked and may generate an internal redirect to whichever file is specified (e.g. index.html).

Although the documentation is clear that a trailing / is required by the index directive. I cannot find where the former behaviour is documented.