拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

二级域名分发系统源码部署指南:自助申请、自动解析与到期回收全流程

二级域名分发系统源码部署指南:自助申请、自动解析与到期回收全流程

简介:这是一套面向企业建站、IDC服务商及个人开发者的2025二级域名分发系统商业版源码,解决大量子域名快速创建、解析、续费与租赁管理问题。包体共2000个文件,约51.17MB,以1219个PHP业务文件、259个JSON配置与接口数据、190个Markdown说明文档、124个PNG界面素材为主,并含JS/CSS、SQL、环境配置等,方便前后台部署和二次开发。前台提供用户注册、域名申请/续费、解析设置;后台支持管理员配置域名模板、用户权限与系统监控,源码内含教程及演示站点,可快速跑通完整分发流程。已有539人学习下载,适合需要搭建域名租赁平台或完善二级域名管理体系的开发者参考。

1. 2025二级域名分发系统:一套源码把域名出租、解析、到期收回来

做域名分发、子域名业务的人都会遇到同一个尴尬:手里攥着主域名,用户却要一个个手工开。客户要个二级域名,你得登录DNS后台加记录、等生效、手记到期时间,客户一多,这套手工流程就是灾难。这套2025商业版二级域名分发系统源码,解决的就是这个闭环——用户在前台自助申请二级域名,系统自动调用解析API写入DNS记录,到期自动回收释放,管理员只需在后台添加主域名、配置解析凭证、设好套餐价格。它适合做域名租赁、建站服务分发、个人子域名自助平台的开发者,也适合想快速搭建一个可运营的域名分发网站的站长。下面这套部署和改造过程,是我按商业版常见结构拆出来的完整落地路径。

2. 核心业务流程与数据模型:域名申请、解析绑定、续费到期的完整闭环

2.1 角色拆解:管理员、用户、主域名三级结构

这套系统里,用户和域名的关系是「多对多」的:一个用户可以在多个主域名下申请子域名,一个主域名下也可以挂多个用户的不同子域名。数据模型不能简单地在用户表里加一个domain字段,而要把主域名、子域名、用户三者分开建模。

管理员侧的动作是:添加主域名(比如 example.com)、配置该域名在DNS服务商处的API凭证、设置允许申请的前缀规则和套餐价格。用户侧的动作是:注册登录、选择一个主域名、申请一个未被占用的子域名、系统自动写DNS记录并返回解析目标。

我一般建议把「主域名」看成一个独立的资源池,而不是一条配置项。这样后续做多域名聚合、按主域名统计收益、按主域名单独设置解析策略时,SQL都不用大改。这套源码的商业版正是按这个思路铺的数据表结构,后面二开加功能时能省很多事。

2.2 核心数据表:域名表、解析记录表、订单与到期表

真正决定业务能不能跑通的表是下面这几张,我把关键字段和用途列出来:

表名关键字段用途
domain_mainid, name, api_type, app_id, app_secret, status主域名资源池,存DNS服务商类型与API凭证
domain_recordid, user_id, main_id, sub_prefix, record_type, record_value, ttl, status每条已分发的二级域名记录,sub_prefix就是用户申请的标识
user_accountid, username, password_hash, level用户表,level决定可用套餐
order_infoid, user_id, record_id, plan_id, pay_status, expire_time购买与续费记录,到期时间在这里

这里最容易设计反的是domain_record表。很多新手会把sub_prefix直接当成主键,但实际业务里同一个子域名可能被删除后再次申请,而且需要保留历史记录,所以用自增id做主键,sub_prefix加唯一索引即可。record_type字段建议直接存字符串类型,记录类型是A还是CNAME,后续调API时不用再做映射转换,也方便前台展示时直接显示。

订单与到期表要特别注意expire_time这个字段。建议用int存时间戳,而不是用datetime。原因是后续算到期、写cron定时任务、做续费计算时,时间戳直接加减比较省事,也避免时区问题导致到期时间错乱。这套源码在MySQL里统一用时间戳存储,排错时会省不少事。

2.3 自动解析逻辑:新增记录、删除记录、状态同步三段式

系统最核心的代码是解析控制层。它对外暴露的动作只有三个:创建解析、删除解析、查询解析状态。无论底层接的是DNSPod还是其他服务商API,上层业务都只调用这三个接口。

创建解析的顺序很关键——必须先查库判断占用,再调API创建,API返回成功后再落库。这个顺序不能反,否则会出现库里没有占用、DNS侧却已经有了的脏数据。

def create_subdomain_instance(user_id, main_domain, sub_prefix, target): # 1. 先查主域名是否存在且可用 main = db.query("domain_main", {"name": main_domain, "status": 1}) if not main: return {"code": 1, "msg": "主域名未上架或已停用"} # 2. 再查子域名是否已被占用(库内唯一索引兜底) exists = db.query("domain_record", {"main_id": main["id"], "sub_prefix": sub_prefix}) if exists: return {"code": 2, "msg": "该二级域名已被占用"} # 3. 调DNS服务商API创建记录,成功后返回记录id dns_record_id = dns_api.create_record( main["app_id"], main["app_secret"], domain=main_domain, sub_domain=sub_prefix, record_type="A", record_value=target, ttl=600 ) # 4. API成功才落库,保证两边一致 db.insert("domain_record", { "user_id": user_id, "main_id": main["id"], "sub_prefix": sub_prefix, "dns_record_id": dns_record_id, "status": 1, "create_time": now() }) return {"code": 0, "msg": "success"}

这里dns_api.create_record的参数顺序和返回值格式,要跟你实际接的API对齐。许多商业版默认对接的是腾讯云DNSPod,参数是domain、subDomain、recordType、recordValue、ttl,返回值里带recordId。如果接阿里云,参数名会变成RR、Type、Value,需要做一层适配层,不要在业务代码里散落调用。

删除解析的时机有两个:用户主动释放、后台到期回收。无论是哪种,都必须先调API删除DNS记录,再更新库里的status字段为0。如果只删库不删DNS,解析还会继续生效,到期回收就等于白做。查询状态一般用于后台的「解析体检」功能,比对库内记录和DNS侧记录,找出不同步的记录并修正。

3. 部署上线实操:环境要求、安装步骤与多域名接入配置

3.1 环境检查:PHP、MySQL 与伪静态规则

这套源码是PHP+MySQL架构,商业版常见要求是PHP 7.2以上、MySQL 5.6以上、Nginx或Apache均可。部署前先确认三件事:PHP是否启用了pdo_mysql扩展、MySQL是否允许连接、伪静态规则是否已写入站点配置。前两个用phpinfo就能查,伪静态则要看服务器软件类型。

我在Nginx下部署时的站点配置如下,重点是location的rewrite规则。如果用的是Apache,把规则转到.htaccess就行,但AllowOverride必须设为All,否则规则不会生效。

server { listen 80; server_name sub.example.com; root /var/www/subapp; index index.php; location / { # 非真实文件或目录时重写到入口文件 if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?/$1 last; } } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 7d; } }

这套配置里有两个容易翻车的点。第一,if (!-e $request_filename) 只能放在location /里,放到server级别会导致静态资源也被重写。第二,fastcgi_pass的地址要跟实际安装的PHP-FPM监听地址一致,配置8000还是9000取决于php-fpm.conf里的listen项,我遇到过因为这里不一致导致所有PHP页面全部502的情况。

站点根目录的runtime目录必须保证可写。多数商业版源码把缓存、日志、上传文件都放在runtime子目录里,权限不到位时表现很迷惑:前台能打开,后台登录却报500,或者提交申请时提示路径错误。我一般直接chown给www用户再chmod 755,比无脑777靠谱一点。

# 项目根目录执行,把运行权限交给nginx用户 chown -R www:www /var/www/subapp chmod -R 755 /var/www/subapp/runtime chmod -R 755 /var/www/subapp/upload

3.2 安装向导:数据库初始化与后台入口验证

把源码上传到站点根目录后,访问域名会进入安装向导。安装向导做的事基本是固定的:检查环境、填写数据库地址和账号、设置管理员密码、写入install.lock文件。数据库导入一般有两种方式,一是向导里自动执行SQL文件,二是手动导入源码包内的sql文件,老版本里更常见的是手动方式。

手动方式下,先建库再导入:

# 创建数据库,字符集用utf8mb4,避免特殊字符乱码 CREATE DATABASE IF NOT EXISTS subapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 命令行导入源码包内的数据库文件 mysql -u root -p subapp < /var/www/subapp/database/install.sql

install.sql里通常包含表结构和一份默认数据,默认数据里会有一个主域名示例和管理员账号,装完后记得在后台改掉默认密码。安装完成后,向导会自动生成install.lock,之后想重新安装必须手动删除这个文件,但要注意这会清空已配置的数据,除非你有数据库备份,否则别轻易操作。

后台入口路径在安装说明里一般有标注,常见的有admin.php或者直接二级目录/admin。登录后第一件事不是急着加域名,而是去系统设置里检查站点名称、备案信息、支付参数是否被正确写入配置文件。配置文件通常是config.php,里面存着数据库连接和API密钥,建议设置600权限,防止被其他用户读取。

3.3 接入第一台主域名:API凭证配置与连通性测试

主域名接入是最容易出现挫败感的一步。在后台的「主域名管理」里添加域名,填入域名名称、选择DNS服务商类型、粘贴API凭证。这里说的API凭证不是域名管理后台的登录密码,而是服务商开放平台上生成的SecretId和SecretKey,两者作用域完全不同,填错后系统的表现是:添加域名成功,但申请子域名时API调用一直报鉴权失败。

在DNSPod侧创建密钥后,建议先在第三方API调试工具里手动调一次记录列表接口,确认密钥有权限操作该域名。有的服务商要求子账号单独授权某域名的权限,主账号密钥默认全权限,子账号密钥如果不授权域名,列表接口能通,创建记录接口却会报错,这就是「读取正常、写入失败」的典型症状。

系统提供的连通性测试按钮很实用。点击测试后,系统会实际调用一次查询接口拉取该域名下的记录列表,并在界面上展示请求耗时和记录数。如果测试返回失败,优先检查两项:密钥是否复制完整(前后不要带空格)、域名是否没有在服务商处完成实名认证。多数服务商对未实名域名的API写操作会直接拒绝。

连通性测试通过后,主域名才算真正接入完成,前台用户才能看到并申请这个域名下的子域名。这一步我一般会顺手在服务商控制台刷新一次,确认系统查询到的记录和后台显示一致,排除系统内部缓存导致的假通过。

4. 参数配置地图:解析API、套餐限制与到期任务怎么调

4.1 套餐与价格规则:时长、限额、单人可持有数

商业版的核心盈利逻辑是「域名租赁」,套餐配置直接决定收益。后台的套餐管理里一般可以设置:套餐名称、价格、时长(天/月/年)、可申请的子域名数量上限、是否允许泛解析前缀。这些参数里最容易忽略的是「单人可持有数」这个限制,不设的话一个用户可以无限申请子域名,把资源池占满。

我把常见套餐参数列一下,方便对号入座:

参数项典型值说明
套餐名称基础版 / 专业版前台展示用,建议区分明显
价格9.9 / 49.9按元计,配合支付接口
时长30 / 365 天到期后自动回收
可申请数量3 / 10限制总量防止滥用
记录类型A / CNAME决定用户填写IP还是域名
是否允许泛解析否允许后子域名可填*,不建议开放

泛解析开关要单独提一下。泛解析意味着用户可以申请*前缀,所有未匹配的子域名都会指向他的目标,这在商业环境里基本等于把主域名整个交出去了,一旦用户拿去做不合规的内容,主域名会被连带拉黑。我一般强烈建议生产环境关闭泛解析,只允许具体前缀,宁可少做点生意也别把根域名搭进去。

套餐价格和时长配置好之后,前台申请页会直接读取这些参数渲染成列表。如果改了套餐参数发现前台没变化,优先检查后台是否生成了缓存,商业版系统通常会把套餐列表缓存到runtime目录,改完配置后点一下「更新缓存」按钮再验证。

4.2 解析记录默认参数:TTL、记录值校验、前缀黑名单

每条自动创建出来的DNS记录都有默认参数,这部分在系统设置里集中配置。TTL建议设600,也就是10分钟,太短会增加DNS查询量,太长则用户改完解析半天不生效。记录值校验规则也要设置,A记录必须是合法IPv4地址,CNAME记录必须是合法域名,这个校验放在服务端做,不能只依赖前端。

前缀黑名单是很多人忽略但非常重要的配置。至少要把以下前缀禁掉:www、mail、smtp、pop、imap、ftp、webmail、ns1、ns2、blog。这些前缀要么是邮件服务器在用,要么是管理服务在用,属于主域名的「保留区」。如果不设置黑名单,用户申请了mail前缀,你的邮件服务就废了。

// 系统设置中的黑名单示例,按需增减 $forbidden_prefix = ['www', 'mail', 'smtp', 'pop', 'imap', 'ftp', 'webmail', 'ns1', 'ns2', 'blog', 'admin', 'api']; // 申请时校验 if (in_array($sub_prefix, $forbidden_prefix)) { return ['code' => 3, 'msg' => '该前缀为系统保留,不可申请']; }

这段逻辑很简单,但位置很关键。校验必须放在服务端申请接口里,而不仅是前端JS里。原因很直接:接口是公开的,有人绕过前端直接POST请求就能把黑名单绕过去。服务端校验一次、数据库唯一索引兜底一次,这才是双层保险。我见过一个站只在前端做了黑名单,被人用脚本刷了一整页mail前缀的解析记录,处理起来相当被动。

除了黑名单,还要注意前缀的格式校验。二级域名前缀只能包含字母、数字和连字符,不能以连字符开头或结尾,长度限制在1到63个字符之间。这个校验用正则或者系统自带的验证器都能做,不加的话用户填个带空格的非法前缀,在DNS服务商API那边会直接报参数错误,用户看到的错误提示还不明不白。

4.3 到期任务与自动回收:cron定时脚本配置

到期回收是这套系统区别于普通域名管理面板的功能。它靠系统定时任务触发,脚本逻辑是:扫描order_info里expire_time小于当前时间的记录,对每一条执行「停用解析」——先把DNS记录删除,再把domain_record.status改为0,同时释放该用户的可申请名额一个。

我一般把回收脚本配置成每10分钟跑一次,太频繁会增加API调用量,太久了用户到期后还能访问,影响续费转化。下面是crontab的典型写法,注意脚本路径和执行用户必须正确:

# 每10分钟执行一次到期回收 */10 * * * * cd /var/www/subapp && php think cron:recycle >> /var/www/subapp/runtime/recycle.log 2>&1 # 每30分钟执行一次解析体检,比对库内记录与DNS侧记录 */30 * * * * cd /var/www/subapp && php think cron:sync >> /var/www/subapp/runtime/sync.log 2>&1

回收任务必须保证「可重复执行」。即使上一次执行到一半PHP内存超限崩了,下一次执行时也不能重复扣用户名额或重复调API删记录。实现上一般靠记录状态机判断:status=1表示正常解析中,status=0表示已回收,cron只处理status=1且已到期的记录。这样就算脚本被重复触发,也不会对已回收的记录做二次操作。

日志是排查到期回收问题的第一现场。recycle.log里每一行应该记录:记录id、子域名、到期时间、API返回结果。如果发现日志里有大量API error但库里状态已经改成0的记录,说明代码顺序有问题——应该是API删除成功后才改库,而不是先改库再调API。这一点在删除逻辑里已经强调过,上线前务必检查一遍回收脚本的代码顺序。

5. 避坑与排查:部署运营中翻车的高发点与处理办法

5.1 添加主域名成功,但申请子域名时API报鉴权失败

现象:后台添加主域名时一切正常,连通性测试也能通过,但用户前台提交申请后,系统提示API鉴权失败,记录没有创建。

原因:这条翻车路径很典型,元凶是域名与服务商平台之间的授权不一致。连通性测试通常只调用查询接口,而创建记录是写操作。某些服务商(尤其是用了子账号密钥的场景)对读和写的权限是分开的,子账号有读取权限但没有写入权限,或者有写入权限但没有对该域名的授权。

解决:先去服务商开放平台检查密钥对应的账号权限,确认该账号对该主域名拥有读写权限。如果用的是子账号,需要在服务商平台上把该域名加到子账号的授权列表里。还有种不明显的原因:密钥填对了,但系统配置的是旧版API地址,服务商升级接口后旧地址返回鉴权失败。这类问题去查系统日志里的API请求URL和返回体,返回体会明确指出问题所在。

5.2 申请时提示域名已占用,但实际库里没有这条记录

现象:用户申请某个子域名,系统提示「该二级域名已被占用」,去数据库里查domain_record表,却发现没有记录。

原因:根源在「唯一索引的检查时机」。如果代码是先往库里插占位记录再调API创建解析,而API调用失败导致插入回滚,此时占用状态是正常的临时状态。但如果是先SELECT再判断,就会有一个并发窗口:两个请求同时查到前缀未被占用,然后都走创建流程,后写的那条就会提示已占用。

解决:把判断逻辑改成「先插占位,后调API,失败回滚」,或者给sub_prefix加唯一索引后直接尝试INSERT,捕获Duplicate entry错误再返回占用提示。第二种方式更稳,不依赖查询与写入之间的时间差,并发下不会出现双写问题。同时建议把DNS解析侧的记录也纳入检查,库里没有但DNS侧存在的记录同样应该提示已占用,否则会出现「申请成功但解析不生效」的假象。

5.3 泛解析记录把未开通的子域名全部指向同一台服务器

现象:主域名下配置了泛解析*记录后,所有未单独创建的子域名都能访问,指向同一台服务器,导致未开通的域名也能打开页面。

原因:这是DNS层面的经典坑。泛解析记录会兜底所有未匹配的二级域名,如果你在服务商处为某个主域名手动加了*,或者之前开通过泛解析套餐,那么即使分发系统只创建了少数几条具体记录,其他未创建前缀的域名也会被泛解析兜到服务器上。

解决:首选方案是删除服务商侧的泛解析记录,让未创建的子域名默认无解析。如果业务上确实需要泛解析,那就要在分发系统里做一层「白名单校验」——所有访问请求进入应用后,先查domain_record表里是否真的存在这个前缀且状态为1,不存在就直接拒绝。这种做法能兜住泛解析带来的滥用风险,但会多一层查询开销。我生产环境上一律禁用泛解析,宁可多创建几条明确记录。

5.4 到期回收后,用户说域名还能打开

现象:后台手动执行回收脚本,日志显示回收成功,但用户反馈域名仍然能访问。

原因:这里有个容易被忽略的时延问题。回收脚本确实调了API删除DNS记录,但DNS的TTL还在生效。TTL设600秒意味着递归解析器会把结果缓存10分钟,10分钟内用户访问仍然能拿到旧IP。如果TTL设成了3600甚至更长,回收后一个小时都能访问,运营上就会产生「回收没生效」的投诉。

解决:两件事一起做。第一,把创建记录时的TTL尽量调小,比如300或600,让回收生效时间控制在合理范围。第二,回收成功后,前台用户中心的域名状态同步标记为「已回收」,让用户能明确看到状态变化。不要跟用户解释DNS缓存原理,直接告诉他「解析配置已删除,全球生效可能需要几分钟」,用户体验好得多。如果被测出回收后两小时还能开页面,优先检查TTL设置,不要先怀疑脚本。

5.5 后台页面打开白屏或重定向循环

现象:部署完成后前台正常,后台打开出现白屏,或者地址栏一直在index.php和login.php之间跳来跳去,进不去登录页。

原因:这类问题大多数跟伪静态规则和runtime缓存有关。白屏常见的元凶是PHP报错被隐藏了,或者入口文件里的调试模式被关闭,错误信息只写进日志不显示,看起来就像整个页面没有输出。重定向循环通常是伪静态规则写重复了,pathinfo模式的rewrite和系统内部的路由跳转打架,形成A跳B、B跳A的死循环。

解决:排查白屏先看runtime/log目录里的错误日志,大多数情况下是某个扩展未安装或权限不足,日志里写得很清楚。排查重定向循环则把伪静态规则临时注释掉,访问index.php?s=/admin/login试试能不能直达,能的话就是rewrite规则写错。把规则精简成只对非真实文件重写一次,很少解决不了。

6. 二开进阶:三件小事把商业版变成可复验的租赁平台

6.1 支付回调与订单状态的骨架

商业版源码里支付接口通常是预留的,你需要在系统设置里填支付网关的appid和密钥,然后核对回调地址是否正确指向系统定义的notify方法。上线前务必用测试金额走一遍完整支付流程,确认支付成功后order_info里的pay_status被置为1、expire_time被正确写入,这一步直接决定后续续费逻辑能不能跑通。

6.2 给用户一个可查的状态页

域名租赁业务里,用户最关心的是「我的域名什么时候到期」。二开时在用户中心加一个状态页,展示每条子域名的申请时间、到期时间、解析目标值、当前状态,再放一个「一键续费」按钮。这个页面不复杂,但它能把后台的到期数据透明化,减少用户来问客服的频次,也降低到期纠纷。

6.3 用一条自查脚本把全链路验收变成习惯

上线交付前,我习惯写一个自查脚本,把「申请-解析-回收」全链路走一遍,确认系统真正可用而不是表面配置完成。脚本直接用命令行PHP跑:

# 创建一条测试子域名,记录返回的id和解析值 php think test:apply --prefix=checktest --target=1.2.3.4 # 查询该记录是否真实存在(调API) php think test:query --prefix=checktest # 手动触发到期回收逻辑,回收后确认DNS侧已删除 php think test:recycle --prefix=checktest

三条命令依次执行完,再回到DNS服务商控制台刷新一下,确认记录确实删除,这套系统才算验收通过。从那以后,我每次部署完这套系统,都会强制走一遍这个check流程,顺手把返回的记录id和解析值对一遍,不做这步就总觉得心里没底。这套流程也帮我挡掉过好几次配置遗漏,希望也能帮到你,少走我当年连文档都没翻完就盲目上线的弯路。

本文还有配套的精品资源,点击获取

返回列表