游客发表
PHP 和 Nginx 的组合,说白了就是让 Nginx 把 .php 文件的请求转交给 PHP-FPM 处理,处理完再把结果吐回给浏览器。Nginx 自己不执行 PHP,它只负责转发。这个转发靠的是 FastCGI 协议,而 PHP-FPM 就是一个 FastCGI 进程管理器。
我见过不少人卡在这一步:Nginx 装好了,PHP 也装好了,访问 index.php 却直接下载文件或者报 502。问题基本都出在 Nginx 的 server 块里没有正确配置 location ~ \.php$ 这一段。
配置之前,先看看 PHP-FPM 是否活着。执行 ps aux | grep php-fpm,能看到 master 进程和几个 pool 进程就对了。如果没跑,systemctl start php-fpm(CentOS)或 service php7.4-fpm start(Ubuntu)。
PHP-FPM 默认监听两种方式:Unix socket 或 TCP 端口。Ubuntu 下通常是 /run/php/php7.4-fpm.sock,CentOS 下是 127.0.0.1:9000。这个信息在 /etc/php/7.4/fpm/pool.d/www.conf 或 /etc/php-fpm.d/www.conf 里能找到。Nginx 配置里的 fastcgi_pass 必须和这个对得上,写错了就是 502。
打开站点的 server 块,加这么一段:
location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } 逐行说。location ~ \.php$ 是正则匹配,凡是 .php 结尾的请求都进这里。include fastcgi_params 引入 Nginx 自带的一组 FastCGI 环境变量,别自己手写,容易漏。fastcgi_pass 告诉 Nginx 去哪儿找 PHP-FPM。SCRIPT_FILENAME 这行最要命,它告诉 PHP-FPM 到底要执行哪个文件。少了这行,PHP-FPM 不知道执行什么,返回 “File not found”。
有个细节:$document_root 是你的 root 指令值。如果你在 location 里单独设了 root,这里的 $document_root 会跟着变。有人图省事直接写死 fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;,也能跑,但换个目录就忘了改。
之前帮人调一个 WordPress 站点,首页正常,点进文章就 404。Nginx 的 error log 显示 Primary script unknown。查了半天,发现他在 location ~ \.php$ 里写了 root /var/www/html;,但 WordPress 的固定链接依赖 try_files 转发到 index.php。他的 location / 里没有配 try_files $uri $uri/ /index.php?$args;,导致请求直接进了 404。加上就好了。PHP 配置本身没问题,是 Nginx 的 rewrite 逻辑缺了。
默认的 fastcgi_params 文件里,SCRIPT_FILENAME 是没有的,需要自己加。另外建议加一行:
fastcgi_param PATH_INFO $fastcgi_path_info; 有些框架用 PATH_INFO 做路由。不加的话,类似 /index.php/foo/bar 这种 URL 可能解析异常。
还有个常见的安全配置:禁止访问 .php 文件以外的敏感路径。比如 location ~ /\.ht { deny all; },防止 .htaccess 被下载。虽然 Nginx 不认 .htaccess,但文件放在那儿被人拿到源码总不好。
改完配置先 nginx -t 测语法。通过后 nginx -s reload。然后建个 info.php,内容就一行 <?php phpinfo(); ?>,浏览器访问。看到 PHP 信息页就通了。如果报 502,去看 /var/log/nginx/error.log 和 PHP-FPM 的日志,八成是 socket 路径不对或者权限问题——Nginx 的 worker 进程用户(通常是 www-data 或 nginx)得有权访问那个 socket 文件。
权限这块补充一句:Unix socket 的所属组一般是 www-data,权限 660。如果 Nginx 跑在 nginx 用户下,而 socket 属于 www-data 组,就会连不上。要么把 Nginx 用户加进 www-data 组,要么改 socket 的权限。我一般直接让两者用同一个用户,省事。
友情链接