/** * 只对**单个域名**做「签发 + 部署」,别的域名一律不碰。 * * 为什么需要它(2026-10-06 加): * 容器只有一个 `POST /renew`,而它调的是 `renewAll` —— **没有域名过滤**。 * 想单独把一个域名提前换掉时,`{force:true}` 会把配置里**所有**域名 * 一起重签一遍:多烧 2 个 CA 订单,还会把本来好好的 t-t.live / 200181.xyz * 一起换掉、增加无关的线上变更面。这个脚本把「只动一个域名」变成可选操作。 * * 与 `redeploy.mjs` 的分工: * · `redeploy.mjs` —— **复用已签好的证书**,只重跑部署(不碰 ACME) * · `renew-one.mjs` —— 真的去 CA **签一张新的**,然后部署 * * 用法: * docker exec cn-certkeeper node src/renew-one.mjs usj.cc * docker exec cn-certkeeper node src/renew-one.mjs usj.cc --no-deploy # 只签不部署 * docker exec cn-certkeeper node src/renew-one.mjs usj.cc --dry # 只看会做什么 * * ★ 默认 `force: true`(线上还剩 60 天也要换)—— 这正是本脚本的用途。 * 想走「按阈值判断」请直接调 /renew。 */ import path from 'node:path'; import { createRequire } from 'node:module'; import { fileURLToPath } from 'node:url'; import { FileKV } from './kv-file.mjs'; const HERE = path.dirname(fileURLToPath(import.meta.url)); const require = createRequire(import.meta.url); const lib = (n) => require(path.resolve(HERE, '../lib', `${n}.js`)); const argv = process.argv.slice(2); const NAME = argv.find((a) => !a.startsWith('--')); const DRY = argv.includes('--dry'); const NO_DEPLOY = argv.includes('--no-deploy'); if (!NAME) { console.error('用法:node src/renew-one.mjs <域名> [--no-deploy] [--dry]'); process.exit(2); } const kv = new FileKV(process.env.DATA_DIR || '/data'); const env = { RSS_KV: kv, TOKEN_SECRET: String(process.env.TOKEN_SECRET || '').trim(), // 留空 → 探针直接走本机 node:tls,不再绕 editor-api EDITOR_API_BASE: '', EDITOR_TOKEN: '', }; const { loadConfig } = lib('certstore'); const { issueDomain, RENEW_BEFORE_DAYS } = lib('certissue'); const cfg = await loadConfig(env); const d = cfg.domains.find((x) => x.name === NAME); if (!d) { console.error(`配置里没有域名「${NAME}」(现有:${cfg.domains.map((x) => x.name).join(', ')})`); process.exit(2); } console.log(`域名 ${NAME}`); console.log(` SAN : ${(d.san || []).join(', ')}`); console.log(` DNS 凭据 : ${d.dns}`); console.log(` 部署目标 : ${(d.deploy || []).join(', ')}`); console.log(` 1Panel 站点: ${(d.one_panel_sites || []).join(', ')}`); console.log(` 多吉云域名 : ${(d.dogecloud_domains || []).join(', ')}`); console.log(` 续期阈值 : ${RENEW_BEFORE_DAYS} 天(本脚本 force,忽略阈值)`); console.log(` 部署 : ${NO_DEPLOY ? '否(--no-deploy)' : '是'}`); if (DRY) { console.log('\n[dry] 不实际签发。'); process.exit(0); } const out = await issueDomain(env, d, { force: true, noDeploy: NO_DEPLOY, by: 'renew-one' }); console.log('\n=== 结果 ==='); console.log(JSON.stringify(out, null, 2)); if (!out.ok) process.exitCode = 1;