ThinkPHP 6 多应用部署实战:从 500/404/502 到稳定运行的完整排障记录

ThinkPHP 6 多应用部署实战:从 500/404/502 到稳定运行的完整排障记录
本文记录了基于 ThinkPHP 6 多应用架构的 Guojiz V8 导航系统(boke.jiuhui.net)从初始化部署到生产环境稳定运行的完整过程。涵盖目录权限、路由 404、调试模式、php-fpm 守护等 6 个真实生产问题的排查与修复,附排障方法论总结。
01 项目背景
boke.jiuhui.net 使用 Guojiz V8(国际网址导航系统)搭建,基于 ThinkPHP 6 多应用架构。站点运行在宝塔面板管理的 Linux + Nginx + PHP 8.0 + MySQL 环境上。
ThinkPHP 6 的多应用模式(Multi-Application)将不同业务模块拆分到 app/admin/(后台管理)、app/index/(前台展示)、app/bookmark/(书签功能)等独立目录中。这种架构带来了灵活的模块化能力,但也引入了部署时的特殊坑点。
02 问题一:子路由全线 500 — Runtime 目录权限
现象:首页能正常访问,但所有子页面(如 /category/10.html、/website/42.html)全部返回 500 错误。
错误信息:Exception #11602 in File.php line 39: cache write error
根因:ThinkPHP 的模板引擎需要将编译后的模板缓存写入 runtime/ 目录。问题出在两个地方:
runtime/temp/目录的 owner 是root:root,但 php-fpm 以www用户运行,没有写入权限runtime/index/目录根本不存在,ThinkPHP 6 为每个应用模块创建独立的 runtime 子目录
修复:
chown -R www:www /www/wwwroot/boke.jiuhui.net/runtime/
mkdir -p /www/wwwroot/boke.jiuhui.net/runtime/index/
chown www:www /www/wwwroot/boke.jiuhui.net/runtime/index/
经验:部署 ThinkPHP 项目后第一件事就是检查 runtime/ 目录权限。这是 ThinkPHP 部署最常见的问题,没有之一。宝塔面板上传文件后默认 owner 是 root,但 PHP-FPM 运行用户是 www,两者不一致导致所有写入操作失败。
03 问题二:管理后台菜单 404 — URL 格式冲突
现象:登录管理后台后,点击左侧菜单进入文章管理等页面,返回 404。
排查过程:
检查菜单配置文件,发现菜单 URL 是 pathinfo 格式:/index.php/admin/web/article.html。
测试发现:
/index.php/admin/web/article.html→ 404 ❌/admin/web/article.html(走 rewrite) → 200 ✅
进一步分析发现,Nginx 的 enable-php-80.conf 中 PHP location 块使用了 try_files $uri =404。当请求 /index.php/admin/web/article.html 时,Nginx 将其视为文件路径查找,找不到该文件就直接返回 404,压根没有转发给 PHP-FPM 处理 pathinfo。
修复方案:不是修改 Nginx 的 pathinfo 配置,而是修改应用内的 URL 格式。因为 rewrite 规则 rewrite ^(.*)$ /index.php?s=/$1 last; 已经让 /admin/web/article.html 正常工作了,所以只需将所有 /index.php/admin/ 前缀统一改为 /admin/。
# 批量替换所有 PHP 和 HTML 文件中的 /index.php/admin/ 为 /admin/
find /www/wwwroot/boke.jiuhui.net/app/ -type f \( -name "*.php" -o -name "*.html" \) \
-exec sed -i 's|/index\.php/admin/|/admin/|g' {} +
# 清除 runtime 缓存
rm -rf /www/wwwroot/boke.jiuhui.net/runtime/admin/temp/
关键教训:不要在 rewrite 和 pathinfo 两种 URL 格式之间混用。当 rewrite 规则已验证可用时,统一走 rewrite 格式最安全。修改后一定要清 runtime 缓存,否则 ThinkPHP 可能仍使用旧的路由缓存。
04 问题三:生产环境 APP_DEBUG 未关闭
现象:.env 文件中 APP_DEBUG = true,生产环境不应开启调试模式。
修复:删除 .env 中的 APP_DEBUG = true 行。ThinkPHP 6 的默认值为 false,删除即关闭。
警示:调试模式会暴露详细的错误堆栈、文件路径等敏感信息,同时也是性能杀手。上线前务必检查并关闭。
05 问题四:php-fpm 进程不稳定导致 502
现象:php-fpm-80 进程多次自行退出,导致全站 502 Bad Gateway。
修复:添加 crontab 守护进程,每分钟检测 php-fpm 状态,异常时自动重启。
* * * * * /etc/init.d/php-fpm-80 status || /etc/init.d/php-fpm-80 start
经验:宝塔面板管理的 PHP-FPM 偶有不稳定的情况,crontab 守护是最轻量的保障方案。用 || 而非 &&:status 失败时才执行 start,避免重复启动运行中的进程。也可以调整 php-fpm.conf 中的 pm.max_children 等参数,从根本上减少退出的概率。
06 问题五:Nginx 过度屏蔽目录
现象:Nginx 配置中有一行 location ~* /(\.git|\.svn|runtime|install)/ { return 404; },把 install 目录也屏蔽了。
分析:Guojiz V8 的 install 目录本身已有 install.lock 文件防止重复安装,不需要 Nginx 层额外屏蔽。而且一旦屏蔽,后续需要重新安装或升级时将无法正常访问。
修复:从 Nginx 配置中移除 install,只保留 .git、.svn、runtime 等真正敏感的目录。
原则:不要过度屏蔽目录。如果应用自身已有安全机制,Nginx 层再屏蔽反而影响后续维护。安全配置应该是"够用就好",不是"越多越好"。
07 问题六:管理员密码重置
现象:管理员账号 covsun 的密码不明,无法登录管理后台。
修复:直接修改 MySQL 数据库中的密码哈希。
mysql -uboke_jiuhui_net -pBk9x2mZp\!2026 boke_jiuhui_net \
-e "UPDATE my_member_admin SET password='e10adc3949ba59abbe56e057f20f883e' WHERE name='covsun';"
该系统的密码使用 MD5 哈希存储,e10adc3949ba59abbe56e057f20f883e 是 123456 的 MD5 值,修改后即可用此密码登录。
注意:MySQL 密码如果包含 ! 等特殊字符,在 Bash 中需要用 \! 转义,否则 Bash 会将其解释为历史命令扩展。更安全的做法是用 -p 参数后直接跟密码(不加空格和引号),或者使用 --defaults-extra-file 指定密码文件。
08 架构解密:ThinkPHP 6 多应用路由机制
通过这次排障,我们也深入了解了 Guojiz V8 的路由机制:
请求 URL:/admin/web/article.html
↓ Nginx rewrite
/index.php?s=/admin/web/article.html
↓ ThinkPHP 解析
应用(module):admin
控制器(controller):Admin(app/admin/controller/Admin.php)
方法(action):web() —— 动态渲染
参数:html = article
管理后台的所有子页面都通过一个统一的 web() 方法动态加载对应的模板文件:
public function web()
{
$id = 'web_'.input('html').'.html'; // web_article.html
$html = './app/admin/view/'.$id; // ./app/admin/view/web_article.html
if (file_exists($html)) {
return View::fetch($html);
} else {
return '模板文件不存在
'.$html;
}
}
这种设计的好处是菜单扩展非常灵活——新增一个菜单项只需要创建对应的模板文件,然后在菜单配置文件中添加一行 URL 即可。
09 排障方法论总结
经过这 6 个问题的实战,总结出 ThinkPHP 部署排障的四条黄金原则:
🔍 先验证再修改
用 curl 测试不同 URL 格式(pathinfo vs rewrite),确认哪种能工作,再决定修改方向。别凭感觉猜。
🔧 最小改动原则
优先修改应用代码而非 Nginx 配置。Nginx 配置影响全局,应用代码变更范围可控。能用 rewrite 解决的就不要动 pathinfo。
🧹 改完清缓存
修改任何路由、URL、配置相关内容后,必须清除 runtime/ 缓存。ThinkPHP 的模板缓存和路由缓存不会自动刷新。
🛡️ 进程守护是底线
对不稳定的服务进程(如 php-fpm),crontab 守护是最轻量、最有效的保障方案。不要相信进程会一直活着。
部署 ThinkPHP 项目的 checklist:
- ✅
runtime/目录 owner 是否为 www:www - ✅ 所有应用模块的 runtime 子目录是否存在
- ✅
.env中 APP_DEBUG 是否已关闭 - ✅ rewrite 规则是否生效,URL 格式是否统一
- ✅ php-fpm 是否有守护进程
- ✅ Nginx 安全配置是否过度