3

I have a location block that looks something like this:

root /var/www/ProjectP;

location /p/ {
    index index.php;
    try_files $uri $uri/ =404;
}

location ~ /p/.*\.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}

In order to make that work, I created a directory /var/www/ProjectP/p/, which is a horrible hack, because it puts the knowledge of where in http space the project is served with the project and not with nginx. Nginx config should be able to move it to /pp/ without modifying project P.

This particular project doesn't have a proxy_pass directive, but that will happen next, and then my hack is quite unlikely to work.

I'm sure nginx has a correct way to handle something so common, but I've not found it. Any pointers?

Update 1

As @RichardSmith notes, the right approach is surely an alias directive. Testing this on static content works nicely:

location /a/ {
    alias /var/www/ProjectA/;
    index index.html;
    try_files $uri $uri/ =404;
}

When I do the same with the php code, I get half success:

location /p/ {
    alias /var/www/ProjectP/;
    index index.php;

    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ /p/(.+\.php)$ {
    alias /var/www/ProjectP/$1;
    include snippets/fastcgi-php.conf;

    # With php7.0-fpm:
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    ## These next are largely set via snippets/fastcgi-php.conf.
    ## Trying them here doesn't help, but I leave them (commented out)
    ## for the moment...
    #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    #include fastcgi_params;
    #fastcgi_param SCRIPT_FILENAME $uri;
}

Testing against a non-php file, I confirm that the first block works. But the second block does not, and so php files don't serve properly. (I get 404's.) I've tried a few variants on the commented-out fastcgi directives at the end, but clearly not the right combination.

Update 2

This works.

root /var/www/;

location /p/ {
    alias /var/www/ProjectP/;
    index index.php;

    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;

    # Pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;

        # With php7.0-fpm:
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }
}
jma
  • 425
  • 6
  • 16
  • You should use an `alias` statement. Something like [this answer](https://serverfault.com/questions/876332/nginx-php-fpm-uri-alias-and-multiple-php-directories/876349#876349) – Richard Smith Oct 12 '17 at 09:12
  • @RichardSmith Thanks, I think that's the right approach. And after some reading and fiddling, it yields progress, but not quite success. I've amended the question to show what I've tried. – jma Oct 12 '17 at 18:45
  • @RichardSmith Now that I got it working, I see that you were 100% right and I had mistyped (mis-copied) the solution presented in that link. *Sigh*. – jma Oct 12 '17 at 19:23
  • My only suggestion is to remove your `try_files` statement which is default `nginx` behaviour anyway. `try_files` and `alias` can be a troublesome together, see [this issue](https://trac.nginx.org/nginx/ticket/97). – Richard Smith Oct 12 '17 at 19:24

2 Answers2

1

There is at least one issue with your location block.

If you request http://www.example.com/p/test.php, the contents of $1 variable will be test.php.

This means your

alias /var/www/ProjectP/$1;

will make the document root directory to /var/www/ProjectP/test.php.

Then, the

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

defines the actual filepath sent to PHP process to locate the file. $document_root contains the alias path in this cast, and $fastcgi_script_name contains the filename from the request.

So, the end result in your case, that the request to http://www.example.com/p/test.php ends up to a filename /var/www/ProjectP/test.phptest.php for PHP process. Therefore there will be a 404 returned.

The fix is to just use:

alias /var/www/ProjectP

in the PHP location block.

Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63
  • That makes sense, but doesn't fix the problem. I'm not sure why. I also tried specifying `$document_root` and `$request_filename`. But [this](https://stackoverflow.com/a/28494798/833300) sorted the problem. I'm not 100% sure why they are different. Here the php location block is nested in the outer block. – jma Oct 12 '17 at 19:12
  • Cf. update 2, above, for what the successful block looks like. – jma Oct 12 '17 at 19:17
  • Please post the solution as an answer yourself and accept it and remove the update from the question. – Tero Kilkanen Oct 13 '17 at 04:36
1

This works.

root /var/www/;

location /p/ {
    alias /var/www/ProjectP/;
    index index.php;

    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;

    # Pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;

        # With php7.0-fpm:
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
    }
}
jma
  • 425
  • 6
  • 16