fastcgi_pass不能写http://前缀,因FastCGI非HTTP协议,仅支持IP:端口或unix:/path.sock两种格式;否则报invalid URL prefix错误。

为什么 fastcgi_pass 不能写成 http://127.0.0.1:9000
因为 FastCGI 不是 HTTP 协议,fastcgi_pass 后面填的是 FastCGI 进程的监听地址,不是 Web 服务地址。写成 http:// 前缀会导致 Nginx 报错:invalid URL prefix in "http://127.0.0.1:9000"。
实际可用形式只有两种:
-
fastcgi_pass 127.0.0.1:9000(TCP socket,需 PHP-FPM 配置listen = 127.0.0.1:9000) -
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock(Unix socket,更推荐,减少网络栈开销)
注意路径必须与 PHP-FPM 的 listen 配置完全一致,包括权限和 SELinux 上下文(如在 CentOS/RHEL 上)。
fastcgi_param SCRIPT_FILENAME 必须显式设置
Nginx 不会自动推导 PHP 文件的绝对路径,漏掉这行会导致 502 或“Primary script unknown”错误。它必须指向磁盘上真实的 .php 文件路径,且不能依赖 $document_root 自动拼接——因为 $document_root 是 location 匹配后的根目录,而 PHP-FPM 进程本身不感知 Nginx 的 root 设置。
立即学习“PHP免费学习笔记(深入)”;
典型写法(放在 location ~ \.php$ 块内):
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
而不是:
# 错误:$document_root 可能被 alias 覆盖,或未定义 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; <h1>更错:硬编码路径,无法复用</h1><p>fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
使用 $realpath_root 是为了兼容 alias 和符号链接场景,它会在运行时解析为真实物理路径。
PHP-FPM 的 security.limit_extensions 会拦截非标准后缀
即使 Nginx 正确转发了 .php 请求,PHP-FPM 默认只允许执行 .php、.php5 等少数后缀。如果项目用了 .php7 或自定义后缀(如 Laravel 的 index.php7),会直接返回 403 或空白响应,Nginx 日志里却只显示 “upstream sent no valid HTTP/1.0 header”,非常误导。
解决方法是在 PHP-FPM pool 配置中(如 /etc/php/8.1/fpm/pool.d/www.conf)调整:
security.limit_extensions = .php .php7 .phtml
改完必须重启 php8.1-fpm(不是 reload),否则不生效。顺带检查 catch_workers_output = yes,方便从 FPM 日志里看到拒绝原因。
转发到子目录时 fastcgi_split_path_info 容易配错
当 PHP 应用部署在子目录(如 /app/)且需要支持 PATH_INFO(例如 /app/index.php/foo/bar),仅靠 fastcgi_index index.php 不够,必须拆分路径。
常见错误写法:
# 错误:正则没捕获 group,或顺序颠倒
location ~ ^/app/(.+\.php)$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
...
}
正确做法是确保 fastcgi_split_path_info 在 fastcgi_param 之前,并用 $fastcgi_path_info 传递给 PHP:
location ~ ^/app/(.+\.php) {
alias /var/www/app/;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $request_filename;
...
}
注意:这里用 $request_filename 是因为 alias 下 $fastcgi_script_name 不可靠;同时要确认 alias 结尾无斜杠,否则路径拼接会多出 //。
Nginx 的 FastCGI 转发看着简单,但每个参数都强依赖 PHP-FPM 的对应配置,且错误往往静默失败——比如 SCRIPT_FILENAME 写错,Nginx 返回 502,而 PHP-FPM 根本没收到请求;又比如 Unix socket 权限不对,连 connect 都失败,但日志里只写“Connection refused”。调的时候得两边日志对照着看:nginx error.log + php-fpm.log + strace -p $(pgrep php-fpm)。



















