☰
二级域名分发系统源码:自动化申请解析与易支付对接实战
2026/9/27 23:06:16 网站建设 项目流程

简介:这份资源是PHP开发的二级域名分发系统源码,已对接易支付接口,面向需要搭建域名分发平台的站长、个人开发者及中小型服务商,可解决多用户二级域名申请、自动分发与在线收款的一体化需求。源码基于PHP7.2环境运行,需安装SG11扩展,部署时放入根目录解压、先设置伪静态再访问域名即可进入安装流程,适合具备一定PHP环境配置与建站经验的技术人员使用。压缩包为rar格式,整体约13.83MB,文件类型明细上游暂未提供,但按此类系统惯例应包含PHP程序文件、前端静态资源、数据库脚本及配置文件等,便于直接部署与二次开发。目前已有448人学习下载,说明该方案在域名分发场景中具有一定参考价值。读者可借此获得一套可运行的域名分发系统,理解易支付对接逻辑、伪静态配置要点与安装排错思路,并在此基础上按自身业务需求调整界面与功能模块。

1. 二级域名分发系统源码:从申请到解析,一套能跑通的自动化链路

做 SaaS、建站平台或者多租户工具的人,迟早会撞上同一个需求:让用户自己申请一个xxx.你的主域.com的二级域名,申请完自动生效,不用你手动去 DNS 后台加记录。用户量一上来,手工加解析就是灾难,一天几十个申请能把人逼疯。这套「二级域名分发系统源码」解决的就是这件事——它把域名申请、可用性校验、DNS 记录写入、订单支付串成一条自动链路,并且已经对接了易支付,用户付完款系统自动开通。适合谁?适合手里有主域名、想快速搭一个二级域名分发站点的站长和独立开发者,尤其是做虚拟主机、短链、博客托管、游戏私服这类需要批量发子域名的场景。源码本身是 PHP 技术栈,部署门槛不高,但 DNS 接口和支付回调这两块是翻车重灾区,下面拆开讲。

2. 系统架构与 DNS 解析原理:为什么不能只靠一条 A 记录

2.1 二级域名分发的核心链路

先把整条链路说清楚,不然后面配置全是玄学。用户在前台输入想要的二级域名前缀,系统做三件事:查这个前缀有没有被占用、查主域名当前的解析记录、把新记录写进 DNS。写记录这一步,取决于你的主域名托管在哪家 DNS 服务商。常见做法是主域名托管在 Cloudflare、阿里云 DNS、DNSPod 这类提供 API 的服务商,系统通过 API 调用添加解析记录。

这里有个关键选型问题:泛解析还是逐条解析。泛解析就是加一条*.你的主域.com指向服务器 IP,所有二级域名自动生效,系统只需要记录「谁申请了哪个前缀」,不用真的去写 DNS。这种方式最省事,但缺点是无法给不同用户指向不同 IP,也没法做单独的解析管理。逐条解析则是每个申请都调一次 DNS API 写一条记录,灵活但依赖 API 稳定性。

这套源码走的是逐条解析路线,因为它要对接支付,每个用户开通的域名需要独立可控。理解这一点很重要,后面排查「域名申请成功但打不开」时,第一个要看的就是 DNS 记录到底写进去没有。

2.2 主域名与 DNS 服务商的对接配置

以 Cloudflare 为例,你需要在 Cloudflare 后台生成一个 API Token,权限给到Zone.DNS的编辑权限,Zone 资源限定到你的主域名。拿到 Token 后填进系统的配置文件。常见做法是把 DNS 配置单独放一个 config 文件,方便换服务商。

// config/dns.php 常见配置结构 return [ 'driver' => 'cloudflare', // DNS 服务商驱动 'api_token'=> '你的Cloudflare_Token', 'zone_id' => '你的主域名ZoneID', // 在域名概览页右下角 'main_domain' => 'example.com', // 主域名,不带 www 'record_type' => 'A', // 默认解析类型 'default_ip' => '1.2.3.4', // 默认指向的服务器IP 'ttl' => 120, // TTL,Cloudflare 自动模式填1 ];

逻辑说明:driver决定调用哪个服务商的 API 封装类,源码里一般有CloudflareDriver、AliyunDriver等。zone_id是最容易填错的地方,它不是域名本身,而是服务商给这个域名分配的唯一 ID,填错会直接报 403 或 record not found。default_ip是二级域名默认解析到的服务器地址,如果你的分发系统本身和业务服务器不是同一台,这里要填业务服务器的 IP。

参数怎么改:TTL 建议设短一点,比如 120 秒,方便调试时快速生效;生产环境可以调到 600。record_type如果你的业务走 CDN,可能要改成 CNAME,这时default_ip要换成 CNAME 目标地址。

2.3 数据库表结构与域名状态流转

源码的数据库一般围绕三张表转:用户表、域名申请表、订单表。域名申请表里最关键的是status字段,它决定了这个二级域名当前处于什么状态。

字段类型说明
idint主键
user_idint申请用户
subdomainvarchar二级域名前缀,如test
full_domainvarchar完整域名,如test.example.com
statustinyint0待支付 1已开通 2已过期 3已释放
dns_record_idvarcharDNS 服务商返回的记录ID,删除时要用
expire_atdatetime到期时间

状态流转是:用户提交申请 → status=0 生成订单 → 支付回调 → status=1 并调用 DNS API 写记录 → 到期未续费 → status=2 → 宽限期后 status=3 并删除 DNS 记录。dns_record_id这个字段很多人建表时漏掉,结果删除域名时找不到记录 ID,只能去 DNS 后台手动删,血泪经验。

3. 易支付对接与支付回调:订单状态怎么才能不错乱

3.1 易支付接口的请求与签名

易支付是一套常见的聚合支付接口,对接方式是基于 MD5 签名的表单提交或 API 请求。核心参数包括商户号pid、商户密钥key、订单号out_trade_no、金额money、回调地址notify_url、跳转地址return_url。签名规则通常是把参数按 ASCII 排序后拼接密钥做 MD5。

// 发起支付请求的常见封装 function buildPayUrl($order) { $params = [ 'pid' => $config['pid'], 'type' => 'alipay', // 支付方式 'out_trade_no' => $order['order_no'], // 商户订单号,必须唯一 'notify_url' => $config['notify_url'], // 异步回调,服务器间通信 'return_url' => $config['return_url'], // 同步跳转,用户浏览器 'name' => '二级域名开通', 'money' => $order['amount'], ]; ksort($params); // 按键名升序 $signStr = ''; foreach ($params as $k => $v) { $signStr .= $k . '=' . $v . '&'; } $signStr = rtrim($signStr, '&') . $config['key']; $params['sign'] = md5($signStr); $params['sign_type'] = 'MD5'; return $config['api_url'] . '?' . http_build_query($params); }

逻辑说明:ksort排序是签名能否通过的关键,顺序错了签名必错。out_trade_no必须全局唯一,一般用「日期+自增ID+随机数」生成,重复订单号会导致支付平台拒绝。notify_url是异步回调,支付成功后支付平台服务器会 POST 数据到这个地址,这是开通域名的真正触发点,不是return_url。

参数怎么改:type按你开通的支付方式填,常见有alipay、wxpay。money保留两位小数,格式错误有些支付平台会直接拒单。

3.2 异步回调的验签与幂等处理

回调处理是整个系统最容易出 bug 的地方。支付平台会 POST 一堆参数过来,你要做四件事:验签、核对金额、检查订单是否已处理、开通域名。

// notify.php 回调处理核心逻辑 $data = $_POST; $sign = $data['sign']; unset($data['sign'], $data['sign_type']); ksort($data); $signStr = ''; foreach ($data as $k => $v) { $signStr .= $k . '=' . $v . '&'; } $signStr = rtrim($signStr, '&') . $config['key']; if (md5($signStr) !== $sign) { exit('fail'); // 验签失败,必须返回 fail } if ($data['trade_status'] !== 'TRADE_SUCCESS') { exit('fail'); } // 幂等:先查订单状态,已开通直接返回 success $order = getOrderByNo($data['out_trade_no']); if ($order['status'] == 1) { exit('success'); } // 核对金额,防止篡改 if (bccomp($order['amount'], $data['money'], 2) !== 0) { exit('fail'); } // 开通域名:写 DNS 记录 + 更新订单状态 openDomain($order['id']); exit('success');

逻辑说明:验签前必须把sign和sign_type从数组里剔除,否则签名串会多出这两个字段导致校验失败。返回success是告诉支付平台「我处理好了,别再重发」,返回fail或什么都不返回,支付平台会按策略重试,重试次数多了可能触发风控。幂等判断是后悔药——支付平台可能因为网络问题重复回调,没有幂等判断就会重复开通、重复扣 DNS 配额。

参数怎么改:trade_status的值不同支付平台不一样,有的用TRADE_SUCCESS,有的用1,以你对接的易支付文档为准。金额核对用bccomp而不是==,浮点数直接比较会翻车。

3.3 开通域名的原子性处理

开通动作包含「写 DNS 记录」和「更新订单状态」两步,这两步必须尽量保证原子性。常见做法是先把订单状态改成「开通中」,再写 DNS,写成功后再改成「已开通」。如果写 DNS 失败,订单停在「开通中」,方便人工介入或定时任务重试。

function openDomain($orderId) { updateOrderStatus($orderId, 'opening'); // 先标记开通中 $order = getOrder($orderId); try { $recordId = dnsAddRecord($order['subdomain'], $order['ip']); saveDnsRecordId($orderId, $recordId); updateOrderStatus($orderId, 'opened'); } catch (Exception $e) { logError('开通失败:' . $e->getMessage()); // 保持 opening 状态,等定时任务重试 } }

逻辑说明:先标记「开通中」是为了防止回调重试时重复写 DNS。dnsAddRecord返回的记录 ID 必须存下来,删除域名时要用。异常不抛出而是记日志,是为了让回调能正常返回,避免支付平台一直重试。

4. 部署与 Nginx 配置:主域名和二级域名怎么共存

4.1 环境准备与源码部署

源码是 PHP 的,常见运行环境是 Nginx + PHP-FPM + MySQL。部署步骤不复杂,但有几个点容易漏。

# 1. 拉取源码到站点目录 cd /www/wwwroot unzip domain-dist.zip -d domain-dist # 2. 设置运行目录权限 chown -R www:www domain-dist chmod -R 755 domain-dist chmod -R 777 domain-dist/runtime # 框架运行时目录 # 3. 导入数据库 mysql -u root -p your_db < domain-dist/install.sql # 4. 修改数据库配置 vim domain-dist/config/database.php

逻辑说明:runtime目录给 777 是因为 PHP 框架要写缓存和日志,权限不够会报「无法写入」的白屏。数据库配置文件里填 host、user、password、dbname 四项,prefix表前缀如果和 install.sql 里不一致要改。

参数怎么改:PHP 版本建议 7.4 或 8.0,太老的 5.6 可能跑不起来某些语法。MySQL 建议 5.7 以上。

4.2 Nginx 主域名与二级域名的 server 配置

这是热词里问得最多的问题:主域名和二级域名怎么在 Nginx 里共存。核心是用泛域名解析配合 server_name 通配符。

# 主域名站点 server { listen 80; server_name example.com www.example.com; root /www/wwwroot/domain-dist/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } # 二级域名泛解析站点 server { listen 80; server_name *.example.com; root /www/wwwroot/user-sites/$host; # 按域名分目录 index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }

逻辑说明:server_name *.example.com匹配所有二级域名,Nginx 会优先匹配精确域名,所以主域名走第一个 server,二级域名走第二个。$host变量是当前请求的域名,用它做目录可以实现「每个二级域名一个独立目录」。如果你的分发系统只是做跳转,第二个 server 可以改成return 301到统一页面。

参数怎么改:fastcgi_pass的 socket 路径要和 PHP-FPM 配置一致,宝塔面板一般是/tmp/php-cgi.sock,自己编译的可能是127.0.0.1:9000。root路径按实际部署目录改。

4.3 泛解析与逐条解析的配合

如果你的系统是逐条解析,那 Nginx 的泛解析 server 只是兜底,真正生效的是 DNS 里逐条写的记录。这里有个坑:泛解析记录*.example.com和逐条记录test.example.com同时存在时,DNS 查询会优先返回精确记录,所以逐条解析能覆盖泛解析。但如果你先加了泛解析,用户申请时系统检测「域名是否可用」会误判——因为泛解析让所有前缀都能解析。常见做法是可用性检测只查数据库,不查 DNS。

5. 避坑与常见问题排查:那些让你怀疑人生的报错

5.1 支付成功但域名没开通

现象:用户付了钱,订单显示已支付,但二级域名访问不了,DNS 里也没有记录。

原因:回调没收到,或者回调收到了但验签失败、金额核对失败,导致openDomain没执行。也可能是notify_url填的是内网地址,支付平台服务器访问不到。

解决:先看支付平台的回调日志,确认有没有发起回调、返回什么。再看系统日志里有没有验签失败的记录。notify_url必须是公网可访问的完整 URL,不能带参数,不能是 localhost。验签失败重点检查密钥有没有多余空格、参数排序对不对。

5.2 DNS 记录写入报 403 或 record already exists

现象:调用 DNS API 时报权限错误,或者提示记录已存在。

原因:403 一般是 API Token 权限不够或 zone_id 填错。record already exists 是同一个前缀已经有一条记录,可能是上次开通失败残留的。

解决:Cloudflare 的 Token 要明确给Zone.DNS.Edit权限,Zone 资源要选中主域名。zone_id 在域名概览页右下角,不是域名本身。遇到记录已存在,先调 API 查一下该前缀的记录,存在就先删再建,或者直接复用。

5.3 二级域名解析生效慢

现象:DNS 记录明明写进去了,本地就是打不开,换网络又能打开。

原因:本地 DNS 缓存没刷新,或者 TTL 设得太长。

解决:调试阶段 TTL 设 120 秒,用dig test.example.com或在线 DNS 查询工具确认记录是否已生效。本地可以ipconfig /flushdns(Windows)或sudo systemd-resolve --flush-caches(Linux)刷新缓存。如果用了 CDN,还要等 CDN 回源配置生效。

5.4 订单号重复导致支付失败

现象:用户下单时报「订单号已存在」或支付平台拒单。

原因:订单号生成规则有并发问题,同一秒内多个请求生成了相同订单号。

解决:订单号里加用户 ID 和随机数,比如date('YmdHis') . $userId . mt_rand(1000,9999)。数据库对order_no字段加唯一索引,插入失败就重新生成。

5.5 删除域名后 DNS 记录残留

现象:用户域名到期释放了,数据库里状态也改了,但 DNS 里记录还在,域名还能访问。

原因:删除时没拿到dns_record_id,或者删除 API 调用失败没重试。

解决:建表时务必存dns_record_id。删除逻辑做成「先标记待删除,定时任务扫描并调 API 删除,成功后再改状态」,避免一次失败就永久残留。

6. 进阶:把分发系统做成可运营的产品

源码跑通只是起点,真要运营还得补几块。第一块是域名前缀的敏感词过滤,用户申请admin、api、mail这类前缀要拦截,否则容易和你的业务冲突,也容易被滥用。常见做法是维护一个保留词库,申请时做前缀匹配。

第二块是到期提醒和自动续费。expire_at字段有了,加一个定时任务,到期前 7 天、3 天、1 天分别发提醒,到期当天没续费就改状态并删记录。定时任务用 crontab 跑,别用用户访问触发,不可靠。

# crontab 示例:每天凌晨检查到期域名 0 2 * * * /usr/bin/php /www/wwwroot/domain-dist/think expire:check >> /var/log/domain_expire.log 2>&1

第三块是解析记录的健康检查。写进去的记录不一定真的能访问,可以加一个定时任务,对已开通的域名做 HTTP 探测,连续失败就告警。这个功能很多分发系统没有,但用户投诉「域名打不开」时,你能第一时间知道是 DNS 问题还是业务服务器问题。

验证方法上,我一般会走一遍完整链路:注册用户 → 申请域名 → 下单 → 用测试支付环境付款 → 看回调日志 → 查 DNS 记录 →dig验证 → 浏览器访问。每一步都留日志,出问题能定位到具体环节。从那以后我每次部署这类系统,都强制先跑一遍全链路测试再开放注册,不然用户一多,问题全堆在一起根本查不过来。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询