'How can I make this nested location configuration use the correct path to call a php program?

I have setup nginx to allow users to have a user website (https://example.org/username maps to /home/username/www).

I want to allow my users to use php. Php is installed and working for a tld on the same server. I do not want to allow php generally on this server, just for specific configurations.

The configuration looks like this.

server {
  listen 443 ssl http2 default_server;
  listen [::]:443 ssl http2 default_server;

  server_name example.org;
  root /var/sites/example.org;

  access_log /var/log/nginx/example_org_access.log main;
  access_log /var/log/nginx/example_org_access.log scripts;
  error_log /var/log/nginx/example_org_error.log info;

  location / {
    try_files maintain.html /index.html @node;
  }

  location ~ ^/(.+?)(/.*)?$ {
    alias /home/$1/www/$2;
    index index.html index.htm;
    autoindex on;

    location ~ ^.+?\.php(/.*)?$ {
      include fastcgi_params;

      fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
      fastcgi_split_path_info ^(.+\.php)(/.*)$;

      # By default, the variable PATH_INFO is not set under PHP-FPM
      # But some apps need it. If you have a “Bad Request” error, double check this var!
      # NOTE: the separate $path_info variable is required. For more details, see:
      # https://trac.nginx.org/nginx/ticket/321

      set $path_info $fastcgi_path_info;
      fastcgi_param PATH_INFO $path_info;

      fastcgi_param SCRIPT_FILENAME /home$realpath_root$fastcgi_script_name;
      fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    }
  }
}

I also have the following log format.

log_format scripts 'fastcgi: $realpath_root/$fastcgi_script_name > $request';

which outputs

fastcgi: -//username/info.php > GET /username/info.php HTTP/2.0

The php-fpm log shows the following for the same request.

- -  27/Apr/2022:20:47:08 -0600 "GET /username/info.php" 404 - 0.154 2048 0.00%

And the error log dumps the following.

2022/04/27 20:47:08 [error] 915687#915687: *14 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 0.0.0.0, server: example.org, request: "GET /username/info.php HTTP/2.0", upstream: "fastcgi://unix:/var/run/php-fpm/php-fpm.sock:", host: "example.org"

All this tells me I'm doing the nested location wrong, specifically the fastcgi_param SCRIPT_FILENAME /home$realpath_root$fastcgi_script_name; line.

Changing that to fastcgi_param SCRIPT_FILENAME /home/$1/www/$fastcgi_script_name or fastcgi_param SCRIPT_FILENAME /home/$1/www/$2 doesn't work ($1 and $2 don't seem to be carried into the nested configuration, which makes sense).

So, am I mistaken in the belief I can set this up this way? How can I make this work?



Solution 1:[1]

@Richard Smith's comment helped point me in the right direction. This configuration works.

server {
  listen 443 ssl http2 default_server;
  listen [::]:443 ssl http2 default_server;

  server_name example.com;
  root /var/sites/example.com;

  access_log /var/log/nginx/example_com_access.log main;
  access_log /var/log/nginx/example_com_access.log scripts;
  error_log /var/log/nginx/example_com_error.log info;

  try_files index.html index.htm /index.html =404;

  location ~ ^/(?<username>[^/]+?)(?<userpath>/.*)?$ {
    alias /home/$username/www$userpath;

    location ~ ^.+?\.php(?:/.*)?$ {
      include fastcgi_params;

      fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
      fastcgi_split_path_info ^(.+\.php)(/.*)$;

      # By default, the variable PATH_INFO is not set under PHP-FPM
      # But some apps need it. If you have a “Bad Request” error, double check this var!
      # NOTE: the separate $path_info variable is required. For more details, see:
      # https://trac.nginx.org/nginx/ticket/321

      set $path_info $fastcgi_path_info;
      fastcgi_param PATH_INFO $path_info;

      fastcgi_param SCRIPT_FILENAME $request_filename;
      fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    }
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 harleypig