Files
dsh_shenxian/dsh-server-docs/04-调整方案/22-服务域名迁移到alotbuy.com.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

99 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 22 · 服务域名迁移:dsh.alotbuy.com → alotbuy.com
- 日期:2026-09-10
- 触发:用户裁定「服务域名改为 alotbuy.com」,并在两条路径中选定 **路径 ②:走 Cloudflare 代理(橙云,零 DNS 改动)**
- 结论一句话:**已完成迁移** —— 门户 = `https://alotbuy.com`,用户实例 = `https://<用户名>.alotbuy.com`;旧域名 `dsh.alotbuy.com` 全部 **301** 到新域名(含用户名映射);证书 `alotbuy.com + *.alotbuy.com` 已签发且**续期演练参数已加固**。
- 状态:**已上线**;遗留:CF SSL 模式建议人工确认 Full (Strict)、全员需重新登录
> **TL;DR**|**结论**:域名迁移完成:门户 **`alotbuy.com`**、用户实例 **`<用户名>.alotbuy.com`**;旧域 `dsh.alotbuy.com` 全部 **301**(含用户名映射)。
> **关键**:走 Cloudflare 代理(橙云、零 DNS 改动);签 `alotbuy.com + *.alotbuy.com` 通配证书(**DNS-01 传播必须 60 s**)+ CF 真实 IP 还原。
> **状态**:✅ 已上线(含回滚步骤)
---
## 一、决策与前置侦察(实测)
| 项 | 结果 |
|---|---|
| `alotbuy.com` A 记录 | **已指向本机** `47.77.182.89`,经 **Cloudflare 代理(橙云)** |
| `alotbuy.com` 当时内容 | **nginx 404(空站)** → 根域未被占用,接管无冲突 ✅ |
| `*.alotbuy.com` | **通配记录已存在**(橙云)→ 用户子域天然可解析 ✅ |
| 同域其它记录 | `gao`/`mao`→154.40.35.3、`www`→apex、`work`→apex、`alimail/smtp`→mxhichina、MX/TXT(SPF) → **迁移不触碰这些** |
| CF token 权限 | **仅 DNS(Zone:DNS:Edit)**:能改记录、能签 DNS-01 证书;**不能读写 zone 设置**(SSL 模式需人工确认) |
| CF 回源端口(实测 `ss`) | 全部 **443**,无 80 连接 → CF 处于 Full(或 Strict)模式,**CF→源站已加密**,无明文风险 ✅ |
| 备案 | alotbuy.com 已在阿里云备案(否则子域无法访问)✅ |
## 二、执行步骤(含踩坑)
### 1. 签发通配证书(DNS-01)
```bash
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 --non-interactive --agree-tos \
--cert-name alotbuy.com -d alotbuy.com -d '*.alotbuy.com'
```
产物:`/etc/letsencrypt/live/alotbuy.com/{fullchain,privkey}.pem`(有效期至 2026-12-09,已配置自动续期)。
> ⚠️ **踩坑 1(重要)**:首次签发**失败**(`No TXT record found at _acme-challenge.alotbuy.com`)。certbot 日志显示 TXT 记录**创建成功**,只是**默认只等 10 秒传播**(CF 上实测 ~10 s 才可见,正好卡边界)。写临时 TXT 探测证实记录可被 Google/CF 解析到(无通配 CNAME 劫持),**把传播等待改为 60 s 后即成功**。
> ⚠️ **踩坑 2(续期)**:`certbot` 只把该参数写进**新证书**的 renewal conf;**旧证书(dsh.alotbuy.com)仍是默认 10 s** → 会在 ~60 天后续期失败。已给两个 renewal conf 都补上 `dns_cloudflare_propagation_seconds = 60`。
### 2. nginx vhost(新域名)
- 新增 `/www/server/panel/vhost/nginx/alotbuy.com.conf`:`server_name alotbuy.com www.alotbuy.com *.alotbuy.com`,80 段**代理**(不 301,兼容 CF 任一模式),443 段用新证书;
- 继承 dsh 站点的三项优化:`proxy_buffering off`(流式)、`gzip_proxied any`(930 KB bundle 压缩)、`/assets/` 长缓存;
- **CF 真实 IP 还原**:`set_real_ip_from <CF 全部回源段>` + `real_ip_header CF-Connecting-IP`(写在 server 块内,避免全局生效;否则日志/风控里全是 CF 机房 IP)。
> 踩坑 3:`set_real_ip_from` 写在 vhost 文件顶层会落到 **http 上下文作用于全局**,务必放进 server 块。
### 3. 切换域名配置(drain + 重启)
脚本:`/opt/dsh/switch-domain-alotbuy.sh`(幂等、带备份、**drain 用按 pid 结束而非 `pkill -f`**——后者会杀掉自身 ssh 会话,档案 20 已踩过)
```
env: DSHS_BASE_DOMAIN=alotbuy.com
DSHS_COOKIE_DOMAIN=.alotbuy.com (备份 /etc/dshs.env.bak-20260910-2332)
停服务 → 结束残留 dsh 子进程/scope → 起服务(残留实例数 = 0)
```
### 4. 旧域名 301(保留用户名映射)
`dsh.alotbuy.com.conf` 改为纯跳转,使用 **map + 通配 server_name**(正则 server_name 实测**不匹配**,踩坑 4):
```nginx
map $host $alotbuy_new_host {
default alotbuy.com;
~^(?<label>[^.]+)\.dsh\.alotbuy\.com$ $label.alotbuy.com;
}
server { listen 80; server_name dsh.alotbuy.com *.dsh.alotbuy.com; return 301 https://$alotbuy_new_host$request_uri; }
server { listen 443 ssl; server_name dsh.alotbuy.com *.dsh.alotbuy.com; ssl_certificate …dsh.alotbuy.com…; return 301 https://$alotbuy_new_host$request_uri; }
```
## 三、验证结果
| 检查 | 结果 |
|---|---|
| 门户(经 CF) | `https://alotbuy.com/login.html` → **200** |
| 用户子域(经 CF,未登录) | `https://admin.alotbuy.com/` → **401**(正常:需登录)✅ 说明编排器已把该 Host 识别为用户子域 |
| 旧域名跳转 | `dsh.alotbuy.com/...` → **301 → https://alotbuy.com/...**;`admin.dsh.alotbuy.com` → **301 → https://admin.alotbuy.com/**;`x.dsh.*` → `x.alotbuy.com`(通用映射) |
| 源站证书校验 | `ssl_verify_result=0`(链有效,CF Full (Strict) 亦可通过) |
| 服务状态 | `active`/`enabled`,编排器正常,残留实例 0(用户重新进入时按需拉起) |
| 自动续期 | 两个证书 renewal conf 均含 `dns_cloudflare_propagation_seconds = 60` |
## 四、回滚
| 项 | 回滚 |
|---|---|
| 域名配置 | `cp /etc/dshs.env.bak-20260910-2332 /etc/dshs.env` → 跑 drain(停服务→清实例→起服务) |
| nginx | `cp /www/server/panel/vhost/nginx/{dsh.alotbuy.com.conf.bak-*-pre-redirect,alotbuy.com.conf}` 还原/删除 → `nginx -t && nginx -s reload` |
| 证书 | 保留(不影响) |
## 五、遗留与注意事项
1. **CF SSL 模式建议人工确认为 Full (Strict)**:token 无 zone 设置权限,只能由用户在 Cloudflare 面板确认(当前实测回源走 443,已是 Full 级别;Strict 仅多一层源站证书校验,而我们的证书有效,可直接切换)。同时建议开启 **Always Use HTTPS**。
2. **全员需重新登录**:`COOKIE_DOMAIN` 由 `.dsh.alotbuy.com` 变为 `.alotbuy.com`,旧 Cookie 失效。
3. **Cookie 覆盖面扩大**:`.alotbuy.com` 意味着该 Cookie 会随请求发往 `alotbuy.com` 下**所有子域**(含 `gao`/`mao`/`work`/`www`)。若日后希望收窄,需改为在 `<用户名>.alotbuy.com` 上设置 host-only Cookie(涉及代码改动)。
4. **宝塔面板会重写 vhost**:在面板里保存站点配置可能抹掉 `proxy_buffering off` / `gzip_proxied any` / `real_ip` 等自定义指令 → 流式或真实 IP 异常时先回来检查。
5. 未完成项(独立跟踪):档案 21 §三 的 **A1 禁用 HMR**、**A2 catch-all 默认站点**。
## 六、红线遵守
- 未触碰 R1(不升级 dsh)与 R2(不改官方 dsh 主程序);仅改 nginx 站点配置、编排器环境变量与 DNS/证书。
- 全程保留可回滚副本(env / vhost / renewal conf 各有 `*.bak-*`)。
- 未改动 alotbuy.com 的 MX/邮件/TXT 记录与 `gao`/`mao`/`work` 等既有子域记录。