最近遇到了需要配置 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文档中有如下定义:
当前请求的文件路径,基于
root
或alias
指令,以及请求URI。 这样就正确地考虑了alias
,并将正确的路径传递给嵌套应用程序中的index.php
文件。
这将在一开始工作! 进入URI /second
可以正常工作。发生的事情是 /second
被 alias
为 /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
。
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许可证)