Nginx 匹配多个不同的PHP 项目

Nginx 匹配多个不同的PHP 项目

Http 服务器 1 year ago 1307 0

Nginx 匹配多个不同的PHP 项目

最近遇到了需要配置 2 个项目在不同文件夹,域名要配置同一个。研究了下 Nginx 配置终于配置好了。 配置如下:

下面是两个 Laravel 应用程序的工作配置,其中一个应用程序存在于另一个应用程序的子目录中。
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/first/public;

    index index.html index.htm index.php;

    server_name _;

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

    location /second {
        alias /var/www/second/public;
        try_files $uri $uri/ @second;

        location ~ \.php$ {
            include fastcgi-php.conf;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }
    }

    location @second {
        rewrite /second/(.*)$ /second/index.php?/$1 last;
    }

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

两个项目的程序文件实际上并不存在于彼此之间。应用程序 first 存在于 /var/www/first 中,而 second 应用程序存在于 /var/www/second 中。 在我看来,在这种情况下,这是首选的设置,因为嵌套应用程序文件,你“物理地”把一个项目的文件放在另一个项目的文件中,大多数PHP应用程序使用公共目录作为web根目录,这会变得非常混乱。 当然,根据应用程序的不同,你遇到的情况可能会有一些变化,但这不会对本教程产生太大的影响。 我们从一个基本的服务器配置开始,适合于服务单个应用程序:

server {
    listen 80 default_server;

    root /var/www/first/public;

    index index.html index.htm index.php;

    server_name _;

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

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}

这排除了你在生产应用程序中可能需要的一些东西(例如:静态资产的缓存头文件),但足以让一个PHP应用程序正常工作。我经常静态文件匹配成功,php 文件失败。一定要匹配正确。

添加嵌套项目

当在子目录中运行第二个应用程序时,我们遇到了一些问题。让我们一起来看看。 首先,我们知道我们想要在子目录 /second 中运行第二个应用程序(子目录是任意的,我只是选择将其命名为 second)。因此,我们为“嵌套”位置创建了一个位置块:

location /second {

}

web root:

我们知道嵌套项目有一个单独的 web root。像我一样,你的第一个倾向可能是设置一个根指向 Nginx 到 /var/www/second/public,但这最终不起作用! 相反,我们需要使用别名: alias

location /second {
    # 把 root 换成 alias + 项目路径
    alias /var/www/second/public;
}

alias 类似于 root,但具有不同的行为。 Nginx 结合 root 和给定的 URI 在磁盘驱动器上找到一个文件。例如,URI /foo/bar 将指示 Nginx 提供 /var/www/first/public/foo/bar。由于该目录不存在,try_files 部分告诉 Nginx 将请求发送到 /var/www/first/public/index.php。

includ fastcgi-php.conf 配置负责解析出 /foo/bar 作为 PHP 应用程序使用的路由的预期 URI。

alias 的行为并不完全像这样。在我们的例子中,/second URI 别名为 /var/www/second/public。因此,/second 的 URI 将在 /var/www/second/public 中查找要服务的文件。URI /second/foo 将指示 Nginx 查找 /var/www/second/public/foo ;省略了 /second 部分。 注意区别——使用这个 alias,Nginx不会像 root 那样查找 /var/www/alias/public/second/foo 中的文件。 因此,alias 具有我们想要的行为——它不会尝试在一些不存在的嵌套目录中查找文件。我们仍然需要从文件 /var/www/second/public/index.php 中创建一个类似 /second/foo 服务的URI,所以我们必须添加另一个 try_files

location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ /index.php$is_args$args;
}

看起来很眼熟! 但是,我们需要在/second的位置做一些PHP的事情,所以让我们在那里也得到一个PHP处理程序:

location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ /index.php$is_args$args;

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}

PHP 处理程序位置在 location /second{…},所以我们可以自定义它一点。 注意,我在PHP位置块中偷偷添加了一些东西。我(重新)设置SCRIPT_FILENAME FastCGI参数为$request_filename。这通常是$document_root$fastcgi_script_name,在我们的配置中,它总是指向 /var/www/first/public/index.php ——错误的应用程序! 相反,我们使用 $request_filename,它在Nginx文档中有如下定义:

当前请求的文件路径,基于 rootalias 指令,以及请求URI。 这样就正确地考虑了 alias,并将正确的路径传递给嵌套应用程序中的 index.php 文件。

工作原理

这将在一开始工作! 进入URI /second 可以正常工作。发生的事情是 /secondalias/var/www/second/public, try_files 将其发送到 /index.php,最终正确地为 /var/www/second/public/index.php 然而,如果我们的应用程序有一个定义的路由(foo,例如),我们试图前往URI /second/foo 到达它,我们收到一个 404 错误!不仅如此,这是一个来自first 应用程序的404页面! 这个请求最终由外部 PHP 处理程序处理,它使用 $document_root$fastcgi_script_name 作为 SCRIPT_FILENAME,因此指向文件 /var/www/first/public/index.php,并由 first 应用程序提供服务。

为了解决这个问题,我们重写了URI,将 index.php 放在 Nginx 眼中的正确位置。

重写

location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ @second;

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}

location @second {
    rewrite /second/(.*)$ /second/index.php?/$1 last;
}

我们调整 try_files 以将请求发送到 @second,然后将 @second 定义为命名位置块。 这个位置块重写URI,因此 /second/foo 变成 /second/index.php/foo。最后一个指令告诉 Nginx 使用新的、重写的URI,并将其与其他位置块进行匹配。 Nginx然后重新到达 location /second{…},在那里它被正确地解析! index.php 文件在磁盘上的正确位置,并且包含的 fastcgi-php.conf 配置正常地从 URI 的其余部分解析出 foo 路由(如果你好奇的话,可以通过 fastcgi_split_path_info)。

不要忘记上面解释的 SCRIPT_FILENAME FastCGI 参数所需要的更改。它将我们正确解析的脚本文件路径发送到 PHP-FPM

最后附带 Thinkphp 项目的配置

server
{
    listen 80;
    root ···;
    ···
    location /second {
            alias /www/wwwroot/second;
            if (!-e $request_filename) {
                rewrite  ^/(.*)$  /second/index.php?s=$1  last;
                break;
            }
            location ~ \.php$ {
                include fastcgi.conf;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_pass  unix:/tmp/php-cgi-74.sock;
            }
        }
}

原文: http://yiqiao.me/articles/36/nginx-matches-multiple-different-php-projects

版权声明: 自由转载-非商用-非衍生-保持署名 (创意共享3.0许可证)