ThinkPHP 8.0 Apache 多站点伪静态关键在于每个站点使用独立 VirtualHost,DocumentRoot 必须指向对应 public/ 目录,启用 mod_rewrite 与 FileInfo Options,并在各 public/ 下配置含 PT 标志的 .htaccess;同时需在 domain_bind 中显式绑定域名与应用名,确保 ParseUrl 中间件启用。

ThinkPHP 8.0 在 Apache 下实现多站点伪静态,关键不是“多个 .htaccess 文件”,而是每个站点独立部署、各自入口隔离,并确保服务器转发路径与框架多应用上下文严格对齐。常见问题如 /admin/login 404、白屏、跳默认应用,90% 源于 root 路径错、domain_bind 不匹配或重写未兜住 public 入口。
Apache 多站点伪静态核心前提
每个 ThinkPHP 8.0 站点必须是独立虚拟主机(VirtualHost),不能共用同一 DocumentRoot;所有站点均以 public/ 为 Web 可访问根目录,而非项目根目录。否则 vendor/autoload.php 加载失败,页面直接空白。
- 每个站点的
DocumentRoot必须指向对应应用的public/目录(例如/var/www/app/admin/public) - 启用
mod_rewrite模块:执行a2enmod rewrite并重启 Apache - 对应 VirtualHost 配置中,
AllowOverride必须设为FileInfo Options(不能是All或None) - 确保
FollowSymLinks已启用(.htaccess 中需用到)
每个站点 public/ 目录下的 .htaccess 规则
规则必须放在各站点的 public/ 目录下(不是项目根目录),内容如下:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
# 禁止访问敏感文件
RewriteRule ^\.env$ - [F,L]
RewriteRule ^\.git/ - [F,L]
# 仅对非真实文件/目录的请求重写
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# 传递完整 PATH_INFO,PT 不可省略
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>注意:index.php/ 中的斜杠分隔符,是 TP8 默认 pathinfo 模式所需;若站点部署在子目录(如 http://example.com/shop/),需额外添加 RewriteBase /shop/。
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
立即学习“PHP免费学习笔记(深入)”;
ThinkPHP 8.0 多应用绑定必须显式配置
伪静态生效的前提是框架能正确识别当前请求属于哪个应用。TP8 不再依赖目录自动推断,必须通过 config/app.php 的 domain_bind 显式绑定:
- 若站点域名为
admin.example.com,则写:'admin.example.com' => 'admin' - 若为
www.example.com/admin这类路径前缀,需配合路由分组或自定义中间件解析,不推荐——易与伪静态冲突 - 本地开发用
localhost:8000,domain_bind 中必须写全'localhost:8000' => 'admin',少端口即失效
同时确认 app/middleware.php 中未禁用 think\middleware\ParseUrl,该中间件负责从 PATH_INFO 提取路由参数。
验证与排错要点
配置完成后,按顺序检查以下四点,基本覆盖 95% 的失败场景:
- 访问
http://admin.example.com/index.php?s=/admin/index/index能正常响应 → 说明 PHP 和框架基础运行正常 - 访问
http://admin.example.com/admin/index/index返回 404 → 检查 .htaccess 是否在 public/ 下、AllowOverride 是否生效、mod_rewrite 是否启用 - 返回空白页且无错误 → 查看 Apache 错误日志,大概率是
DocumentRoot指向了项目根目录而非 public/,导致 autoload 失败 - 请求被路由到默认应用(如显示首页)→ 检查
domain_bind域名是否完全一致(含 www、端口、大小写)、是否漏掉ParseUrl中间件


















