【问题标题】:Can't run node from web server无法从 Web 服务器运行节点
【发布时间】:2018-01-27 13:06:56
【问题描述】:

我试图从 PHP 网页运行 npm,但它永远不会运行。我总是得到 127 的退出代码并且没有输出。在做了一些测试后,我将问题缩小到npm 中的shebang,如下所示:

#!/usr/bin/env node

相当标准,但我做了一些测试代码:

<?php
$result = exec("/usr/bin/env node --version", $output, $exit);
var_dump($result);
var_dump($exit);
$result = exec("node --version", $output, $exit);
var_dump($result);
var_dump($exit);
$result = exec("/usr/bin/env gzip --version", $output, $exit);
var_dump($result);
var_dump($exit);

在我的浏览器中得到了这个输出:

string(0) ""
int(127)
string(6) "v8.4.0"
int(0)
string(28) "Written by Jean-loup Gailly."
int(0)

我在 PHP-FPM 配置中启用了catch_workers_output,并在 PHP 日志中看到了这一点:

[18-Aug-2017 15:15:35] WARNING: [pool web] child 27872 said into stderr: "/usr/bin/env: "
[18-Aug-2017 15:15:35] WARNING: [pool web] child 27872 said into stderr: "node"
[18-Aug-2017 15:15:35] WARNING: [pool web] child 27872 said into stderr: ": No such file or directory"
[18-Aug-2017 15:15:35] WARNING: [pool web] child 27872 said into stderr: ""

我还尝试从 Web 服务器运行 exec("which node"),并在 PHP 日志中看到了这一点:

[18-Aug-2017 15:31:12] WARNING: [pool web] child 27873 said into stderr: "which: no node in ((null))"

我尝试运行 var_dump(exec('echo $PATH')) 并得到以下输出:

string(28) "/usr/local/bin:/bin:/usr/bin"

这似乎与env 命令如何处理路径有关。我尝试使用nginx.conf 中的fastcgi_param PATH 指令手动设置它,但对上述输出没有任何改变。

单独运行 env 并打印输出如下所示,没有 PATH 条目:

Array
(
    [0] => USER=nginx
    [1] => PWD=/var/www/html
    [2] => SHLVL=1
    [3] => HOME=/var/cache/nginx
    [4] => _=/bin/env
)

我在一个基于 RHEL 的发行版上,禁用了 SELinux,通过 Nginx 1.12.1 的 UNIX 套接字运行 PHP-FPM 5.6.31。 /usr/local/bin/node 是一个指向/usr/local/nodejs/bin/node 的符号链接,它有 775 个权限。出于测试目的,nginx 用户拥有/usr/local/nodejs 目录及其所有后代。有什么建议吗?


请注意,如果我从 CLI(作为 nginx 用户)运行 PHP 代码,它会按预期工作,所以这肯定与 CGI/FPM 环境有关。

$ su -s "/bin/sh" -c "/var/www/html/test.php" nginx
string(6) "v8.4.0"
int(0)
string(6) "v8.4.0"
int(0)
string(28) "Written by Jean-loup Gailly."
int(0)

【问题讨论】:

  • 在浏览器中运行exec("which node", $output, $exit);会发生什么?
  • @chiliNUT 没有输出,退出代码 1。这又没有意义,因为我可以只使用 node 运行它,所以它必须在 $PATH 中。在 CLI 中工作正常($_SERVER["PATH"] 在 FPM 中返回 null,在 CLI 上似乎很好)
  • 很奇怪。如果 which 返回代码 1 我认为这意味着它没有找到它。但如果你可以只用node 运行它,它必须在$path...但我很确定which 只是查看路径中的所有内容,直到找到它或放弃它,所以这很奇怪
  • 根据_变量,用/bin/env调用shell。当你运行exec("/bin/env node --version", $output, $exit); 时会发生什么?
  • @piarston 是一样的,/usr/bin/env 是一个符号链接。

标签: php bash shell npm path


【解决方案1】:

让我好奇的一件事...为什么以 ngnix 用户身份运行脚本完全可以工作?

实际上,ngnix 正在向 php-fpm 询问进程,而执行脚本的是 PHP-FPM。因此,可能 PHP-FPM 服务就是其中之一,它缺少对您的 /usr/bin/env node 的权限。

为了简单起见,ngnix 需要权限才能将其虚拟手放在 PHP-FPM 上。但需要权限才能处理文件的是 PHP-FPM。

为了使解决方案简单,可能会通过将 PHP-FPM 用户(www-data?)添加到组中来修复,该节点二进制文件在其中,ngnix 用户已经在其中。

或者更好地遵循这些建议:https://serverfault.com/a/52703

编辑#1:

我仍然会照顾特权。

/usr/local/bin/node 是到 /usr/local/nodejs/bin/node 的符号链接,它有 775 个权限。 nginx 用户拥有 /usr/local/nodejs

在没有-x 的情况下在/usr/local 树上设置特定用户有点不标准。到 /usr/local 成为任何用户的存储库时。

请在不同的情况下(从 CLI、FPM、ngnix、etx)运行此脚本并检查您的权限:

<?php

$myuid = getmyuid();
$mygid = getmygid();

// you should change to check /usr/local/nodejs/bin/node
$path = '/usr/local/n/versions/node/7.2.0/bin/node'; 

$patharray = array_filter(explode('/', $path));

$dump = "%s \t %s \t %s%s%s \t %s" . PHP_EOL;

$fileOrFolder = __FILE__;
printf("uid \t gid \t rwx \t file" . PHP_EOL);
printf($dump, $myuid, $mygid, (is_readable($fileOrFolder) ? 'r' : '-'), (is_writable($fileOrFolder) ? 'w' : '-'), (is_executable($fileOrFolder) ? 'x' : '-'), $fileOrFolder);

$fileOrFolder = '';
while(count($patharray) > 0) {
    $fileOrFolder .= ('/' .  array_shift($patharray));

    $myuid = posix_getpwuid(fileowner($fileOrFolder));
    $mygid = posix_getgrgid(filegroup($fileOrFolder));

    printf($dump, $myuid['name'], $mygid['name'], (is_readable($fileOrFolder) ? 'r' : '-'), (is_writable($fileOrFolder) ? 'w' : '-'), (is_executable($fileOrFolder) ? 'x' : '-'), $fileOrFolder);

    if (is_dir($fileOrFolder) && !is_executable($fileOrFolder)) {
        echo PHP_EOL . "Ouh, cant go further cause of privelages" . PHP_EOL;
        break;
    }
}

我的输出证明,尽管是不同的用户,PHP 可以一直向下查找目标文件:

@riddick:~/temp$ php phpowner.php
uid      gid     rwx     file
1000     1000    rw-     /home/yergo/temp/phpowner.php
root     root    r-x     /usr
root     root    r-x     /usr/local
root     root    r-x     /usr/local/n
root     root    r-x     /usr/local/n/versions
root     root    r-x     /usr/local/n/versions/node
root     root    r-x     /usr/local/n/versions/node/7.2.0
                 r-x     /usr/local/n/versions/node/7.2.0/bin
                 r-x     /usr/local/n/versions/node/7.2.0/bin/node

【讨论】:

  • PHP-FPM 被配置为作为用户/组nginx运行
  • 请参考我的补充。 IMO 它仍然是一些特权不匹配的情况。
【解决方案2】:

您需要在/etc/php5/fpm/pool.d/www.conf 中设置PATH 环境以包含/usr/local/bin/node。

在 ubuntu 发行版中被注释掉:

;env[PATH] = /usr/local/bin:/usr/bin:/bin 

所以

env[PATH] = /usr/local/bin/node 

应该做的工作。 RHEL 应该不会有太大的不同,但是即使该行不存在,您也可以随时添加它。

别忘了重启 php-fpm。


如果没有任何效果,您始终可以在调用npm 时明确设置路径:

exec('PATH=$PATH:/usr/local/bin/node npm');

但这是最后的手段,我不会推荐它。

【讨论】:

  • 是的,这似乎成功了!我对 FPM 还是很陌生,没有意识到你可以像这样在配置中设置环境变量。
猜你喜欢
  • 2014-09-03
  • 2021-10-04
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 2018-06-26
  • 2017-12-21
相关资源
最近更新 更多