这是一个非常实用的功能,常用于多城市站、多分站、多用户空间等场景,用户注册后,系统会自动为其创建一个专属的二级域名,如 username.yourdomain.com。

实现这个功能主要涉及以下几个步骤:
- 服务器环境准备:这是最关键的一步,需要服务器支持。
- 域名解析配置:确保顶级域名能正确解析。
- 服务器虚拟主机配置:让所有二级域名指向同一个网站目录。
- 织梦程序修改:编写代码自动创建子目录和绑定域名。
- 用户交互流程:在前台提供用户注册和访问入口。
第一步:服务器环境准备
要实现自动分配二级域名,你的服务器必须满足以下条件:
-
拥有独立服务器或VPS:虚拟主机(共享主机)通常无法完成这个操作,因为它没有修改服务器核心配置的权限。
-
Web服务器支持:主流的 Nginx 或 Apache 都可以,这里我们以更高效、更常用的 Nginx 为例进行讲解。
(图片来源网络,侵删) -
绑定通配符域名:这是最核心的一步,你需要联系你的域名注册商,为你的顶级域名(
yourdomain.com)添加一个 的A记录,指向你的服务器IP地址。- 示例:
- 记录类型:
A - 主机记录: (注意是星号,不是www)
- 记录值:
你的服务器IP地址 - 这样,所有未明确指定的二级域名(如
abc.yourdomain.com,xyz.yourdomain.com)都会被解析到你的服务器上。
- 记录类型:
- 示例:
-
安装必要的工具:
- Nginx/Apache:Web服务器。
- PHP:织梦是PHP程序。
- MySQL:数据库。
bind9(DNS服务软件):如果你的服务器需要自己管理DNS(更高级的做法),需要安装它,但对于大多数情况,使用域名注册商提供的DNS解析功能就足够了。
第二步:域名解析配置
如上所述,在你的域名管理后台(如阿里云、腾讯云、Cloudflare等)添加 *.yourdomain.com 的 A 记录,指向你的服务器IP。
重要提示:DNS解析生效需要一些时间(几分钟到几小时不等),你可以使用 ping 命令来测试,ping test.yourdomain.com,看是否能解析到你的服务器IP。

第三步:服务器虚拟主机配置
我们需要配置Web服务器,让所有指向 *.yourdomain.com 的请求,都由织梦程序来处理。
以 Nginx 为例
打开你的Nginx配置文件(通常在 /etc/nginx/sites-available/ 或 /usr/local/nginx/conf/ 目录下),找到你的站点配置文件(如 yourdomain.com.conf),修改 server 块如下:
# 你的主域名配置 (www.yourdomain.com 和 yourdomain.com)
server {
listen 80;
server_name www.yourdomain.com yourdomain.com;
# ... 其他配置,如根目录、日志等 ...
root /www/web/yourdomain.com; # 织梦网站的根目录
index index.php index.html;
# ... 其他规则 ...
}
# 通配符二级域名配置 (这是关键部分)
server {
listen 80;
# 这行会匹配所有以 .yourdomain.com 结尾的域名
server_name ~^(?<subdomain>.+)\.yourdomain\.com$;
# 将所有请求转发到织梦的根目录
root /www/web/yourdomain.com;
index index.php index.html;
# 织梦的伪静态规则
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 将所有PHP请求交给PHP-FPM处理
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # 或 unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# ... 其他规则 ...
}
配置解释:
server_name ~^(?<subdomain>.+)\.yourdomain\.com$;:这是一个正则表达式匹配。- 表示启用正则匹配。
^(?<subdomain>.+)\.yourdomain\.com$匹配形如anything.yourdomain.com的域名。(?<subdomain>.+)是一个命名捕获组,它会将anything这个部分捕获并存储在名为subdomain的变量中,这个变量我们将在PHP代码中使用。
root /www/web/yourdomain.com;:所有二级域名都指向同一个网站根目录。try_files ...:标准的织梦伪静态规则,确保URL能被正确解析。
修改完配置后,记得重启Nginx使配置生效:
sudo nginx -t && sudo systemctl restart nginx
第四步:织梦程序修改
我们需要修改织梦的核心文件,在用户注册时自动创建对应的目录(虽然我们上面配置了所有二级域名都指向同一个目录,但为了SEO和逻辑清晰,我们通常会为每个用户创建一个独立的子目录,并将织梦的 data 和 templets 等关键目录进行隔离)。
这里我们采用一种更优化的方案:不创建物理子目录,而是通过PHP代码动态判断并加载不同用户的数据。 这避免了大量文件IO,性能更好。
-
找到用户注册文件: 通常位于
/member/reg_new.php。 -
修改注册成功后的逻辑: 在用户数据成功插入数据库后,我们需要做一些额外操作,找到类似
ShowMsg("注册成功", ...)的代码段,在此之前添加我们的逻辑。 -
编写自动绑定代码: 在
reg_new.php中,找到用户注册成功的位置,加入以下PHP代码:// 假设用户名已经存放在 $username 变量中 // 在织梦的 reg_new.php 中,新注册的用户名通常在 $_POST['userid'] 中 $username = trim($_POST['userid']); // 1. 生成二级域名 $subdomain = $username . '.yourdomain.com'; // 2. (可选)在数据库中记录用户的二级域名 // 这样你可以在后台或其他地方查询到用户的专属域名 // 假设你的会员表是 `dede_member`,并且你添加一个 `subdomain` 字段 $uid = $GLOBALS['dsql']->GetLastID(); // 获取刚刚插入的用户ID $query = "UPDATE `dede_member` SET `subdomain` = '{$subdomain}' WHERE `mid` = {$uid}"; $GLOBALS['dsql']->ExecuteNoneQuery($query); // 3. 动态绑定域名(核心步骤) // 这个函数需要我们自己来实现 function bindSubdomain($subdomain) { // 这里我们不需要真的创建Nginx配置文件,因为我们的Nginx已经用通配符处理了 // 我们只需要在PHP中动态设置当前请求的域名,并加载对应的数据即可 // 这个逻辑将在一个公共文件中实现,比如一个初始化文件 $_SESSION['current_subdomain'] = $subdomain; } bindSubdomain($subdomain); // 4. (可选)发送欢迎邮件,告知用户其专属域名 // ... -
创建动态加载机制: 我们需要一个在每次请求时都能运行的文件,根据当前访问的二级域名来加载不同的数据,最好的位置是织梦的入口文件
index.php。修改
/index.php文件,在最开始加入以下代码:// index.php 顶部代码 require_once (dirname(__FILE__) . "/include/common.inc.php"); // 检查是否是二级域名访问 $host = $_SERVER['HTTP_HOST']; $main_domain = 'yourdomain.com'; // 你的主域名 if (strpos($host, $main_domain) !== false && $host != $main_domain && $host != 'www.' . $main_domain) { // 提取子域名部分 $subdomain = str_replace('.' . $main_domain, '', $host); // 从数据库中验证这个子域名是否存在(即是否存在对应的用户) $row = $dsql->GetOne("SELECT * FROM `dede_member` WHERE `subdomain` = '{$subdomain}'"); if ($row) { // 用户存在,将当前用户信息存入全局变量,供模板调用 // 你可以根据需要,将 $row 中的信息赋值给全局变量 // 设置一个全局变量 $current_user_info $GLOBALS['current_user_info'] = $row; // 如果你的网站数据是按用户隔离的(比如文章、图集等) // 你需要在这里动态修改数据库查询的表名或增加条件 // 这是一个非常复杂的话题,通常需要改造织梦的数据查询类 // 在查询文章时,自动加上 `arccorpus LIKE 'uid_{$row['mid']}_%'` 这样的条件 // 这里只做概念性演示 // 定义一个函数,用于修改后续的SQL查询 if (!function_exists('filter_sql_by_user')) { function filter_sql_by_user($sql) { global $dsql, $current_user_info; // 这是一个简化的例子,实际中需要更复杂的解析和替换 // 在查询文章表时,自动加上用户ID的条件 if (strpos($sql, 'FROM `#@__archives`') !== false) { $sql .= " AND mid = '{$current_user_info['mid']}'"; } return $sql; } // 挂载到织梦的查询钩子上(如果织梦有此类机制,否则需要直接修改类文件) // 这是一个高级操作,通常需要直接修改 $dsql 对象的行为或其父类 } } else { // 子域名对应的用户不存在,可以显示一个“页面不存在”或“用户未找到”的错误页面 // include(DEDETEMPLATE.'/error.htm'); // exit(); header("HTTP/1.1 404 Not Found"); echo "The user for this subdomain does not exist."; exit(); } } // ... 后续的织梦核心流程 ... require_once(DEDEROOT.'/dedeapi/start.php');
关于数据隔离的说明:
上面的第4步是整个功能中最复杂、最核心的部分,简单地改变 $_SERVER['HTTP_HOST'] 是不够的,真正的挑战在于如何让每个二级域名看到的是自己独立的数据。
- 简单方案:所有用户共享所有数据,只通过二级域名做一个“品牌”或“入口”的区分,这实现简单,但数据不隔离。
- 推荐方案:改造织梦的数据查询逻辑,为每个用户的数据打上“用户ID”的标签,在发布文章时,文章的
mid(会员ID) 字段被记录,当用户通过userA.yourdomain.com访问时,所有查询(文章、图集、软件等)都自动加上WHERE mid = 'userA的ID'的条件,这需要你对织梦的数据库查询流程有很深的理解,通常需要继承和重写dedesql.class.php中的查询方法。
第五步:用户交互流程
-
前台注册页面: 用户访问
www.yourdomain.com/member/reg_new.php,填写注册信息(用户名、密码等)。 -
系统处理:
- 用户点击注册,提交表单。
reg_new.php验证信息,将用户名和密码存入dede_member表。- 触发我们添加的代码,生成二级域名
username.yourdomain.com,并存入数据库。 - 注册成功,提示用户。
-
用户访问:
- 用户注册后,可以直接访问
username.yourdomain.com。 - 服务器Nginx接收到请求,根据通配符规则将其转发到织梦的
index.php。 index.php中的代码解析出username,从数据库中找到该用户,并加载其专属数据。- 网站首页显示该用户相关的信息。
- 用户注册后,可以直接访问
总结与注意事项
- 复杂性:这是一个高级功能,特别是数据隔离部分,需要对织梦底层有较深的了解。
- SEO风险:大量二级域名如果内容高度相似,可能会被搜索引擎判断为“内容农场”,导致降权,务必确保每个二级域名下的内容是独特且有价值的。
- 性能开销:每次请求都需要额外的PHP逻辑来判断用户和过滤数据,对服务器性能有一定要求。
- 安全:务必对用户输入的用户名进行严格过滤,防止恶意用户注册特殊字符(如 , )破坏域名结构或进行注入攻击。
- 替代方案:如果你觉得改造织梦太复杂,可以考虑使用其他更现代的CMS(如WordPress + WP Multi Site插件),或者使用专门的多租户SaaS架构。
希望这份详细的指南能帮助你实现织梦的自动分配二级域名功能!如果遇到具体问题,可以针对某个步骤进行提问。
