ThinkPHP5二级域名绑定需三者协同:开启url_domain_deploy、在route/app.php用Route::domain()注册子域名规则(如'admin'=>'admin')、Nginx正确透传HTTP_HOST并root指向public目录。

ThinkPHP5 在 Nginx 下做域名绑定,核心不是改入口文件或复制项目,而是靠 Route::domain() + 正确的 Nginx 配置 + url_domain_deploy 开关三者协同。漏掉任意一环,子域名就只会 404 或跳回 index 应用。
确认多应用结构和域名部署开关已启用
TP5 的二级域名绑定必须基于多应用模式,不是“一个项目多个入口”那种伪绑定。先检查你的项目是否已真正进入多应用状态:
- 根目录下没有
app/controller目录(存在则框架认为是单应用) - 已执行过类似
php think build admin,生成了app/admin/、app/api/等独立目录 -
config/app.php中明确设置了'url_domain_deploy' => true(注意:不是APP_SUB_DOMAIN_DEPLOY,后者在 TP5.1+ 已废弃)
如果没做完这三步,Route::domain() 注册再正确也无效——框架根本不会解析 Host 头。
在 route/app.php 中注册子域名路由规则
所有子域名映射必须写在 route/app.php(推荐)或 app/common/route.php,且必须在 use think\Route; 后立即调用。示例:
立即学习“PHP免费学习笔记(深入)”;
use think\Route;
Route::domain('admin', 'admin'); // admin.example.com → 加载 app/admin/
Route::domain('api', 'api'); // api.example.com → 加载 app/api/
Route::domain('*', 'index'); // 其他未匹配域名(含 www.example.com)→ app/index/
关键点:
- 左侧是子域名字符串,支持通配符
*,但不支持正则或路径匹配 - 右侧是应用目录名(即
app/下的子目录名),必须完全一致、大小写敏感 - 不要在规则里写控制器或方法,这是应用级绑定,不是 URL 路由
- 若用泛域名
*,务必放在最后,否则会覆盖前面的具体规则
Nginx 配置必须透传 Host 头且 root 指向 public
很多 404 实际是 Nginx 层没把原始 Host 头交给 PHP。检查你的 vhost 配置中这两处:
-
root必须指向项目public/目录,例如root /home/www/example.com/public;;若指向项目根目录,框架无法加载vendor/和thinkphp/ - 必须确保
fastcgi_param HTTP_HOST $http_host;或至少没显式覆盖它(有些模板会写fastcgi_param HTTP_HOST $server_name;,这会导致 Host 固定,子域名识别失效) - 不需要为每个子域名单独写
server块——只要 DNS 解析到同一 IP,一个server块就能承载全部子域名
典型最小可用配置片段:
server {
listen 80;
server_name example.com www.example.com admin.example.com api.example.com;
root /home/www/example.com/public;
index index.php;
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
}
}
location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params; // 这行默认含 HTTP_HOST 传递
}
}
常见失败现象与定位方法
遇到绑定不生效,别急着重写配置,按顺序查这几项:
- 浏览器访问
admin.example.com,用开发者工具看 Network → Headers → Request Headers,确认Host: admin.example.com真实发出 - 在
app/admin/controller/Index.php的 index 方法里临时加dump($_SERVER['HTTP_HOST']); exit;,看输出是不是预期子域名 - 检查
phpinfo()页面中$_SERVER['HTTP_HOST']值,如果不是请求的子域名,说明 Nginx 没透传,重点查fastcgi_params文件或自定义的fastcgi_param行 - 确认
open_basedir没限制到只允许public/目录——它必须包含整个项目根目录,否则跨目录加载失败报 500
最易被忽略的是 open_basedir 和 HTTP_HOST 透传,这两处出问题,框架连域名都收不到,后面所有配置都白搭。



















