Files
blog/deploy/cn-certkeeper/src/redeploy.mjs
T

70 lines
2.9 KiB
JavaScript
Raw Normal View History

/**
* 只重跑「部署」这一步 —— 复用 KV 里**已经签好的**证书,不碰 ACME。
*
* 为什么需要它(2026-10-06 加):
* 签发的成败与部署的成败是**两件独立的事**。一旦部署侧出问题(1Panel 接口
* 改结构、站点名对不上、面板限流…),重新走 `/renew` 会**再签一张新证书**
* —— 白白消耗 CA 配额,而证书本身根本没出问题。
* 这个脚本直接把 KV 里的证书 + 配置里的部署目标重跑一遍。
*
* 用法:
* docker exec cn-certkeeper node src/redeploy.mjs t-t.live
* docker exec cn-certkeeper node src/redeploy.mjs t-t.live --dry # 只看会绑哪些站点
*/
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');
if (!NAME) {
console.error('用法:node src/redeploy.mjs <域名> [--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(), EDITOR_API_BASE: '', EDITOR_TOKEN: '' };
const { loadConfig, getCert, getAccess } = lib('certstore');
const { makeDeployer } = lib('deployer');
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);
}
const rec = await getCert(env, NAME);
if (!rec?.cert || !rec?.key) {
console.error(`KV 里没有「${NAME}」的证书内容(先跑一次签发)`);
process.exit(2);
}
console.log(`域名 ${NAME}:证书到期 ${new Date(rec.expireAt).toISOString()}(${Math.round((rec.expireAt - Date.now()) / 86400000)} 天)`);
console.log(`部署目标 ${(d.deploy || []).join(', ')};1Panel 站点 ${(d.one_panel_sites || []).join(', ')}`);
if (DRY) process.exit(0);
for (const target of d.deploy || []) {
const credName = target === '1panel' ? '1panel-cn' : target;
const cred = await getAccess(env, credName);
if (!cred) {
console.log(` ${target}: ★ 找不到凭据「${credName}」`);
continue;
}
try {
const dp = makeDeployer(cred);
const res = await dp.deploy(
{ domain: NAME, cert: rec.cert, key: rec.key, notAfter: rec.expireAt },
{ dogecloudDomains: d.dogecloud_domains, onePanelSites: d.one_panel_sites, log: (m) => console.log(` [${target}] ${m}`) },
);
console.log(` ${target}: 完成 —— ${res.details.join(';')}`);
} catch (e) {
console.log(` ${target}: ★ 失败 —— ${e instanceof Error ? e.message : e}`);
process.exitCode = 1;
}
}