ThinkPHP5在Nginx跑不起来主因是root未指向public目录、try_files配置错误或SCRIPT_FILENAME路径不存在;root必须设为/public绝对路径,location /中配try_files $uri $uri/ /index.php?$query_string,且SCRIPT_FILENAME需拼出真实PHP文件路径。

ThinkPHP5 在 Nginx 上跑不起来,90% 是因为 root 指向错、try_files 写错、或 SCRIPT_FILENAME 拼出来根本不存在。
root 必须指向 public 目录,不是项目根目录
ThinkPHP5 的入口强制在 public/index.php,Nginx 的 root 必须直接落到这个目录,否则所有请求都 404。常见错误是把 root 设成 /var/www/myapp,结果 /index.php 对应的物理路径变成 /var/www/myapp/index.php——但这个文件根本不在那里。
- ✅ 正确写法:
root /var/www/myapp/public; - ❌ 错误写法:
root /var/www/myapp;(除非你额外用alias或rewrite补救) - 如果项目结构是
/data/www/myapp/,那public就是/data/www/myapp/public/,root就得精确写到这一层
try_files 规则不能丢,也不能塞进 PHP location 里
try_files 是路由兜底的核心,必须放在 location / 块里,且末尾要指向 /index.php?$query_string(TP5/6/8 默认用 querystring 模式)。写在 location ~ \.php$ 里毫无意义,Nginx 根本不会执行它。
- ✅ 推荐写法:
location / { try_files $uri $uri/ /index.php?$query_string; } - ❌ 危险写法:
if (!-e $request_filename) { rewrite ^/(.*)$ /index.php/$1 last; }——if在location中是 Nginx 反模式,易导致重写循环或静默失败 - 如果你用的是 PATH_INFO 模式(如旧版兼容需求),才需要加
fastcgi_split_path_info和PATH_INFO参数,否则别碰
SCRIPT_FILENAME 必须拼出真实绝对路径
PHP 能否真正执行,全看 fastcgi_param SCRIPT_FILENAME 的值是否指向一个真实存在的 .php 文件。常见错误是依赖 $document_root$fastcgi_script_name,但没确认 $document_root 是否已正确定义,或漏了 root 配置。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 更健壮写法:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;(自动解析软链接) - ✅ 基础写法:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;,前提是root已在同级或上级location中定义 - 务必检查
fastcgi_pass是否匹配 php-fpm 实际监听方式:unix:/run/php/php8.1-fpm.sock(注意unix:前缀)或127.0.0.1:9000(别写localhost) - 漏掉
fastcgi_param QUERY_STRING $query_string;会导致$_GET为空
open_basedir 权限常被忽略,导致 500 错误
PHP 启动后会检查 open_basedir,限制脚本能访问的目录范围。ThinkPHP5 的核心代码(thinkphp/)、扩展(vendor/)都在 public 上级目录,如果 open_basedir 只设成 /var/www/myapp/public,框架一加载就会报 500。
- ✅ 正确设置(在
php.ini、.user.ini或 Nginx 的fastcgi_param中):open_basedir = /var/www/myapp:/tmp/:/proc/ - ⚠️ 注意:路径末尾不要加斜杠;多个路径用冒号分隔(Linux)或分号(Windows)
- 调试时可在
public/index.php开头加var_dump(ini_get('open_basedir'));确认实际生效值
最常卡住的地方不是配置多复杂,而是 root 和 open_basedir 这两个路径没对齐——一个指到 public,另一个却只放开 public 自身,框架连 autoload 都触发不了。



















