The Automatic Certificate Management Environment (ACME) modules obtain, install, renew, and revoke Transport Layer Security (TLS) certificates. They implement the client side of RFC 8555 and work with Let's Encrypt or another compatible ACME service. The modules are shared by the Barracuda App Server (BAS), Mako Server, and Xedge.
Most applications use acme/runtime. It connects the ACME protocol engine to writable storage, coordinates certificate installation, and uses one of these validation methods. Mako and Xedge automatically install certificates in their standard BAS HTTPS listeners:
| Validation method | Use it when | What must be reachable |
|---|---|---|
| HTTP-01 | The ACME service can connect directly to the server by its public domain name. | The server's HTTP challenge endpoint. |
| Automatic DNS-01 | The server is on a private network and a SharkTrust portal manages its DNS record. | The portal over outbound HTTPS. |
| Manual DNS-01 | An operator can create the required DNS TXT record. | The public DNS record. The server still needs outbound HTTPS access to the ACME service. |
Automatic DNS-01 is the most common choice for memory-constrained, deeply embedded systems. It works with Xedge or with an application built directly from the Barracuda App Server libraries, and it does not require the device to accept a public inbound connection.
Start with staging. The examples select the Let's Encrypt staging service with
production=false. Staging certificates are not trusted by browsers, but staging lets you test without consuming production rate limits. Change the setting totrueonly after the complete flow works.
The three examples run as shown on Mako Server and Xedge. The runtime selects the host's writable I/O automatically and installs certificates in the standard ba.slcon and ba.slcon6 HTTPS listeners. An application that embeds the BAS library directly must supply an io option and the install callback described under Runtime.create(). You can also supply these options on Mako or Xedge when using different storage or HTTPS listeners.
Each example's notify(code) function receives the numeric lifecycle code. The examples omit application-specific event handling and error reporting. Do not log private keys, SharkTrust credentials, zone secrets, proof values, or authorization headers.
Use the same configuration table on Mako, Xedge, or a custom BAS host. Omitting challenge selects HTTP-01. The certificate authority must reach the device on public TCP port 80.
local runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"device.example.com"},
production = false
},
notify = function(code) trace("ACME event ", code) end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem)
-- Report a failure through the application's normal error handling.
end)
A SharkTrust portal publishes and removes the TXT record. When credentials are omitted, the shared DNS module uses the host's compiled etokengen or tokengen identity.
local runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"controller"},
production = false,
namePolicy = "exact",
challenge = {type="dns-01", dns="local"}
},
notify = function(code) trace("ACME event ", code) end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem) end)
For an explicit identity, set challenge.portalUrl, challenge.zoneKey, and challenge.proof(message) together. The client does not accept a secret option. A host callback calculates the proof from provisioned credentials. Keep credentials outside the application ZIP and source repository. The configuration fields are described below.
The runtime uses the first domain as the requested device name, then manages the name assigned by the portal. It stores registration with the ACME state unless the host supplies a custom store. Local IPv4 discovery is automatic; forward later address changes with runtime:setIpAddress(newIpAddress, callback).
Manual mode pauses issuance until an operator publishes the TXT record. It uses the same constructor; no separate adapter setup is required.
local runtime, err
runtime, err = require"acme/runtime".create {
config = {
acceptTerms = true, -- After accepting the provider's terms.
email = "operator@example.com",
domains = {"device.example.com"},
production = false,
challenge = {type="dns-01", mode="manual"}
},
notify = function(code)
if code == 32 then
local record = runtime.challenge:status()
print("Create TXT record:", record.recordName, record.recordData)
end
end
}
assert(runtime, err and (err.message or err.code))
runtime:start(function(result, problem) end)
After a public DNS lookup returns the exact TXT value, continue the pending operation:
local challenge = runtime.challenge
if challenge:status().phase == "publish" then
challenge:continue(function(ok, problem)
-- Validation continues asynchronously after the operator confirms DNS.
end)
end
The operator removes the TXT record after validation. Use runtime.challenge:cancel() to cancel the pending publication step.
Call runtime:close(callback) during application unload. It cancels owned work, removes an active challenge when possible, closes network clients, and prevents new operations. On a device that starts before its clock is valid, wait for the clock synchronization event before calling start(). Certificate validation and HTTPS server trust checks require a correct clock.
Mako users can configure the same runtime in mako.conf. Xedge users normally configure it in the Xedge certificate user interface.
| Public module | Use it for |
|---|---|
acme/runtime | The normal entry point for startup, certificate management, and shutdown. createManager() exposes certificate management separately for custom hosts. |
acme/dns | Automatic and manual DNS-01. createClient() exposes direct SharkTrust enrollment, DNS commands, address updates, and reverse connections. |
acme/engine | ACME protocol operations, renewal information, software and TPM keys, and HTTP-01 challenges. |
The package contains five ACME modules. acme/_util provides shared transport and storage functions; acme/_server installs certificates in BAS listeners. These two modules are private host implementation details. The former manager, SharkTrust, logging, and separate engine-helper modules are no longer packaged.
The modules require the auxiliary Lua bindings, an HTTPS client with a trusted Certificate Authority (CA) store, a valid system clock, and private writable storage. A BAS build that creates software keys and certificate signing requests must enable these SharkSSL options:
#define SHARKSSL_ENABLE_ASN1_KEY_CREATION 1 #define SHARKSSL_ENABLE_RSAKEY_CREATE 1 #define SHARKSSL_ENABLE_ECCKEY_CREATE 1 #define SHARKSSL_ENABLE_CSR_CREATION 1
Add missing definitions to the platform's inc/arch/[platform]/TargConfig.h or compiler options. RSA certificate keys also require RSA support in the SharkSSL build. Mako Server and Xedge packages that include the ACME plugin provide the required integration.
Asynchronous methods use callback(result, err). On success, result contains a value and err is nil. On failure, result is nil and err is a structured error table. A storage load() callback may return nil, nil to mean that no saved state exists.
{
code = "bad_nonce",
message = "The ACME server rejected the replay nonce",
temporary = true,
status = 400,
type = "urn:ietf:params:acme:error:badNonce",
detail = "...",
retryAfter = 15,
operation = "newOrder",
url = "https://acme.example/directory/new-order"
}
temporary is true.phase is request, write, or read.A method may return nil, err before it starts, usually because an argument is invalid or the object is closed. After an asynchronous operation starts, its callback is invoked once. Transport errors can include cause and phase, where the phase is request, write, or read.
Lua callers must supply the documented argument types, supported option values, and callbacks. Internal calls do not repeat every argument or interface check. Incorrect Lua API use is a programming error; do not depend on an invalid_* result for every malformed argument. Network responses, persisted credentials, service identity, terms acceptance, and operation lifecycle still receive the required checks.
Constructors that accept notify call notify(code) with one integer and no event table. Use the code to refresh a user interface or write an application log. The callback is optional, returns no value, must return promptly, and must not yield. A Lua error in this callback is contained and traced.
| Integer code | Meaning |
|---|---|
1 | Certificate management starting. |
2 | Certificate management ready. |
3 | Startup attempt failed. The start completion callback supplies its error. |
4 | Startup retry scheduled. |
10 | Device enrollment starting. |
11 | Device enrolled. |
12 | Saved registration being restored. |
13 | Registration confirmed. |
20 | Reverse connection enabled. This does not mean it is connected. |
21 | Reverse connection disabled. |
30 | Automatic DNS TXT record published; propagation wait starting. |
31 | Automatic DNS TXT record successfully removed. |
32 | Manual DNS TXT publication required. Read the manual adapter status for the record name and value. |
40 | Certificate issued and saved; installation follows. |
41 | Certificate renewed and saved; installation follows. |
42 | Certificate revocation accepted and local record removed. |
50 | ACME service profile committed. |
Ignore unknown future codes. Notifications carry no domain, retry delay, error text, or credential. Use runtime:status() for an operational snapshot and completion callbacks for operation results. In a multi-domain application, a certificate event signals that the domain status should be refreshed. For code 32, read challenge:status() for the TXT record, then call continue() or cancel() through the host interface.
local service = {
production = false,
productionUrl = "https://acme.example/production/directory",
stagingUrl = "https://acme.example/staging/directory",
http = {
proxy = "proxy.example.com",
proxyport = 8080,
shark = trustedSharkSslClient
}
}
The service table selects the ACME directory:
The selected directory URL identifies an ACME account and certificate profile. Staging and production state are kept separate. Changing the active directory through the manager or runtime uses a transactional service switch, described under manager:switchService().
acme/runtimeacme/runtime is the recommended high-level API. It creates an engine and manager, selects the HTTP or DNS challenge adapter, restores saved state, starts renewal, and closes the owned objects in the correct order.
Creates the high-level certificate runtime. Use this constructor for normal application integrations. Mako and Xedge configuration users do not call it because those hosts create the runtime automatically.
local Runtime = require"acme/runtime" local runtime, err = Runtime.create(options)
Parameters
home; standalone Xedge defaults to disk. Xedge's built-in integration passes its selected I/O explicitly.install(records, callback) activates the complete certificate set. Mako Server and Xedge provide a default for their standard HTTPS listeners. Supply this function when embedding BAS directly or when any host uses custom listeners.acme table.load(callback) and save(state, callback) functions. Automatic DNS uses sharktrust.json below the runtime's storage directory when this option is omitted. See SharkTrust state storage.type, present, and cleanup. Used when config.challenge does not select a built-in DNS mode.io. The default is acme.notify(code) receives one numeric lifecycle code.renewAllowed(domain, expiresAt) is called before a scheduled renewal. domain is a string and expiresAt is the certificate expiration as a numeric Unix timestamp in seconds, or nil if unavailable. No certificate or private key is passed. Return false to defer the renewal for one hour. Any other return value permits it. Forced renewal ignores this callback. The callback must not throw; its Lua errors propagate and interrupt scheduled renewal processing.Return values
Throws
The listed validation failures return errors. Incorrect field types or missing required nested fields can raise Lua errors. Errors from supplied components and native setup can propagate. Most configuration and key validation occurs later during startup.
Pass this table as options.config on every host, or as acme in mako.conf. Direct Lua callers supply the documented types. Host UI input validation stays at the UI boundary.
The optional challenge table selects type="dns-01" (string). Its optional mode is automatic (default) or manual (string). Automatic mode accepts portalUrl (HTTPS string), zoneKey (64-character hex string), and proof(message) (required function returning 32 binary bytes for a string message). See the proof callback contract. Omit the identity fields to use the compiled identity. Optional dns is local (default), wan, or both (string); reverse is a boolean defaulting to false; propagationDelay is seconds (number, default 30, zero allowed). Manual mode needs only type and mode.
The manager calls this function whenever its active certificate set changes. Replace a non-empty set atomically if possible. An empty records array means the manager has no certificates to supply; the host determines how to handle its existing HTTPS listeners. Mako and Xedge applications normally omit this callback because their standard HTTPS listeners use the built-in installer.
The built-in installer intentionally leaves the currently installed certificates in place when records is empty. It does not switch to the self-signed default. Thus removing or revoking the last managed certificate does not immediately stop the listeners from presenting it. The installed set remains until another non-empty set replaces it or the host restarts. A custom installer must define its own empty-set behavior.
local function installCertificates(records, callback) -- Convert each record for the platform and replace the active TLS set. -- Call callback only after every record is active, or after the update fails. callback(true, nil) end
Parameters
Return values
The installer's direct return values are ignored. Completion must use callback, synchronously or asynchronously. The manager remains busy until completion; it does not interpret a direct nil, err return as failure.
Throws
Installer exceptions and callback-reported failures become certificate_install_failed error tables. For a table error, the manager keeps its message; other error fields are not forwarded. Duplicate completion calls are ignored. An exception after completion does not replace the completed result.
The client discovers the local IPv4 address used for the portal connection and sends it during enrollment. The application supplies only the naming, DNS publication, and descriptive fields below.
The registration table supplies SharkTrust enrollment data:
{
name = "controller",
namePolicy = "exact",
dns = "local",
info = "BAS controller"
}
exact rejects an unavailable requested name. increment permits a numbered alternative. An explicit name defaults to exact.local, wan, or both. The default is local. See Selecting the Published Address.Starts certificate management. Call this once after storage, networking, DNS, and the system clock are ready. It restores saved certificates and SharkTrust registration, enrolls when needed, obtains missing certificates, and starts renewal.
Parameters
result is a table whose boolean started member is true when this call started the runtime or false when it was already running. A new or changed service profile adds table switch with boolean changed, boolean reused, and number rebuilt. A non-fatal registration check can add table warning containing the structured error. On failure, result is nil and err is the error table.The method is idempotent. A retryable startup transport error is returned to the callback and retried in the background. The delay starts at 30 seconds, doubles after each failure, and stops increasing at five minutes. Certificate trust errors and ambiguous enrollment results are not retried automatically.
Return values
Throws
Reported storage, enrollment, issuance and installation failures use the callback. Completion callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Checks the current device registration with SharkTrust and refreshes the portal with the automatically discovered local IPv4 address. Use it for diagnostics or a registration-status user interface. Normal startup performs this work automatically.
Parameters
result contains boolean registered and may contain string deviceId and string name when registered. With the built-in DNS client, string sockname is the local IPv4 address of the connection to the portal. Without a SharkTrust configuration, err.code is sharktrust_not_configured.Return values
Throws
Reported storage and portal failures use the callback. Callback errors are caught and traced. Errors raised by supplied components can propagate.
Checks whether a requested SharkTrust device name appears available. Use it only as an advisory user-interface check. Enrollment performs the authoritative check and can still report a conflict.
Parameters
result is {available=boolean, name=string}, where name is the normalized full name.Return values
Throws
Reported portal failures use the callback. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Updates the local IPv4 address stored by the SharkTrust portal and refreshes the device's DNS A record. Use it after startup when DHCP or another network event reports that the device address changed. Startup discovery and the first update are automatic.
Parameters
192.168.1.20.result is the portal acknowledgement table. Without a SharkTrust configuration, err.code is sharktrust_not_configured.Return values
Throws
Reported storage and portal failures use the callback. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Changes the SharkTrust reverse-connection state immediately. Use it when an application lets an operator enable or disable portal-assisted remote access after startup.
Parameters
Return values
Throws
Reported configuration and proof failures return nil, err. Native reverse-connection option errors and exceptions from supplied components can propagate.
Moves certificate management to another ACME directory. Use it to change between staging and production or to select another compatible provider. Existing certificates stay installed until the new profile is ready. SharkTrust registration does not change.
Parameters
boolean production.result contains boolean changed, boolean reused, and, when rebuilding, number rebuilt.Return values
Throws
Uses the exception and error-reporting behavior documented for manager:switchService().
Immediately requests a replacement certificate even when the current certificate is not near expiration. Use it for an operator-requested renewal or after a certificate-related policy change. Scheduled renewal needs no application call.
Parameters
result is the new certificate record. The current certificate remains installed until replacement succeeds.Return values
Throws
Uses the exception and error-reporting behavior documented for manager:renew().
Returns an operational snapshot for status pages, diagnostics, and health checks. The built-in components do not include private keys or device credentials.
Parameters
None. Additional arguments are ignored.
Return values
{
loaded = true,
started = true,
closed = false,
starting = false,
retryPending = false,
operation = nil,
directoryUrl = "https://acme.example/directory",
domains = {},
jobs = {},
lastError = nil,
retryAt = nil,
registration = challengeStatusOrNil,
reverse = {enabled=true, connected=true, status=202, connections=3}
}
close() prevents further work.expiresAt, renewAt, and optional ARI fields.{enabled=boolean, connected=boolean, status=number, connections=number}.Throws
Exceptions raised by an underlying status method, including a custom challenge adapter's status() method, propagate. Lua allocation errors can also propagate.
Stops certificate management and releases owned resources. Call it during application unload. It closes the manager and challenge adapter and cancels owned work.
Parameters
Repeated close calls succeed immediately, without waiting for an earlier close to finish or retrying cleanup. Their callbacks receive true, nil.
Return values
If a custom certificate installer or automatic DNS registration operation is still pending, returns nil, err (string) with err equal to "busy". Registration operations include loading or saving state, enrollment and identity switching. Shutdown has not begun: both components remain open, timers are unchanged, and the supplied close callback is not called. Retry close after the operation finishes. The built-in installer completes synchronously.
Throws
Reported cleanup failures go to the callback as nil, err. Errors raised by the completion callback are caught and traced. A custom challenge adapter must follow its callback contract; an exception from its close() method is not converted to a cleanup error result.
runtime.challenge contains the selected challenge adapter. Most applications do not use it directly. A manual DNS user interface uses it to call status(), continue(), or cancel().
acme/dnsacme/dns creates DNS-01 challenge adapters. Use createSharkTrust() for automatic DNS updates or createManual() for an operator-assisted flow.
Creates a DNS-01 challenge adapter that uses SharkTrust to publish TXT records and persists the device registration. Runtime.create() calls this constructor automatically when config.challenge selects automatic DNS-01. Call it directly only when assembling an engine and manager without the runtime.
local Dns = require"acme/dns"
local challenge, err = Dns.createSharkTrust {
client = sharkTrustClient,
store = {
load = function(callback) callback(savedState, nil) end,
save = function(state, callback) callback(true, nil) end
},
propagationDelay = 30,
notify = function(code) end
}
Parameters
function load(callback) and function save(state, callback), described below.Return values
Throws
Incorrect options or a missing/incompatible client can throw. Store callbacks are used later; exceptions from store.load and store.save are converted to storage_read_failed and storage_write_failed errors.
The adapter calls store.load and store.save as plain functions, without an implicit self argument. Both functions must call their callback exactly once:
Parameters
Return values
Ignored. Report completion exactly once through callback.
Throws
Exceptions are caught and reported as storage_read_failed. Callback-reported errors use the same code, with the supplied message. Errors raised after completion do not replace the result.
Parameters
Return values
Ignored. Report completion exactly once through callback. The adapter serializes saves and retains failed state for a later resume() retry.
Throws
Exceptions and callback-reported errors become storage_write_failed errors with the supplied message. Other table error fields are not forwarded. Duplicate completions and exceptions after completion do not replace the result.
callback(state, nil) -- load: state was found callback(nil, nil) -- load: no state exists callback(nil, err) -- load: read failed callback(true, nil) -- save: durable commit completed callback(nil, err) -- save: commit failed
save() must not report success until the data is durably committed. A filesystem implementation can write a temporary file and rename it. The adapter serializes save operations.
{
version = 2,
portalUrl = "https://portal.example.com/sharktrust.lsp",
zoneIdentity = "<opaque-non-secret-fingerprint>",
deviceId = "0123456789abcdef0123",
name = "controller.example-zone.com",
credential = "<64-lowercase-hexadecimal-characters>",
updatedAt = 1788105600
}
The credential is secret. Protect it with the strongest storage available on the target. Do not place this state in an application ZIP, source repository, public resource, log, or diagnostic download. The adapter rejects malformed state and state belonging to another portal or zone identity.
Direct returns acknowledge submission; callbacks report completion and may run before the method returns. Use the runtime methods for ordinary application code.
Registers the device and saves its assigned identity.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Performs an advisory name-availability check; enrollment makes the final decision.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Loads and validates saved registration state. Concurrent loads share the same pending read.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Confirms saved registration with the portal and persists a changed assigned name. First retries a pending failed state save.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Checks registration and updates the portal with the automatically discovered local IPv4 address.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Updates the registered local IPv4 address after a network-address change.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Reads the public IPv4 address observed by the portal.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Replaces the portal client. Changing the portal or zone identity requires enrollment and persistence before replacing the active registration.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Publishes the TXT record and waits for the propagation delay. Called by the ACME engine.
Parameters
Return values
Throws
Callback errors are caught and traced. Reported storage or portal failures use the callback. Errors from incorrect arguments or supplied client/timer implementations can propagate.
Reads a non-secret status snapshot.
Parameters
None.
Return values
Throws
Does not throw for valid adapter state.
See the separate cleanup() and close() contracts below.
Clears the active challenge and cancels its propagation timer. A pending present() callback receives nil and an error table with code challenge_cancelled. When registration state exists, cleanup requests removal of the TXT record.
Parameters
Return values
Throws
Removal failures are reported through the callback. Errors from the pending present() callback or completion callback are caught and traced. Incorrect use of a supplied client or timer may throw.
Cancels the pending challenge and its propagation timer. If a registration and active challenge exist, it attempts to remove the TXT record before closing the client. Client cleanup proceeds even when record removal fails.
Parameters
Return values
After shutdown has started, repeated calls return no values and invoke the supplied callback immediately with true, nil. They neither wait for the first call nor retry failed cleanup.
Throws
Reported removal and close failures are delivered to the callback. Completion callback errors are caught and traced. A supplied client must implement the documented methods and callback contracts; errors from incorrect client usage are not converted to cleanup error results.
switchIdentity() is required when the portal URL, zone key, zone secret, or generated proof identity changes. Without explicit re-enrollment permission, it returns sharktrust_identity_change_requires_reenrollment. An ACME production or staging change does not change SharkTrust identity.
challenge:switchIdentity(
{client = newClient},
{
reenroll = true,
enrollment = {
name = "controller",
namePolicy = "exact",
dns = "local",
info = "BAS controller"
}
},
function(result, err)
-- result.changed is true when the identity was replaced.
-- result.state contains the newly saved registration state.
end)
Creates an operator-assisted DNS-01 adapter. Use it when the application cannot update DNS automatically and can show the TXT record to an operator.
local challenge = Dns.createManual {
-- Code 32 tells the host to read challenge:status() and display the TXT record.
notify = function(code) end
}
Parameters
status().Return values
Throws
Throws if options cannot be used as an options table. Notification callback errors are caught and traced when a notification is delivered.
The manual adapter implements present(context, callback) and cleanup(context, callback) for the engine. Application code uses these methods:
Returns the information needed to display the pending DNS record.
Parameters
None.
Return values
Throws
Does not deliberately throw for a valid adapter and challenge context.
Continues validation after the operator confirms that the TXT record is publicly visible.
Parameters
Return values
Throws
No pending action is reported as an error result. Errors raised by the engine or completion callback are caught and traced.
Cancels the pending operator action and returns the adapter to idle. The engine's pending present() callback receives nil and an error table with code challenge_cancelled.
The old action is cleared before its callback runs, so a callback can cancel again or start a new action without notifying the old action twice.
Parameters
Return values
Throws
Errors raised by the engine or completion callback are caught and traced.
Closes the adapter and cancels any pending action. Later engine present() calls fail with adapter_closed. Repeated close calls succeed.
Parameters
Return values
Throws
Errors raised by cancellation or completion callbacks are caught and traced.
The module does not send email. A host may display the manual adapter status in a user interface or forward it through its own email service.
The manager in acme/runtime owns persistent ACME state, certificate installation, renewal scheduling, revocation, and service profiles. Most applications should use acme/runtime. Use the manager directly only when the application must assemble these responsibilities separately from SharkTrust or other runtime services.
The manager is a lower-level API and therefore always requires a certificate installer. In the example, installCertificates is the host function defined by the certificate installation callback contract. Mako and Xedge automatic installation applies to Runtime.create(), not to a manager constructed directly.
local Runtime = require"acme/runtime"
local manager, err = Runtime.createManager {
io = writableIo,
engine = engine,
install = installCertificates, -- host callback described above
notify = function(code) end,
renewAllowed = function(domain, expiresAt) return true end,
path = "acme"
}
Parameters
domain is a string and expiresAt is the certificate expiration as a numeric Unix timestamp in seconds, or nil if unavailable. No certificate or private key is passed. Return false to defer renewal for one hour. Any other result permits it. Forced renewal ignores this callback. The callback must not throw; its Lua errors propagate and interrupt scheduled renewal processing.io. The default is acme.Return values
Throws
A missing or incorrectly typed options argument can throw. Incorrect path types can throw during construction; I/O, engine and callback interfaces must satisfy their documented contracts and are used later.
Sets the desired domains, ACME service, challenge adapter, and certificate-key policy. Call it before start() when using the manager directly. Calling it does not contact the ACME service.
local ok, err = manager:configure {
email = "operator@example.com",
domains = {"device.example.com"},
acceptTerms = true,
service = {production = false},
challenge = challengeAdapter,
key = {type = "ecc", curve = "SECP384R1"},
cleanup = true,
timeout = 600,
dnsResolveTimeout = 30,
fallbackRenewBefore = 22 * 24 * 60 * 60
}
boolean production.string type, function present(context, callback), and function cleanup(context, callback). Omit it for the built-in HTTP-01 adapter.string type is ecc (default) or rsa; string curve defaults to SECP384R1 for ECC; number bits defaults to 2048 for RSA.Runtime.create() passes its configured value.Parameters
Return values
Throws
Configuration validation failures use the error results above. Supply the documented types and ordinary configuration tables; values that cannot be copied or used by the configured components may raise Lua errors. Errors from later operations are reported by those operations.
Certificate key type defaults to Elliptic Curve Cryptography (ECC) on curve SECP384R1. Set key.type="rsa" and optionally key.bits for RSA. ECC keys automatically use the platform TPM when its key interface is available; otherwise they are created as software keys. RSA keys are always software keys. fallbackRenewBefore defaults to 22 days and cannot be less than one hour.
cleanup=true removes saved certificate entries for domains no longer configured. Direct manager use defaults to no cleanup.
Loads saved state and installs the active certificate set without contacting an ACME service. Repeated calls reinstall the loaded active profile without reading storage again. The runtime calls this during startup.
Parameters
Return values
Throws
Installer exceptions are converted to certificate_install_failed errors. Completion callback errors are caught and traced. Incorrect use of a supplied storage or scheduling interface may throw.
Loads saved state if needed, obtains missing or expired certificates, installs the active set and enables renewal. Call after configure().
Parameters
Return values
If stop() is called while startup is loading state, that startup cannot later enable renewal. Its callback receives nil, err with code manager_stopped. close() similarly prevents the pending startup, with code manager_closed. Pending storage and installation work is allowed to finish. A subsequent explicit start() can resume a stopped manager.
Throws
Reported storage, issuance and installation failures use the callback. Installer exceptions become certificate_install_failed errors. Completion callback errors are caught and traced. Incorrect configuration or supplied components may raise Lua errors.
Stops the automatic renewal timer while leaving explicit management methods available. This does not cancel work already in progress, but a pending startup cannot re-enable renewal after this call. Use close() for shutdown.
Parameters
Return values
Throws
Callback errors are caught and traced. Incorrect use of a supplied timer interface may throw.
Changes the active ACME directory and its account/certificate profile. Switching to the same directory updates the service settings without rebuilding certificates.
Parameters
Return values
The manager retains the previous active profile until installation and persistence succeed. If saving the active-profile selection fails after installation, it asks the installer to restore the previous set. An unsuccessful restoration is reported in err.rollback (table). The host's installer determines the effect of partial installation and empty sets.
Throws
Reported preparation, storage and installation failures use the callback. Installer exceptions become certificate_install_failed errors. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Checks or forces renewal of one managed certificate, then installs the current set.
Parameters
Return values
Throws
Reported issuance, persistence and installation failures use the callback. Installer exceptions become certificate_install_failed errors; completion callback errors are caught and traced. Incorrect options or supplied components may raise Lua errors.
Requests revocation, removes the saved record, persists the profile, and passes the remaining set to the installer. Removing the last record retains the installed certificates when using the built-in installer.
Revocation does not remove the domain from configuration. If the domain remains configured, a later startup can obtain a new certificate because its saved record is now missing. Remove the domain from the host configuration as well if the host should stop managing certificates for that name.
Parameters
Return values
Throws
Reported service, storage and installation failures use the callback. Installer exceptions become certificate_install_failed errors; completion callback errors are caught and traced. Incorrect options or supplied components may raise Lua errors.
Returns an operational snapshot without certificate private keys.
Parameters
None.
Return values
Renewal dates may be more than 49.7 days away. The manager splits long waits into timer intervals of at most 4294967295 milliseconds and checks the due dates again after each interval. An intermediate wakeup does not renew a certificate before its scheduled date.
Throws
No error for a valid manager and supported engine. Errors from a supplied engine's jobs() method propagate.
Reads managed certificate records, including private keys. Use status() for public diagnostics.
Parameters
None.
Return values
Throws
Does not throw for valid managed records.
Parameters
Return values
Throws
Does not throw for a valid domain argument and managed record.
Parameters
None.
Return values
Throws
Does not throw for a valid managed account.
Stops the renewal timer and closes the engine. Call during shutdown when using the manager directly.
Parameters
Return values
While a certificate installer is pending, returns nil, err (string), where err is "busy". The manager remains open, its timer is unchanged, and the close callback is not called. The caller must retry after installation finishes. No close retry is queued internally.
Throws
Reported engine close failures are passed to the callback. Completion callback errors are caught and traced. Incorrect use of a supplied engine or timer may throw.
domains(),certificate(), andaccount()return trusted management data that can include private keys. Do not use these values as status or logging data.
-- Certificate record returned by manager accessors
{
domain = "device.example.com",
privateKey = privateKey,
certificate = pemCertificateChain,
expiresAt = unixTime,
renewAt = unixTime,
ariCheckAt = optionalUnixTime,
ariId = optionalAriIdentifier,
explanationUrl = optionalUrl,
orderUrl = "https://acme.example/order/123",
directoryUrl = "https://acme.example/directory",
issuedAt = unixTime
}
The manager uses ACME Renewal Information (ARI) when the service advertises RFC 9773 support. Otherwise, it schedules renewal from the certificate expiration time with a small random offset. Retryable renewal failures back off from 30 seconds to five minutes. A permanent failure is checked again after six hours.
A scheduled check remains busy until certificate installation completes. Installation failure is recorded in status().lastError (table), with code certificate_install_failed, and retried after six hours under the existing non-temporary error policy. The retry installs the saved certificate set; it does not request another certificate unless renewal is due. If renewal or refresh also failed, its error remains primary and lastError.install (table) contains the installation error. A successful retry clears retryAt; lastError remains the most recent recorded failure.
Dns.createClient() creates the low-level SharkTrust device client. It handles device enrollment, authenticated portal commands, DNS updates, and reverse connections. It is not an ACME client and does not persist credentials. Most applications use acme/runtime, which creates this client and the persistent DNS adapter automatically.
Resolves portal identity without making a network request.
createClient() calls this resolver automatically.
Parameters
createClient(). Defaults to an empty table.Return values
Otherwise, returns a copy of options with portalUrl (string, prefixed with https://), zoneKey (hexadecimal string), and proof (function) from the compiled identity module. It first loads etokengen, falling back to tokengen only if that load fails. If neither loads, or the selected module lacks a proof function, returns nil, err (table) with code sharktrust_not_configured. Keep the resulting identity and proof callback private.
Throws
Incorrect option types or an incompatible compiled identity module may throw. Errors raised by the selected module's info() function propagate. Missing compiled identity support is reported as nil, err.
Creates a client for one SharkTrust portal and zone. Omit the identity fields, or the entire options table, to use the compiled identity through Dns.identity(). Call it directly only when an application needs low-level SharkTrust operations or when constructing Dns.createSharkTrust() without the runtime.
local Dns = require"acme/dns"
local client, err = Dns.createClient {
portalUrl = "https://portal.example.com/sharktrust.lsp",
zoneKey = "<64-hexadecimal-character-zone-key>",
proof = hostProof, -- host callback described below; no secret option
credential = savedDeviceCredential,
http = httpOptions,
reverse = reverseOptions
}
Parameters
/sharktrust.lsp endpoint. Other paths, queries, fragments, and non-HTTPS URLs are rejected.proof(message) receives a binary-safe string and must return a 32-byte binary Hash-based Message Authentication Code (HMAC). Use a generated or hardware-backed function when the zone secret should not be exposed to Lua. It is synchronous and must not yield. There is no secret option.setCredential().ba.revcon. The client supplies the portal URL and authentication headers.The optional reverse table accepts these native reverse-connection settings. The SharkTrust client supplies url and the authentication headers:
ba.sharkclient().Return values
Throws
Proof callback errors are caught and reported as proof_failed. Incorrect option types, compiled-identity interfaces or native hashing setup can raise Lua errors.
The host supplies proof(message), a synchronous function accepting the exact binary-safe string to authenticate, including any NUL bytes. It must return a 32-byte binary HMAC-SHA-256 result and must not yield. The client constructs the message and base64url-encodes the result for X-SharkTrust-Proof. Do not change the message or encode the result in the callback. The client neither receives the zone secret nor derives its proof key.
A compiled tokengen.proof or etokengen.proof function can be supplied directly. For host-provisioned secrets, this helper recalculates the key on each call:
-- Capture globals during mako.conf evaluation for later callback calls.
local ba,string,tonumber=ba,string,tonumber
local function makeProof(zoneKey,secret)
return function(message)
local salt=zoneKey:gsub("%x%x",function(pair) return string.char(tonumber(pair,16)) end)
local key=ba.crypto.PBKDF2("sha256",secret:upper(),salt,1000,32)
return ba.crypto.hash("hmac","sha256",key)(message)(true,"binary")
end
end
makeProof(zoneKey, secret) is an illustrative host helper, not a client API. Both required arguments are strings of exactly 64 hexadecimal characters, with no defaults. It returns the callback. Assign hostProof=makeProof(zoneKey, zoneSecret), where zoneSecret is the host-provisioned secret string. Capture globals during mako.conf evaluation as shown: its loader removes the global fallback before later callback calls.
PBKDF2-HMAC-SHA-256 takes the secret's 64 uppercase ASCII characters as its password, the hex-decoded 32-byte zone key as its salt, 1000 iterations, and 32 output bytes. Do not hex-decode the secret. The callback returns HMAC-SHA-256 of the unchanged message using that derived key. Recalculation costs more CPU than deriving once; the helper retains only the host-provided credentials between calls.
The host supplies its configuration and callback again on startup. The core does not persist them. Xedge's settings UI retains its own encrypted credential configuration and supplies a callback internally. Portal-issued device credentials and ACME account/certificate state still require persistence.
| Method | Arguments and result | When to use it |
|---|---|---|
client:isAvailable(name, callback) | See the typed contract below. | Use for an advisory name check before enrollment. It does not reserve the name. |
client:enroll(request, callback) | See the typed contract below. | The DNS adapter normally calls this and persists the result. Call it directly only if the application owns credential persistence. |
client:isRegistered(callback) | See the typed contract below. | Use to confirm a saved device registration. The runtime and DNS adapter perform this during startup. |
client:setIpAddress(ipAddress, callback) | See the typed contract below. | Use after startup when DHCP or another network event reports that the device address changed. Normal startup reports the initial address automatically. |
client:setAcmeRecord(request, callback) | See the typed contract below. | Normally not called directly. The SharkTrust DNS adapter calls it while handling challenge:present(). |
client:removeAcmeRecord(callback) | See the typed contract below. | Normally not called directly. The SharkTrust DNS adapter calls it during challenge cleanup. |
client:getWan(callback) | See the typed contract below. | Use only when the application must display or inspect the portal-observed public address. |
client:reverseConnection([enable]) | enable is an optional boolean and defaults to true. Returns true when applied, or nil followed by table err. | Use to start or stop portal-assisted remote access. Runtime users should call runtime:reverseConnection(). |
client:reverseStatus() | Returns the reverse-connection status table described below. | Use for a reverse-connection status display or diagnostic check. |
client:credential() | Returns the current secret device credential string or nil. | Normally not called directly. The persistent DNS adapter reads it while managing registration state. |
client:setCredential(credential) | credential is nil to clear it or a 64-character hexadecimal string. Returns true, or nil followed by table err. It does not persist the value. | Normally not called directly. The persistent DNS adapter restores and clears credentials. |
client:identity() | Returns a copy of the portal identity described below. | The DNS adapter uses this to reject state from another portal or zone. It may also be used for non-secret diagnostics. |
client:close(callback) | callback(result, err) is optional. It receives true after active operations finish. The method clears credential and proof references and closes reverse and HTTP clients. | Call during shutdown when using the client directly. The runtime and DNS adapter close owned clients automatically. |
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
Throws
Reported transport, portal and proof failures use the callback. Proof callback errors become proof_failed; completion callback errors are caught and traced. Incorrect arguments or errors raised by supplied/native components may propagate.
Parameters
Return values
On failure returns nil, err (table). Errors include client_closed, not_enrolled, reverse_connection_unavailable and proof_failed. Except when already closed, the requested enable setting is retained even if startup fails. A later credential update attempts to restart an enabled connection.
Throws
Proof callback errors are converted to proof_failed. Incorrect native reverse-connection options or incompatible supplied components may throw.
Parameters
Return values
Setting a credential attempts to restart an enabled reverse connection. The true result confirms storage only; a returned restart error is not forwarded. Inspect reverseStatus() for connection state.
Throws
Invalid credential values are reported as nil, err. Errors raised by native options or supplied components during reverse restart may propagate.
Clears credential and proof references and closes reverse and HTTP clients.
Parameters
Return values
Throws
Completion callback errors are caught and traced. Errors from incorrect use of supplied components may propagate. Return values from underlying transport close methods are not forwarded.
Parameters
None.
Return values
Closing the client stops its reverse connection but does not reset the stored enable setting. Use connected to inspect connection state.
Throws
No error for a valid client using the supported native reverse interface. Errors raised by a custom reverse interface's status() method propagate.
Parameters
None.
Return values
Throws
Does not throw for a valid client.
Parameters
None.
Return values
Throws
Does not throw for a valid client.
client:enroll({
name = "controller",
namePolicy = "exact",
dns = "local",
info = "Xedge"
}, function(result, err) end)
exact or increment. An explicit name defaults to exact.local, wan, or both. The default is local.namePolicy="exact" requires the requested name and returns name_unavailable on a conflict. namePolicy="increment" lets the portal try numbered variants such as controller1 and controller2. If a name is supplied without a policy, the policy is exact. If no name is supplied, the portal assigns one.
The dns field selects the ordinary DNS A record for the enrolled device. It does not select HTTP-01 or DNS-01.
| Value | Published address | Network effect |
|---|---|---|
local | The device's local IPv4 address, discovered automatically at startup and updated through setIpAddress() after a later network change. | Use this when local clients should connect directly to the device. This is the default. |
wan | The public source address observed by the portal. | Remote access still requires suitable router and firewall rules. |
both | Both local and public addresses. | Public DNS exposes the private address and clients may try either address. |
both is ordinary multi-address DNS. It is not split-horizon DNS and does not guarantee failover. Publishing wan does not create a NAT, port-forwarding, or firewall rule. Reverse connection is separate and routes public requests through the portal.
Application code normally does not call setAcmeRecord() or removeAcmeRecord(). The SharkTrust DNS adapter calls them from its engine-facing present() and cleanup() methods. This request format is documented for developers implementing or testing a custom DNS integration.
client:setAcmeRecord({
recordName = "_acme-challenge.controller.example.com",
recordData = "base64url-acme-validation-value",
dnsResolveTimeoutMs = 30000
}, function(result, err) end)
acme/engineacme/engine is the low-level RFC 8555 client. It communicates with an ACME directory but does not own persistent storage, renewal timers, certificate installation, Mako configuration, Xedge events, or SharkTrust enrollment. Most applications should use acme/runtime. Use the engine directly when implementing a custom manager or challenge workflow.
Creates a low-level ACME client and its serialized certificate-job queue.
local Engine = require"acme/engine"
local engine = Engine.create {
tpm = tpmInterface,
now = os.time
}
Parameters
os.time. This option is mainly useful for deterministic tests.Mako and Xedge install their platform TPM callbacks before publishing ba.tpm. Those trusted callbacks take precedence over constructor injection.
Return values
Throws
Incorrect options or dependency types may raise Lua errors. For valid options, construction has no reported operational error return.
The account argument used by certificate and revocation operations has this form:
{
email = "operator@example.com",
key = accountPrivateKey,
url = "https://acme.example/acct/123",
directoryUrl = "https://acme.example/directory"
}
The caller must persist the account returned by certificate operations. The manager does this automatically.
Downloads and validates an ACME directory to inspect provider capabilities.
Parameters
Return values
Throws
Reported transport and response errors go to the callback. A directory requiring External Account Binding returns external_account_required. Malformed JSON returns invalid_response; missing or invalid endpoint URLs return invalid_directory. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Reads the provider's Terms of Service URL before the application accepts the terms.
Parameters
Return values
Throws
Uses the same directory validation and operational error reporting as directory(). Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Queues one certificate order and immediately returns a job object. Use it when a custom manager owns account persistence, certificate persistence, installation, and renewal. Normal applications use the runtime or manager.
-- Use the callback for completion and check immediate submission errors.
local job, err = engine:certificate(service, account, {
domain = "device.example.com",
acceptTerms = true,
challenge = challengeAdapter,
key = {
type = "ecc",
curve = "SECP384R1"
},
replaces = optionalAriIdentifier,
timeout = 600,
dnsResolveTimeout = 30
}, function(result, requestErr) end)
Parameters
string email.ecc (default) or rsa. Omit this member when supplying privateKey.SECP384R1.table account, string|table privateKey, string certificate in PEM format, string orderUrl, string directoryUrl, and optional string ariId.ECC defaults to SECP384R1 and automatically uses the configured TPM interface. RSA defaults to 2048 bits and always uses a software key. New ACME account keys always use P-256.
Return values
Throws
Invalid submission arguments or worker setup can throw. Errors inside the certificate coroutine are caught and reported as operation_failed; reported operational failures go to the callback. String errors from native key and CSR creation become operation_failed error tables with the original message. Callback errors are caught and traced. Challenge cleanup is attempted on failure when a challenge context exists.
Reads ACME Renewal Information (ARI). The manager normally performs this check.
Parameters
Return values
Throws
Reported HTTP, certificate and response errors use the callback. Malformed JSON produces invalid_response; a missing or invalid suggested window produces invalid_renewal_info. A provider without ARI returns ari_unavailable. Callback errors are caught and traced. Incorrect arguments or supplied components may raise Lua errors.
Asks the ACME service to revoke a certificate. This method does not remove saved records or change the installed certificates. Normal applications use manager:revoke().
Parameters
Return values
Throws
Reported transport, signing and service failures go to the callback. A signing error string becomes a sign_failed error table; a signer's error table is preserved. No signed request is sent after signing fails. An account from a different directory returns account_directory_mismatch; missing PEM certificate data returns invalid_certificate. Callback errors are caught and traced. Incorrect arguments, invalid signing keys or supplied components may raise Lua errors.
Creates a certificate key synchronously for a custom integration. ECC uses the configured TPM interface when available; otherwise it uses a software key. RSA always uses a software key.
Parameters
Return values
Throws
Invalid software key settings throw as described for ba.create.key(). Errors raised by the supplied TPM interface propagate. This synchronous method does not catch Lua errors or invoke a completion callback.
Lists outstanding certificate requests for diagnostics.
Parameters
None.
Return values
Throws
Does not throw for valid job state.
Cancels queued work, performs required challenge cleanup, closes owned HTTP clients, and prevents new work. Call during shutdown when using the engine directly.
Parameters
Return values
Throws
Challenge cleanup exceptions are converted to error tables. Completion callback errors are caught and traced. Incorrect use of supplied components may throw.
A challenge adapter makes an ACME validation value reachable and removes it afterward. Runtime users normally select the built-in HTTP adapter, the SharkTrust DNS adapter, or the manual DNS adapter. Implement this interface only for another DNS provider or hosting environment.
challenge.type = "dns-01" -- or "http-01" challenge:present(context, callback) challenge:cleanup(context, callback)
dns-01 or http-01.context is the engine-created table shown below. Call callback(true, nil) only when the value is ready for validation, or callback(nil, err) on failure.present(). context is the same engine-created table. Call callback(true, nil) after cleanup or callback(nil, err) on failure.For DNS-01, context has this form:
{
domain = "controller.example.com",
token = "token-from-acme-server",
keyAuthorization = "token-and-account-thumbprint",
challengeUrl = "https://acme.example/challenge/123",
recordName = "_acme-challenge.controller.example.com",
recordData = "base64url-acme-validation-value",
dnsResolveTimeoutMs = 30000
}
For HTTP-01, context has this form:
{
domain = "controller.example.com",
token = "token-from-acme-server",
challengeUrl = "https://acme.example/challenge/123",
tokenPath = "acme-challenge/token-from-acme-server",
keyAuthorization = "token-and-account-thumbprint"
}
/.well-known/ where keyAuthorization must be served.All context members are supplied by the engine. The adapter must not change them. After a successful present(), the engine calls cleanup() for success, failure, timeout, cancellation, or callback error.
engine:certificate() returns a job immediately. Use the job only to inspect or cancel a low-level certificate request. Runtime and manager users normally do not handle job objects.
Parameters
None.
Return values
Throws
Does not throw for a valid job.
Reads progress or the final outcome of a retained job object. Completion is also delivered through the certificate callback.
Parameters
None.
Return values
Throws
Does not throw for valid job state.
Cancels a queued or running operation and performs challenge cleanup when required.
Parameters
Return values
Throws
Challenge cleanup exceptions are converted to error tables. Errors from the certificate and cancellation callbacks are caught and traced.
The optional TPM interface stores ECC private keys outside Lua and performs signing or certificate-request operations with those keys. A standalone host implements these synchronous functions. Normal Mako and Xedge applications do not provide this table.
local tpmInterface = {
hasKey = function(name) end,
createKey = function(name, options) end,
jwtSign = function(name, payload, protectedHeader) end,
keyParams = function(name) end,
createCsr = function(name, distinguishedName,
certificateTypes, keyUsages) end
}
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Ignored by the ACME layer; a direct nil, err return is not recognized as a creation failure.
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
Throws
Platform exceptions propagate to the calling engine operation.
Parameters
Return values
None. Installs the trusted callbacks and removes setTPM from the module, allowing only one installation.
Throws
Incorrect interface types can throw. Calling Engine.setTPM again fails because that function no longer exists. Individual platform callbacks are used and checked later by engine operations.
Certificate jobs catch Lua errors from platform callbacks and report operation_failed. Direct createKey() and standalone revocation do not provide that coroutine error handling; see their method contracts.
Mako and Xedge log the numeric notification codes directly. The former acme/log object is removed. A custom host may translate codes into messages in its own notify(code) function. Keeping messages in the host avoids loading a general logging framework on embedded devices.
The manager stores state below acme/ by default. Each effective ACME directory has an independent profile below acme/services/, and acme/active.json selects the installed profile. A Mako SharkTrust integration stores device enrollment separately in acme/sharktrust.json.
The modules read only their current state format. They do not import the old cert/ layout, acme-v2/, legacy devkey or refresh-token state, or account and certificate files from an earlier implementation.
Account keys, certificate private keys, SharkTrust device credentials, zone secrets, and proof material are secrets. Keep the writable I/O private and exclude it from application packages, source repositories, diagnostics, and downloads.
The current modules do not implement:
A domains list is handled as separate certificate records, one DNS identifier per ACME order.