feat(ssl): 证书签发链路搬到国内机 Docker,清理 1Panel 过期证书

架构定案(B+C):CF Worker 免费版 CPU 硬顶 10ms(cron 同),
不再购买 Paid($5/月≈¥36),改为——
  B. Worker 留免费版 + 代码优化(把 CPU 压进预算)
  C. 签发+部署整条链路搬国内机 Docker 容器

代码
- acme.ts: 缓存 signingKey 为 Promise,单次签发 importKey 12→1 次
  (实测 importKey 126µs / sign 84µs;一次签发 3.3ms → 1.4ms)
- deployer.ts: 新增 DogeCloudDeployer.ping();修正 cert_id → id 的注释
- dnsprovider.ts: 新增 RemoteDns(把 DNS-01 写 TXT 委托给国内机 cn-dns-helper)
- tools/certkeeper-config.mjs: 域名配置抽为唯一事实源(两个消费方共用)
- tools/export-certkeeper-data.mjs: 导出国内机数据目录

新增部署单元
- deploy/cn-certkeeper: 签发+部署容器(只绑 127.0.0.1:8019,compose 管理)
  含 FileKV(文件系统版 KVNamespace)、带鉴权 HTTP、每日 4:10 续期
- deploy/cn-dns-helper: DNS-01 写 TXT 助手(只绑 127.0.0.1:8018)

文档
- 函数版证书管家-方案.md 新增第九章:B+C 定案、实测 CPU 数据、
  容器验收记录、1Panel 过期证书清理记录、t-t.live 两套管理冲突
- 标注旧 8.3 节「免费版跑不了签发」为未实测误判

一并纳入:.gitignore 忽略 deploy/cn-certkeeper/lib/(tsc 编译产物)
This commit is contained in:
zqlit committed 2026-10-06 18:28:55 +08:00
1 parent ca3e7e8160
commit 1fa639e630
15 files changed
+1387 -52

No files matched your search

+26 -1
View File
@@ -134,6 +134,30 @@ export class DogeCloudDeployer implements Deployer {
return d.data as T;
}
/**
* 只读探活:列一次 CDN 域名,验证 AK/SK 与连通性。
*
* ★ 与 OnePanelDeployer.ping 保持**同一签名**(返回对象、不抛错),
* 这样调用方(cn-certkeeper 的 /preflight、Worker 的 /ssl/selfcheck)
* 能统一处理,不必为每种部署器各写一套判错逻辑。
*/
async ping(): Promise<{ ok: boolean; error?: string; hint?: string; detail?: string }> {
try {
const d = await this.call<{ domains?: unknown[] }>('/cdn/domain/list.json', {});
const n = Array.isArray(d?.domains) ? d.domains.length : 0;
return { ok: true, detail: `${n} 个 CDN 域名` };
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
return {
ok: false,
error: msg,
hint: /签名|signature|auth|TOKEN/i.test(msg)
? 'AK/SK 不对或签名算法有变(多吉云 → 个人中心 → API 密钥)'
: undefined,
};
}
}
async deploy(cert: DeployCert, opts: DeployOptions): Promise<DeployResult> {
const log = opts.log || (() => {});
const details: string[] = [];
@@ -142,7 +166,8 @@ export class DogeCloudDeployer implements Deployer {
const certId = await this.uploadOrReuse(cert, opts.dogecloudDomains || [], log);
details.push(`证书 #${certId}`);
// ② 逐个域名绑定(★ 字段名是 cert_id,下划线)
// ② 逐个域名绑定(★ 字段名是 `id` —— 实测传 `cert_id` 会被服务端**无视**,
// 见本文件顶部「用假 id 999999 做对照实验」那段)
const domains = (opts.dogecloudDomains || []).map((s) => s.trim()).filter(Boolean);
if (!domains.length) {
log('多吉云:没有配置要绑定的域名,只上传不绑定');