Files
dsh_shenxian/dsh-server-docs/04-调整方案/135-旧域alotbuy.com从项目移除.md
T
admin 971ccc3703 feat(auth): 注册页人机验证 + 邮箱验证码;品牌标识去 DeepSeek(附域名迁移线 序㊿ 补提交)
三条线合并入库 —— 均已完成并上线(源码与生产一致,此前只部署未入仓)。
⚠️ 其中域名迁移线为**另一会话**产出,本会话只做入库、**未复验其正确性**(它自报零回归)。

【档案 134 · 注册页人机验证 + 邮箱验证码】
- DB 迁移 v10:users.email(唯一索引 LOWER(email))+ email_codes 事件表(2 索引)
- 新增模块 src/web/{register-guard,mail,turnstile,email-code}.ts
- routes/auth.ts:新增 GET /api/auth/register/config、POST /api/auth/register/email-code;
  注册接口加人机验证与验证码校验;config.ts 新增 12 项配置(默认空 ⇒ 不配 = 老行为)
- 邮件走**可插拔驱动**(brevo/http/log),发件人 [email protected](Brevo 域名已认证 + DKIM + SPF)
- 防爆破:三层配额(邮箱 6/h、8/天;IP 20/h;全局 200/h)+ 递增冷却阶梯
  (60→60→180→300→900→1800s)+ 试错 5 次作废 + 码只存哈希 + 单次使用 + 与用户名绑定
- Turnstile 服务端校 **success + action + hostname 三项**:sitekey 是公开的,
  只校 success 时"拿我们的 sitekey 在自己站点替真人取合法 token 再打我们接口"这条路是通的
- 新增 test/register-guard.test.mjs(19 用例)

【档案 137 · 品牌标识改造 — 去 DeepSeek 图形】
- login/register/admin 页头:删 DeepSeek 鲸鱼图标 + 「DeepSeek」文字图形
  → 平台标识(中文「能力枢纽」/英语及其他语言「CapabilityNet」,走 i18n 词条 brand.name)
- portal 顶栏换图标(页面名「管理门户」保留)
- 新建 web/favicon.svg(平台自有 hub 图标,避开 DeepSeek 蓝)+ 四页 favicon 指向它
- 新增 test/i18n-brand.test.mjs(node:vm 跑真实 i18n.js,六条语言路径断言渲染结果)
- scripts/verify-static.mjs 新增 SVG 段:XML 注释不得含 ASCII 双连字符(否则整份 SVG
  解析失败、图标静默不显示 —— 实际踩到过)
- 🔴 会话页面(实例内官方 dsh 界面)的标识**按用户要求未动**(也受 R2 约束)

【档案 135/136 · 域名迁移线(另一会话产出)】
- 域名收敛为 ai1net.com;旧域 alotbuy.com 降级为 301 过渡装置
- src/net/relay/{addr-override,directory,rendezvous,switcher}.ts 种子与候选链更新;
  src/web/server.ts、src/worker/relay-tunnel.ts、scripts/verify-cluster-domain.mjs
- 档案 136 = 控制面按两台中继取并集(**已立项、未落地**)

验证(本会话两条线):新增单测 21 条全通过|全量 221 pass / 0 fail / 1 skipped|
verify-static 全合格|其余 10 个 verify 脚本全 OK|线上实测:Turnstile 假 token 403、
发码 delivered、四页 deepseek 命中 0、favicon 200。
2026-09-19 09:11:24 +08:00

12 KiB
Raw Blame History

135-旧域 alotbuy.com 从项目移除(2026-09-19 落地)

一句话:平台对外域名收敛为 ai1net.com 单一域名;旧域 alotbuy.com 在代码 / 服务端配置 / 文档技能三层全部移除, 旧域 nginx 站点降级为 301 过渡装置(保留 relay 透传与 ACME,30 天零流量后退役)。 触发:用户 2026-09-19 原话 —— 「旧域 alotbuy.com 怎么处置:从项目中移除后续都用新域名」 执行:序㊿ 执行棒(会话名 旧域移除-控制面并集-20260919)· 计划书 = 工作区根 _tmp_dompurge/PLAN-旧域移除与并集立项_20260919.md 姊妹件:同棒产出的立项交接单 = 04-调整方案/136-控制面按两台中继取并集-立项交接单.md

背景与动机

  1. 域名已在 09-19 切换完成(见 ops/域名迁移_ai1net_20260919/RUNBOOK-cutover.md),但切换只做到"新域能用", 旧域仍以独立门户站点形态存在 ⇒ 两套入口并存 = 两套证书、两处签名目录、两处排障路径。
  2. 旧域残留会让判据撒谎:演练脚本的"是否切到 47 那台中继"判定用硬编码域名字符串匹配端点 ⇒ 域一改,真实发生的切换会被判成失败(本节 §"实测踩坑 1" 即此坑)。
  3. relay 候选里存在"摘名不同、物理同一"的伪多样性:alotbuy.com 与 relay-direct.alotbuy.com 摘名不同、 同落 47 同一路径、且后者还开了 DSHS_OVERLAY_ADDR_OVERRIDES 直连 IP ⇒ 5 条候选里 2 条零物理多样性。

用户决策

时间 用户口径 落地
2026-09-19 「从项目中移除后续都用新域名」 代码 / 服务端 / 文档技能三层真实替换;旧域不删站、降级 301(删站会打断仍指向旧域的客户端,净变差 ⇒ R11 不允许)
2026-09-19 「A 立项修」(控制面并集) 只出立项交接单(档案 136),本轮不落地

范围分桶(最终实测结论)

桶 对象 处置
A 代码 / 运行时 src/**、web/**、test/**、scripts/** ✅ 全量替换(10 个源文件 + 2 个 test + 2 个 live 校验脚本 + 1 个演练脚本 + 1 个探针注释)
B 服务器配置 47 的 drop-in / nginx;106 的 worker env ✅ 落新值(见 §执行记录 S3/S4)
C nginx 旧域站点 47 /etc/nginx/conf.d/alotbuy.com.conf ✅ 降级为 301 过渡装置(保留 3 条非 301 路径)
D 文档 / 技能 文档库 + skills/** ✅ 42 处精确替换 + 1 处补 Edit(只改"现行事实"章节)
E 不动的 04-调整方案/** 历史档案、archive/**、参数表 §11 历史补记 ⛔ 历史记录不改(改了就是伪造历史)
F 排除 work.alotbuy.com(Gitea 仓库服务) ⛔ 不是本平台域名,与迁移无关

执行记录(S1–S7)

S1 · 代码层替换(A)

  • 扫描 127 个文件,命中并改写 10 个:src/config.ts×2、src/net/relay/addr-override.ts×4、src/net/relay/directory.ts×2、 src/net/relay/rendezvous.ts×1、src/net/relay/switcher.ts×4、src/web/server.ts×3、src/worker/relay-tunnel.ts×5、 test/overlay-bootstrap.test.mjs×22、test/relay-failover.test.mjs×4、web/wake.html×1。
  • ⚠️ 计划书的行号表是快照、已漂移(例:计划写 config.ts:312,实测 :381;另有计划未登记的 config.ts:125、directory.ts:324) ⇒ 一律先自己 scoped grep、再做字节级精确替换,⛔ 不按计划行号下手。

S2 · 修掉一个真 bug(A3)

  • web/wake.html 里有转义点写法 alotbuy\.com,被批量替换漏掉 ⇒ 白名单正则仍只认旧域 = 唤醒后跳转白名单恒不命中。
  • 修为新域后缀(单后缀即正确 —— 已核 next 是由请求 host 拼出的绝对 URL,见 src/supervisor/proxy.ts:613): /^(\^|\.)ai1net\.com$/.test(x.hostname)(源码中无多余反斜杠)。

S3 · 47 服务端(B + C)

  • drop-in overlay-443fb.conf:DSHS_OVERLAY_BOOTSTRAP_SEEDS 5 → 3,删掉同机同路径的两条旧域候选; DSHS_OVERLAY_ADDR_OVERRIDES=relay-direct.ai1net.com=47.77.182.89;注释写明"旧域 /dshs-relay 透传仍在"与回滚原文。
  • nginx 旧域站点降级:map $host $alotbuy_301_host(默认 ai1net.com;~^(?<lb301>[^.]+)\.alotbuy\.com$ → $lb301.ai1net.com ⇒ 子域对子域映射),80/443 双 server 全 301;仅保留 3 条非 301 路径: /.well-known/acme-challenge/、/dshs-relay → 127.0.0.1:20080、= /dshs-overlay/bootstrap → 127.0.0.1:3080。
  • 文件头写入降级而非删除的理由与退役条件 = 30 天零流量。
  • 归档 _pending-ai1net/ → mv 到 /root/_dompurge/_pending-ai1net-archived-<ts>(不是删除)。

S4 · 106 worker(B)

  • /etc/dshs-worker.env 第 26 行同步为同 3 条 SEEDS;备份 /etc/dshs-worker.env.bak-dompurge-20260919-073149;daemon-reload。
  • 顺带取证:dshs-relay-client 单元为 disabled(历史遗留、无害)—— 只报告、未动。

S5 · 控制面二次重启以清签名目录缓存(关键一步)

  • 一次重启后 bootstrap 仍是 5 条、仍含 2 条旧域 ⇒ 定位到 Manager 把自己发布的签名目录缓存在 /var/lib/dshs/overlay/directory.json(fetchedAt 07:29,早于改动)且懒重建。
  • 处置:备份 + 删除该可再生缓存 → 第二次重启控制面 ⇒ Manager 解析出 3 条候选、全部新域 (source=seed-directory),缓存重建 578 B。

S6 · 文档与技能(D)

  • 42/42 处精确替换(每处带 count 断言):BRIEF.md、README.md、INDEX.md、DEPLOY-本部署.md、 02-运维手册.md(仅附录 C = 现行事实章节)、docs-manifest.json、scripts/docs-consistency.py、 scripts/cf-probe.py(新增 CREDS={'ai1net.com':'/etc/cloudflare-ai1net.ini'} + token(zone))、7 个技能文件。
  • 补 1 处:skills/dsh-instance-diagnose/SKILL.md(goto https://<user>.ai1net.com/)。
  • 文档库镜像同步:ops/nginx/alotbuy.com.conf 换为 301 版(md5 eccf9014c6e1c3f13a5c32b7b14418a9,与生产一致)。
  • 从 47 暂存目录抢救回 ops/域名迁移_ai1net_20260919/RUNBOOK-cutover.md(唯一副本),并在头部加状态横幅 (记录 §1 阻塞已解、S1–S5 已执行;原"留待你确认退役时机"已被本棒取代)。

S7 · 参数字典与判据脚本

  • 参数表值格 2 键:PORTAL_HOST_HEADER、DRILL_KILLED_MATCH 由 alotbuy.com → ai1net.com(🔴 后者是假红根因,见踩坑 1); + 两处 -H "Host: alotbuy.com" 示例 + §6 一条候选摘名说明 ⇒ §10 指纹同步为 075a97239c2d1d8a1f442ec6cc787ede。
  • scripts/overlay-probe.cjs 注释、verify-cluster-domain.mjs / verify-platform-admin-section.mjs 默认域同改。

实测踩坑(两条,都是"判据撒谎"型)

踩坑 1 · 演练"假红"(已修)

  • 现象:overlay-failover-drill.cjs --scene all = 11 PASS / 1 FAIL(基线 12 PASS),红在幕4-A「目标不是 47 那台」。
  • 根因:幕4-A/幕4-B 的判定用硬编码字符串 alotbuy.com 去匹配端点 ⇒ 豁免真的生效了、真的切回 47,只是判定认不出。
  • 修法:两处匹配器改为取参数表 DRILL_KILLED_MATCH(m3.includes(killedMatch) / m2.includes(killedMatch)),并在注释块记录本次域迁移的勘误。

踩坑 2 · 「查旧域不存在」的两种假象

  • 旧域 /dshs-relay 直取 = 404:曾疑似回归 ⇒ A/B 对照:新域裸 GET 同样 404;两域带 WS 升级头都返回 101 ⇒ 非缺陷(/dshs-relay 只对 WebSocket 升级生效)。
  • admin/guest.ai1net.com = 401(不是 302):属既有"无 session 直连实例页"行为,非回归(档案 136 §7 E7 已登记口径)。

验收证据

# 判据 结果
V1 签名 bootstrap 候选集 3 条 / 0 处旧域,source=seed-directory,缓存 578 B
V2 零回归三件套 · 探针 overlay-probe.cjs 29 PASS / 0 FAIL / 0 SKIP(rc=0);OBS-21 = count=3 hosts=3,47 / 106 两机读一致,全表零 alotbuy
V3 门户可达 新域首屏 200
V4 旧域过渡 301 生效,含子域映射(guest.alotbuy.com → https://guest.ai1net.com/...)
V5 relay 透传双域一致 裸 GET 双域同 404 / WS 升级双域同 101
V6 零回归三件套 · npm test 未跑(本棒零测试面逻辑改动;仅字符串与匹配器)
V7 零回归三件套 · 演练 --scene all ✅ 12 PASS / 0 SKIP / 0 FAIL(rc=0;5m56s~6m;末行原文 # 结果:12 PASS / 0 SKIP / 0 FAIL)—— 修后复跑,幕4-A 目标 = wss://ai1net.com/dshs-relay、耗时 15867 ms / deadline 30000 ms。⚠️ 全套含 120 s + 90 s 观察窗 ⇒ 外层超时必须 ≥ 8 min,否则 restore() 不跑、106 relay 会留在停机态
V8 技能「三处」同步 ✅ 6 个技能全部本机/文档库/47 镜像三处域已清;其中 3 个(decision-method / feature-first / plugin-diagnose)三处 md5 全同(a8971220 / a1397140 / 3edeeb89);⚠️ 另 3 个(change-workflow / opensource-release / instance-diagnose)本机副本更新 ⇒ 存在本会话之外的既存漂移,本轮只做域替换、⛔ 未覆盖新副本(详见 §残留项 6)

回滚

  • 代码:git checkout -- src web scripts + npm run build ⇒ scp 回 /opt/dshs/(产物清单见 _中间产物_待清理/_证据_序50_部署产物15文件md5_20260919.txt,15 个文件)。
  • 47:drop-in 恢复 5 条 SEEDS(原文在文件注释里)→ daemon-reload → restart dshs;nginx 旧域站点恢复原站(备份在同目录 .bak-*)。
  • 106:cp /etc/dshs-worker.env.bak-dompurge-20260919-073149 /etc/dshs-worker.env → daemon-reload → restart dshs-worker。
  • 回滚后必须删一次 /var/lib/dshs/overlay/directory.json 并重启控制面(否则又读到旧缓存 ⇒ 假回滚成功)。

残留项 / 后续(不阻塞)

  1. 旧域退役条件:alotbuy.com 站点保持 301 过渡,30 天零流量后再评估删除;relay-direct.conf、dsh.alotbuy.com.conf 同属"导向新域 / 兜底"装置,删除即净变差(R11) ⇒ 保留。
  2. 参数表 §11 历史补记仍引用旧域(含旧证据原文引用)—— 故意不改(历史记录)。
  3. dshs-relay-client(106) = disabled 历史遗留,无害,未动。
  4. 演练脚本修正版按惯例应两机同源部署(scripts/overlay-failover-drill.cjs 是本机 ssh 出去的工具,不被任何单元读取 ⇒ 零服务影响)。
  5. 控制面按两台中继取并集 —— 立项见 档案 136(本轮只立项,未落地)。
  6. 技能副本的既存漂移(⛔ 本会话之外形成,只报告未统一):.workbuddy/skills/ 与文档库 skills/ 三对不一致 —— dsh-change-workflow(本机 1055 行 vs 文档库 1039 行)、dsh-opensource-release(本机 1.8.2 vs 文档库 1.7.8)、 dsh-instance-diagnose(本机 SSH 别名更正 vs 文档库旧写法)。⇒ 本轮对这三份只做域替换(⛔ 不覆盖,避免丢内容); 镜像 /opt/dsh/docs/skills/ 已与文档库对齐(md5 同)。回头条件 = 有人真正要动用这三份技能时,先做一次副本收敛。
  7. /opt/dsh/docs 镜像的更广泛漂移(⛔ 本单范围外,未推送):docs-sync-check.sh(须 [email protected],默认别名已失效) 报出30+ 个"仅本地待推送"文件 —— 属本会话之前就存在的镜像滞后,本轮只推了 6 个技能文件,其余按"只做被明确要求的事"未动。
  8. 演练脚本 overlay-failover-drill.cjs 未铺服务器:两机 /opt/dshs{,-cluster}/scripts/ 本来就没有该文件(它是本机 ssh 出去的工具) ⇒ 只在本机生效;而 overlay-probe.cjs 已按惯例三处同源(md5 55568f87bfe2dc8e43289c69b4126004)。