0

There are two hosts with a PHP-FPM pool each - one.com and two.com. I would like one.com/two to pass through and show two.com using two's pool, but I seem to be having difficulty.

Through alias and try_files, I've managed to get static assets from two.com's files served via. one.com/two/path/to/asset.ext, but PHP requests e.g. one.com/two/index.php (and requests to files which don't exist in two's files) seem to be falling back to the last rule and showing one.com's application 404 page instead.

Here's the location configuration for one.com:

location / {
    try_files $uri $uri/ /index.php$is_args$args;
}

location ~* ^/two$ {
        return 301 /two/;
}

location /two/ {
        alias /srv/two.com/public/;
        try_files $uri $uri/ /two/index.php$is_args$args;
}

location ~* ^/two/(.+\.php)$ {
        alias /srv/two.com/public/$1;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/7.1-two.com.sock;
}

location ~* \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/7.1-one.com.sock;
}

snippets/fastcgi-php.conf:

# regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;

# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

fastcgi_index index.php;
include snippets/fastcgi_params.conf;

$1 for the alias seems to be correct - I replaced the block with return 302 /$1 which would redirect the client to the expected path (e.g./two/foo.php->/foo.php`)

Furthermore, if I put deny all; on either of the last two location blocks, it blocks all of the affected requests (/two/*.php, /two/path/to/nonexistent.file)

It's like it's not stopping at the first fastcgi pass location block - am I missing something which should tell it to stop?

-

EDIT: Adding break; did not stop, and trying to debug by adding headers in each location block only shows the header present in the last generic php block.

-

EDIT 2:

It turns out that fastcgi_split_path_info needed changing to also account for the directory prefix.

So I've ripped out the snippet file and modified it a bit inside the location block:

location ^~ /two {
        alias /data/srv/nginx/two.com/public/;
        try_files $uri $uri/ /two/index.php$is_args$args;

        location ~* ^\/two.+\.php$ { # have also tried with just \.php$
            alias /srv/two.com/public/$1;

            fastcgi_split_path_info ^/two(.+\.php)().*$; # the second group is deliberately empty.

            try_files $fastcgi_script_name =404;

            fastcgi_param PATH_INFO $path_info;

            fastcgi_index index.php;
            include snippets/fastcgi_params.conf;

            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

            fastcgi_pass unix:/var/run/php/7.1-two.com.sock;
        }
}

This seems to get the location blocks working, except when I traverse one level deeper e.g. /two/account - which shows one.com's 404 page again.

I've dropped a deny on the outer location which stops the request, but dropping a deny on the inside location instead does not block the request. For some reason it decides to the use the last regex location in the original code.

Sean
  • 101
  • 3
  • 1
    Read about location priorities. It's not the order that counts! – Gerard H. Pille Sep 28 '18 at 15:32
  • True enough! I've tried nesting block 3 inside block 2 (using `~* \.php$`) instead to no avail. I believe it might have something to do with the `try_files` line inside the fastcgi snippet. Removing this is actually giving me different results, so that's my focus now - I get "Primary Script Unknown" from the FastCGI instance – Sean Sep 28 '18 at 15:35
  • What are the contents of `snippets/fastcgi_params.conf`? – Richard Smith Sep 28 '18 at 16:03
  • Just a list of `fastcgi_param` declarations which set up the server vars for PHP. I've made a bit of progress on this but hit another block. – Sean Sep 28 '18 at 16:13
  • 1
    Only recently I read that you shouldn't use try_files with fastcgi, a bug, it ruins fastcgi_split_path_info. – Gerard H. Pille Sep 28 '18 at 19:18
  • You still have two try_files. – Gerard H. Pille Sep 30 '18 at 02:08

1 Answers1

0

So I found the problem and a no-so-great solution.

As per the nginx documentation, there is a known bug when using try_files and alias in the same context (which won't be fixed).

The nginx bugtracker has a discussion on the bug including the cases and what is actually happening.

Therefore, what I had to end up needing to do is change my config as follows:

First, the trailing slash needed to be removed from alias lines as try_files will add the slash on itself.

Second, the try_files in the first block needed to prefix the request name twice - instead of /two/index.php, it became /two/two/index.php (because the alias will trim the first part off before determining the next location block).

Finally, for PHP, I needed to tweak the REQUEST_URI so instead of /two/index.php it would pass through as /index.php.

I created a variable mapping in my main nginx config as follows:

http {

    # ...

    map $request_uri $prefixless_request_uri {
        "~^/[^/]+(?P<path>.*)$" $path;
    }

And then referenced it right before I call fastcgi_pass to override the passed value.

fastcgi_param REQUEST_URI $prefixless_request_uri;
Sean
  • 101
  • 3