错误解决

在 macOS 中配置 nginx+php-fpm 出错,访问 http://localhost/phpinfo.php ,浏览器中的显示是:

File not found.

在 nginx 的 log 中,完整的错误为:

1
2017/08/01 10:39:54 [error] 50087#0: *15 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "GET /phpinfo.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "localhost"

nginx 配置内容(位于 server 段):

1
2
3
4
5
6
7
8
9
10
11
12
location / {
root /srv/www;
index index.html index.htm;
autoindex on;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}

首先要判断是 nginx 的问题,还是 php-fpm 的问题。

/etc/php-fpm.conf 中配置:

1
access.log = /var/log/php-fpm.$pool.access.log

重启 php-fpm,查看 /var/log/php-fpm.www.access.log 的内容:

  • 如果看到类似于 “GET /“ 这样的没有包含具体的 php 文件名的 log,则说明可能是 nginx 路径配置问题;
  • 如果看到类似于 “GET /your_php_file.php” 404 这样的 log,则说明可能是 php-fpm 进程无法读取文件。

无法读取文件的原因有很多,可能是文件路径错误,也可能是权限问题。幸运的是,我碰到的是后者:

1
127.0.0.1 - 01/Aug/2017:10:39:48 +0800 "GET /phpinfo.php" 404

首先排除权限问题,配置 /etc/php-fpm.conf ,将 user 和 group 设置为 macOS 中我的用户。然后重启 php-fpm 服务。

1
2
user = zrong
group = staff

错误依旧。

接着怀疑路径问题。我们需要知道 nginx 传给 php-fpm 的具体文件路径是什么,这需要做一些 log 配置。

把下面的配置写入 nginx 配置文件的 http 段:

1
log_format scripts '$document_root$fastcgi_script_name > $request';

把下面的配置写入 nginx 配置文件的 server 段:

1
access_log /usr/local/var/log/nginx/scripts.log scripts;

重启 nginx 服务,查看 /usr/local/var/log/nginx/scripts.log ,此时真相大白。由于我没有在 location ~ \.php$ 段中配置 root,nginx 默认使用了其安装目录下的 html 作为 root,导致传递的文件路径不正确,php-fpm 无法接收到实际的 php 文件。

我误以为 location / 中配置的 root 会自动向下传递,但我忽略了 location ~ \.php$ 其实与 location / 是平级,没有继承关系。

1
2
/usr/local/Cellar/openresty/1.9.7.4/nginx/html/phpinfo.php > GET /phpinfo.php HTTP/1.1
/usr/local/Cellar/openresty/1.9.7.4/nginx/html/phpinfo.php > GET /phpinfo.php HTTP/1.1

修改 nginx 配置文件,问题解决:

1
2
3
4
5
6
7
location ~ \.php$ {
root /srv/www;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}

此时查看 /usr/local/var/log/nginx/scripts.log ,内容为:

1
2
/srv/www/phpinfo.php > GET /phpinfo.php HTTP/1.1
/srv/www/phpinfo.php > GET /phpinfo.php HTTP/1.1

几个小技巧

php-fpm.plist

在 macOS 下应该创建一个 launch plist 文件,将其放在 /Library/LaunchDaemons/zrong.php-fpm.plist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>zrong.php-fpm</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/php-fpm</string>
<string>--fpm-config</string>
<string>/etc/php-fpm.conf</string>
<string>--nodaemonize</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>UserName</key>
<string>root</string>
<key>WorkingDirectory</key>
<string>/var</string>
<key>StandardErrorPath</key>
<string>/var/log/php-fpm.log</string>
</dict>
</plist>

启动:

1
sudo launchctl load /Library/LaunchDaemons/zrong.php-fpm.plist

停止:

1
sudo launchctl unload /Library/LaunchDaemons/zrong.php-fpm.plist

在 macOS 上重启 php-fpm

需要注意的是,php-fpm 默认是以守护进程的方式启动的。因此需要在命令行参数中传递 --nodaemonize 禁止其以守护进程启动,否则上面使用 launchctl 来停止服务的操作就是无效的。

你还可以在 /etc/php-fpm.conf 中通过设置参数来禁用守护进程(命令行参数的优先级最高):

1
2
3
; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging.
; Default Value: yes
daemonize = no

当然,最简单粗暴的重启办法是这样的,怎么都有效:

1
sudo pkill php-fpm

参考

全文完

留言