ThinkPHP5 不支持「单入口 + 多域名自动绑定模块」的开箱即用方案,必须靠 define('BIND_MODULE', 'xxx') 显式绑定 + Web 服务器路由分离来实现前台/后台域名区分,否则所有域名都会走默认模块(通常是 index)。

直接说结论:ThinkPHP5 不支持「单入口 + 多域名自动绑定模块」的开箱即用方案,必须靠 define('BIND_MODULE', 'xxx') 显式绑定 + Web 服务器路由分离来实现前台/后台域名区分,否则所有域名都会走默认模块(通常是 index)。
为什么不能只靠 route.php 配置多域名路由?
TP5 的路由系统在解析 URL 前,先由入口文件决定当前应用绑定哪个模块。而 route.php 是模块级配置,它只对已确定模块生效。如果你没在入口文件里提前锁定模块,哪怕你在 route.php 里写了 Route::domain('admin.example.com', ['admin' => 'admin']);,请求进来时框架仍会按默认逻辑加载 index 模块,导致路由规则压根不加载。
- 现象:访问
admin.example.com/index/index仍进前台,不是后台 - 根本原因:
public/index.php没做模块绑定,app/下的route.php属于模块内部配置,无法跨模块生效 - 兼容性注意:TP5.0.x 和 5.1.x 均无内置多应用模式,
APP_MULTI_MODULE是 TP6 才引入的常量,TP5 中定义无效
正确做法:两个独立入口文件 + 域名指向不同入口
这是 TP5 最稳定、最可控的方式。你需要两个物理入口文件,分别绑定模块,并让 Web 服务器根据 Host 头把请求分发过去。
- 保留
public/index.php,顶部添加:define('BIND_MODULE', 'index'); - 复制一份为
public/admin.php,顶部添加:define('BIND_MODULE', 'admin'); - Nginx 配置示例(关键在
fastcgi_param SCRIPT_FILENAME):
server {
listen 80;
server_name www.example.com;
root /path/to/public;
index index.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
}
server {
listen 80;
server_name admin.example.com;
root /path/to/public;
index admin.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root/admin.php;
include fastcgi_params;
}
}
- Apache 同理:用
<VirtualHost>分别指定DocumentRoot并设置DirectoryIndex admin.php - 注意:
admin.php中必须调用\think\App::route(false)关闭后台路由(避免和前台路由冲突),且不能启用 URL 重写隐藏该文件——否则域名区分就失效了
隐藏前台入口但保留后台入口的关键细节
你希望 www.example.com/user/login 访问前台(无 index.php),而 admin.example.com/admin/user/edit 必须带 admin.php ——这其实依赖两层控制:Web 服务器重写 + 入口文件逻辑。
立即学习“PHP免费学习笔记(深入)”;
- 前台 Nginx 重写规则(放在
www.example.com的 server 块内):
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
}
- 后台 Nginx 不做重写,且确保
admin.example.com的请求全部落到admin.php上(见上一节配置) - 容易踩的坑:
admin.php中若漏掉\think\App::route(false),会导致后台也尝试匹配前台的路由规则,出现 404 或跳转错乱 - 另一个坑:TP5 默认开启
url_html_suffix,如果前台配置了伪静态但后台没关,可能造成后台 URL 被追加 .html 后缀而 404
真正难的不是写几行配置,而是理解 TP5 的模块加载顺序:入口文件 → 模块绑定 → 路由加载 → 控制器执行。任何想绕过入口绑定、纯靠路由或中间件切换模块的做法,在 TP5 里都会在第一步就失败。



















