4.0 KiB
- this repo is dependent on letsencrypt and its limits
- to simpify the outside API, smartacme is stateful, meaning it works with a mongodb and a collection called 'SmartacmeCert'.
Certificate Request Behavior
As of v7.4.0, SmartAcme no longer automatically requests wildcard certificates for all domain requests. This change was made to fix issues with HTTP-01 only configurations which cannot validate wildcard domains.
- By default,
getCertificateForDomain('example.com')only requests a certificate forexample.com - To request both regular and wildcard certificates, use
getCertificateForDomain('example.com', { includeWildcard: true }) - Wildcard certificates require a DNS-01 challenge handler to be configured
- Direct wildcard requests like
getCertificateForDomain('*.example.com')only request the wildcard certificate
This change ensures HTTP-01 only configurations work properly while still allowing wildcard certificates when needed and supported.
ACME Protocol Implementation
As of v8.1.0, the acme-client npm package has been replaced with a custom OOP implementation under ts/acme/. This uses node:crypto for all cryptographic operations and @peculiar/x509 solely for CSR generation. The implementation follows RFC 8555.
Key files:
ts/acme/acme.classes.client.ts— Top-level facade (AcmeClient), accepts optionalloggercallbackts/acme/acme.classes.crypto.ts— Key gen, JWK, JWS signing, CSR (AcmeCrypto)ts/acme/acme.classes.http-client.ts— JWS-signed HTTP transport with nonce management and loggingts/acme/acme.classes.error.ts— StructuredAcmeErrorwith type URN, subproblems, Retry-After,isRetryable/isRateLimitedts/acme/acme.classes.account.ts— Account registrationts/acme/acme.classes.order.ts— Order lifecycle + pollingts/acme/acme.classes.challenge.ts— Key authorization + challenge completionts/acme/acme.classes.directory.ts— CA directory URL constants (ACME_DIRECTORY_URLS)
Usage in ts/plugins.ts: import * as acme from './acme/index.js' (replaces acme-client)
Concurrency & Rate Limiting (taskbuffer integration)
As of v9.1.0, @push.rocks/lik.InterestMap was replaced with @push.rocks/taskbuffer.TaskManager for coordinating concurrent certificate requests. This provides:
- Per-domain mutex (
cert-domain-mutex): Only one ACME issuance per TLD at a time, withresultSharingMode: 'share-latest'so queued callers get the same result without re-issuing. - Global concurrency cap (
acme-global-concurrency): Limits total parallel ACME operations (default 5, configurable viamaxConcurrentIssuances). - Account-level rate limiting (
acme-account-rate-limit): Sliding-window rate limit (default 250 orders per 3 hours, configurable viamaxOrdersPerWindow/orderWindowMs) to stay under Let's Encrypt limits. - Step-based progress: The cert issuance task uses
notifyStep()for prepare/authorize/finalize/store phases, observable viasmartAcme.certIssuanceEvents.
Key implementation details:
- A single reusable
Tasknamedcert-issuancehandles all domains viatriggerTaskConstrained()with different inputs. - The
shouldExecutecallback on the domain mutex checks the certmanager cache as a safety net. TaskManager.start()is called inSmartAcme.start()andTaskManager.stop()inSmartAcme.stop().- The "no cronjobs specified" log messages during tests come from taskbuffer's internal CronManager polling — harmless noise when no cron tasks are scheduled.
Dependency Notes
acme-clientwas replaced with custom implementation ints/acme/+@peculiar/x509for CSR generation@push.rocks/smartfile,@api.global/typedserver,@push.rocks/smartrequest,@push.rocks/smartpromisewere removed as unused dependencies in v8.1.0- The
@apiclient.xyz/cloudflareconveniencenamespace is deprecated but still functional. TheDns01Handleraccepts anIConvenientDnsProviderinterface which remains stable. - Test imports use
@git.zone/tstest/tapbundle(not@push.rocks/tapbundle) - Build uses
tsbuild(no flags needed, v4+)