Ubuntu Linode 上 Nginx 的 PHP 错误(通过 FastCGI)

ele*_*119 3 linux ubuntu php nginx fastcgi

我使用以下指南在 Linode 的 Ubuntu 10.04 服务器上设置了 LEMP(Linux、Nginx、MySQL 和 PHP):http : //library.linode.com/lemp-guides/ubuntu-10.04-lucid

从本质上讲,我上传了我的PHP脚本到一个目录(/srv/www/mysite.com/public_html)中指定/etc/nginx/sites-available/mysite.com.conf

在浏览器中访问该站点给我一个 500 内部服务器错误。我假设 PHP 代码有一些错误,这很好。但是,我完全不知道如何调试它,因为有几个组件:PHP、FastCGI 和 Nginx。

我的问题是,如何让这些错误显示在浏览器中,或者至少显示在日志中,以便我可以弄清楚发生了什么?我不确定是否需要告诉 Nginx 在某处记录错误,或者 FastCGI,或者编辑 php.ini。

我对服务器有完全的 root 访问权限来解决这个问题。但是,我不确定如何重新启动 PHP/FastCGI(虽然我知道如何重新启动 Nginx),因为我遵循的指南使用了某种守护进程。

非常感谢你能给我的任何帮助。

cyb*_*x86 16

简短的回答:

最有可能的情况是您在 Nginx 中存在轻微的配置错误,导致发送到 PHP-FPM 的路径不正确。确保您的 root 指令在 location 块之外,打开fastcgi_intercept_errors,增加您的 error_log 的详细程度(例如通知)并查阅这些日志以获取更多信息。

长答案 - 诊断问题

首先,我不是 Ubuntu 人(更像是 CentOS 人)-因此,如果一些路径/软件包对您的操作系统的特定性不如理想情况,请原谅我。

正如您所说,您的设置中有多个部分必须协同工作。

  • Nginx - 必须能够接收和处理请求 - 最简单的测试是静态文件。
  • FastCGI - 必须能够与 PHP 通信。
  • PHP - 必须能够成功解释您的文件。

对于这种诊断方法,我们希望保持简单——不要通过尝试加载像 Wordpress 这样的 CMS 来测试它——我们想要一个独立的文件。

测试文件:

静态 - 让我们使用名为“test.txt”的文本文件。

测试.txt:

Hello world
Run Code Online (Sandbox Code Playgroud)

PHP - 让我们使用 phpinfo() 函数。

测试.php:

<?php
    phpinfo();
?>
Run Code Online (Sandbox Code Playgroud)

测试 Nginx:

如果 Nginx 可以提供静态文件,我们可以确认基本设置和软件功能正常。

server {
        listen *:80 default;
        server_name mysite.com www.mysite.com;
        root  /srv/www/mysite.com/public_html;
        error_log /var/log/nginx/mysite.com/error.log notice;
        access_log /var/log/nginx/mysite.com/access.log main;
}
Run Code Online (Sandbox Code Playgroud)

提几点:

  • 我已将“默认”添加到监听行 - 这有望确保使用此服务器块(当然,除非您有其他指定“默认”的服务器块,这是一个不同的问题)。
  • 我已将 error_log 的详细程度增加到“通知” - 我想查看可能出现的任何问题
  • 我已经指定了一个 access_log - 我希望能够确认我尝试访问的任何文件都出现在 access_log 或 error_log 中 - 没有任何下落不明。

将'test.txt'复制到'/srv/www/mysite.com/public_html',确保它可以被用户'nginx'(nginx运行的默认用户)读取,644的权限就足够了。确保public_html 之上的所有目录对'other' 具有'execute' 权限(即'other' 可以遍历目录结构)。

重新启动 Nginx 以使配置更改生效(如果需要,您可以重新加载而不是重新启动)。

从安装了 nginx 的同一台服务器上进行测试:

curl --header "Host: mysite.com" 127.0.0.1/test.txt
Run Code Online (Sandbox Code Playgroud)

这里值得注意的点:

  • 通过在设置 nginx 的同一服务器上进行测试,我们能够消除 DNS 和网络问题。
  • 127.0.0.1 当然是 'localhost'(但 'localhost' 确实需要在 hosts 文件中指定一个规范才能工作)
  • 由于我们通过 IP 地址访问站点,我们应该告诉服务器我们尝试访问的“域名”(此处不严格要求,因为我们将服务器块设置为“默认”,但很好的做法)。
  • 最后,我们需要指定文件的路径——相对于我们的根指令(来自我们的服务器块)。

理想情况下,上述命令将返回“Hello world”——您在文本文件中输入的文本。

PHP:

确保 PHP 正常工作是相当容易的:

在您的 public_html 文件夹中创建文件“test.php”(如上)并运行:

php /srv/www/mysite.com/public_html/test.php
Run Code Online (Sandbox Code Playgroud)

您应该得到一个很长的输出,其中包含您通常在 phpInfo() 页面上看到的所有信息。

如果上述方法不起作用:

  • 如果您遇到某种文件未找到错误,请指定 php 的绝对路径,并检查您的文件的路径
  • 如果您收到权限错误,请确保您的当前用户具有所需的权限 - 以这种方式访问​​时,php 实际上并不需要对文件的执行权限。
  • display_errors在 php.ini 文件中打开并增加 error_reporting 的详细程度(首先,使用 找到正确的 php.ini 文件php -i | grep 'Loaded Configuration'

希望现在您已经确认 PHP 和您的简单测试文件可以正常工作。

PHP-FPM:

不幸的是,FastCGI 不会“说”纯文本。我们需要一名口译员来帮助我们。你需要cgi-fcgi二进制文件。(在 CentOS 上,它可以在来自 EPEL 的“fcgi”包中找到;我相信 Ubuntu 有一个libfcgi提供相同功能的包)。

cgi-fcgi 读取环境变量并将正确的请求传递给我们的 FastCGI 进程管理器 (PHP-FPM)。

首先,让我们设置 PHP-FPM:默认的全局选项应该足够了,但是,启用日志记录 - 在调试时,我们需要尽可能多的信息(默认日志前缀是 /var)。

error_log = log/php-fpm.log
log_level = notice
Run Code Online (Sandbox Code Playgroud)

设置一个基本池,指定:

[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1

pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 2

user = nginx
group = nginx
Run Code Online (Sandbox Code Playgroud)

(当然,您可以 - 并且可能应该使用套接字而不是 TCP 侦听器,但我发现这种方法更易于测试(即权限问题更少) - 显然,确保在您选择的端口上没有其他任何内容侦听)。我们只需要允许本地机器访问它,设置进程管理器的基础,并给池一个所有者(当然,您稍后将更改内容以满足您的需要)。

  • 启动 PHP-FPM(解决启动时遇到的任何错误)
    • FPM 是 PHP 的 FastCGI 进程管理器,它是一个独立的运行服务 - 通常service php-fpm restart可以工作(reload如果您需要在生产环境中执行此操作,请改用)。(在 /etc/init.d 中可能有一个 init 脚本)
  • 如果您还没有安装 cgi-fcgi

运行以下命令:

SCRIPT_NAME=/test.php \
SCRIPT_FILENAME=/srv/www/mysite.com/public_html/test.php \
QUERY_STRING= \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 127.0.0.1:9000
Run Code Online (Sandbox Code Playgroud)

这里我们告诉 PHP-FPM 文件的路径、文件名以及请求类型 (GET),然后指示 cgi-fcgi 连接到正确的主机和端口。

它应该返回与之前相同的输出,但是这一次,它使用了 FastCGI,而不是直接使用 php 二进制文件。如果这有效,则您已成功验证设置的每个组件。

如果出现错误,请检查 /var/log/php-fpm.log 中的错误日志

将它们放在一起: 如果设置的每个部分都有效,那么您需要确保所有部分都可以协同工作。真的,这里只剩下一个部分了——让 Nginx 通过 FastCGI 进行通信。

以最简单的形式,我们只需要向现有的 nginx 服务器块添加一个位置块:

    location ~ \.php {
        include /etc/nginx/fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
    }
Run Code Online (Sandbox Code Playgroud)

为了支持这一点,文件“fastcgi_params”非常重要。真正重要的几行是:

    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
Run Code Online (Sandbox Code Playgroud)

您实际上可以将所需的 FastCGI 指令直接包含在 location 块中 - 但我发现当您获得更复杂的设置时,拥有外部文件更容易维护。您会在此处注意到,路径取决于 $document_root - 如果您没有正确设置(根指令),在您的位置块之外,您通常会遇到设置问题。

某些设置可能还需要一行,例如:

 fastcgi_split_path_info ^(.+\.php)(/.+)$;
Run Code Online (Sandbox Code Playgroud)

调试 FastCGI 设置错误的一个有用指令是fastcgi_intercept_errors On. 这将使 nginx 记录错误(例如找不到文件等)。

最后,尝试通过 nginx 加载您的 PHP 页面:

curl --header "Host: mysite.com" 127.0.0.1/test.php
Run Code Online (Sandbox Code Playgroud)

希望你得到你的 phpinfo() 输出。如果不是,您就知道问题出在您的 nginx 设置中(因为每个其他组件都可以自行运行)开始检查您的 nginx 错误日志,此时您应该记录了足够多的信息来识别问题。