From 36a3060cce70a0ead7fd6898eb897df058e248d0 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 27 Mar 2026 19:49:38 +0000 Subject: [PATCH] fix(dcrouter): re-trigger auto certificate provisioning after SmartAcme becomes ready --- changelog.md | 7 +++++ ts/00_commitinfo_data.ts | 2 +- ts/classes.dcrouter.ts | 56 +++++++++--------------------------- ts_web/00_commitinfo_data.ts | 2 +- 4 files changed, 22 insertions(+), 45 deletions(-) diff --git a/changelog.md b/changelog.md index 02f399c..7510c79 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-03-27 - 11.12.3 - fix(dcrouter) +re-trigger auto certificate provisioning after SmartAcme becomes ready + +- clear certificate provisioning scheduler state before retrying startup-affected routes +- use route updates to re-run certificate provisioning for all current auto-cert routes +- remove the unused single-route domain lookup helper + ## 2026-03-27 - 11.12.2 - fix(dcrouter) guard auto certificate reprovisioning against unnamed routes diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 079be58..7a03b92 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '11.12.2', + version: '11.12.3', description: 'A multifaceted routing service handling mail and SMS delivery functions.' } diff --git a/ts/classes.dcrouter.ts b/ts/classes.dcrouter.ts index e7b6d7c..c9bc160 100644 --- a/ts/classes.dcrouter.ts +++ b/ts/classes.dcrouter.ts @@ -389,34 +389,21 @@ export class DcRouter { this.smartAcmeReady = true; logger.log('info', 'SmartAcme DNS-01 provider is now ready'); - // Re-provision any certificates that failed during the startup window - // (before SmartAcme was ready — the certProvisionFunction returned 'http01' - // which fails because Rust ACME is disabled when certProvisionFunction is set) + // Re-trigger certificate provisioning for all auto-cert routes. + // During startup, certProvisionFunction returned 'http01' (SmartAcme not ready), + // but Rust ACME is disabled when certProvisionFunction is set — so all domains + // failed silently (SmartProxy doesn't emit certificate-failed for this path). + // Calling updateRoutes() re-triggers provisionCertificatesViaCallback internally, + // which calls certProvisionFunction again — now with smartAcmeReady === true. if (this.smartProxy) { - const failedDomains = [...this.certificateStatusMap.entries()] - .filter(([_, status]) => status.status === 'failed') - .map(([domain]) => domain); - - if (failedDomains.length > 0) { - logger.log('info', `Re-provisioning ${failedDomains.length} certificates that failed before SmartAcme was ready`); - // Clear backoff and status for failed domains — these failures were from the startup race - for (const domain of failedDomains) { - if (this.certProvisionScheduler) { - await this.certProvisionScheduler.clearBackoff(domain); - } - this.certificateStatusMap.delete(domain); - } - // Re-trigger provisioning for all auto-cert routes - const routes = this.smartProxy.routeManager.getRoutes(); - for (const route of routes) { - const tls = (route as any).action?.tls; - if (tls && tls.certificate === 'auto' && route.name) { - this.smartProxy.provisionCertificate(route.name).catch((err: any) => { - logger.log('warn', `Re-provision for route '${route.name}' failed: ${err?.message || err}`); - }); - } - } + if (this.certProvisionScheduler) { + this.certProvisionScheduler.clear(); } + const currentRoutes = this.smartProxy.routeManager.getRoutes(); + logger.log('info', `Re-triggering certificate provisioning for ${currentRoutes.length} routes`); + this.smartProxy.updateRoutes(currentRoutes).catch((err: any) => { + logger.log('warn', `Failed to re-trigger cert provisioning: ${err?.message || err}`); + }); } } }) @@ -1160,23 +1147,6 @@ export class DcRouter { return false; } - /** - * Find the first route name that matches a given domain - */ - private findRouteNameForDomain(domain: string): string | undefined { - if (!this.smartProxy) return undefined; - for (const route of this.smartProxy.routeManager.getRoutes()) { - if (!route.match.domains || !route.name) continue; - const routeDomains = Array.isArray(route.match.domains) - ? route.match.domains - : [route.match.domains]; - for (const pattern of routeDomains) { - if (this.isDomainMatch(domain, pattern)) return route.name; - } - } - return undefined; - } - /** * Find ALL route names that match a given domain */ diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 079be58..7a03b92 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '11.12.2', + version: '11.12.3', description: 'A multifaceted routing service handling mail and SMS delivery functions.' }