Why nginx internal redirect is not happening

I'm pretty sure I missed an obvious thing but it's driving me crazy, I need other eyeballs..

I got an application with plugins were sources are organized like:

/app/plugins/foo/www/... that corresponds to my URL http://example.com/plugins/foo/...

I got the following snippet as nginx configuration:

location /plugins/foo {
    alias /app/plugins/foo/www;
    try_files $uri /index.php =404;
}

location ~* ^/plugins/foo/(.*\.php)$ {
    alias /app/plugins/foo/www/$1;

    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

It works well for URLs like:

  • http://example.com/plugins/foo/style/style.css
  • http://example.com/plugins/foo/index.php
  • http://example.com/plugins/foo/bar.php

But as soon as I'm trying to reach (front controller pattern):

  • http://example.com/plugins/foo/?id=5
  • http://example.com/plugins/foo/another/path

I got to download the php file.

According to the logs, the try_files seems to do what is expected but instead of internal redirect to php handler, it server the file as static:

2017/01/24 13:29:36 [debug] 20803#0: *6 using configuration "/plugins/foo"
2017/01/24 13:29:36 [debug] 20803#0: *6 http cl:-1 max:1048576
2017/01/24 13:29:36 [debug] 20803#0: *6 rewrite phase: 3
2017/01/24 13:29:36 [debug] 20803#0: *6 post rewrite phase: 4
2017/01/24 13:29:36 [debug] 20803#0: *6 generic phase: 5
2017/01/24 13:29:36 [debug] 20803#0: *6 generic phase: 6
2017/01/24 13:29:36 [debug] 20803#0: *6 generic phase: 7
2017/01/24 13:29:36 [debug] 20803#0: *6 generic phase: 8
2017/01/24 13:29:36 [debug] 20803#0: *6 access phase: 9
2017/01/24 13:29:36 [debug] 20803#0: *6 access phase: 10
2017/01/24 13:29:36 [debug] 20803#0: *6 post access phase: 11
2017/01/24 13:29:36 [debug] 20803#0: *6 try files phase: 12
2017/01/24 13:29:36 [debug] 20803#0: *6 http script var: "/plugins/git/"
2017/01/24 13:29:36 [debug] 20803#0: *6 trying to use file: "/" "/app/plugins/foo/www/"
2017/01/24 13:29:36 [debug] 20803#0: *6 trying to use file: "/index.php" "/app/plugins/foo/www/index.php"
2017/01/24 13:29:36 [debug] 20803#0: *6 try file uri: "/plugins/foo/index.php"
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 13
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 14
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 15
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 16
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 17
2017/01/24 13:29:36 [debug] 20803#0: *6 content phase: 18
2017/01/24 13:29:36 [debug] 20803#0: *6 http filename: "/app/plugins/foo/www/index.php"
2017/01/24 13:29:36 [debug] 20803#0: *6 add cleanup: 000000000153FF70
2017/01/24 13:29:36 [debug] 20803#0: *6 http static fd: 13
2017/01/24 13:29:36 [debug] 20803#0: *6 http set discard body
2017/01/24 13:29:36 [debug] 20803#0: *6 xslt filter header
2017/01/24 13:29:36 [debug] 20803#0: *6 HTTP/1.1 200 OK 

So question is: how to implement my front-end controller pattern in this situation ?

EDIT

With

location /plugins/foo {
    alias /app/plugins/foo/www;
    try_files $uri /plugins/foo/index.php?$args;
}

I got redirected to Core front-controller instead of the plugin ones:

2017/01/25 13:45:48 [debug] 14086#0: *197 using configuration "/plugins/foo"
...
2017/01/25 13:45:48 [debug] 14086#0: *197 try files phase: 12
2017/01/25 13:45:48 [debug] 14086#0: *197 http script var: "/plugins/foo/"
2017/01/25 13:45:48 [debug] 14086#0: *197 trying to use file: "/" "/app/plugins/foo/www/"
2017/01/25 13:45:48 [debug] 14086#0: *197 http script copy: "/plugins/git/index.php?"
2017/01/25 13:45:48 [debug] 14086#0: *197 http script var: "group_id=101"
2017/01/25 13:45:48 [debug] 14086#0: *197 trying to use file: "/index.php?group_id=101" "/app/plugins/foo/www/index.php?group_id=101"
====> ??? 2017/01/25 13:45:48 [debug] 14086#0: *197 internal redirect: "/index.php?group_id=101"
2017/01/25 13:45:48 [debug] 14086#0: *197 rewrite phase: 1
...

Why redirect to /index.php?group_id=101 when /app/plugins/foo/www/index.php?group_id=101 is valid ?


To avoid the long standing issue with using alias together with try_files, you could use an if block instead (taking care to note usage restrictions). Note also, that $request_filename is used instead of $document_root$fastcgi_script_name to obtain aliased pathnames.

I have tested this example:

location ^~ /plugins/foo {
    alias /app/plugins/foo/www;

    if (!-e $request_filename) {
        rewrite ^ /plugins/foo/index.php last;
    }

    location ~ \.php$ {
        if (!-f $request_filename) {
            rewrite ^ /plugins/foo/index.php last;
        }
        fastcgi_pass 127.0.0.1:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }
}
  • The ^~ modifier make this location block take precedence over other location blocks at the same level (see this document).
  • The rewrite statement automatically appends arguments (see this document).
  • The nested location block handles PHP files within the aliased scope.
  • Always include fastcgi_params; before using fastcgi_param to avoid the latter being silently overwritten by the included file.