ACME DNS-01 Interactive CLI Challenge Handler
acme-dns-01-cli is an interactive command-line interface (CLI) based strategy for handling ACME DNS-01 challenges, primarily designed for integration within the Greenlock and ACME.js ecosystems. As of version 3.0.7, it provides a simple, manual process where it prints the required DNS Host and Key Authorization Digest to the terminal, pauses for user input, and then verifies the challenge. Unlike HTTP-01 challenges, this module fully supports wildcard certificate requests, making it a crucial component for securing domains like `*.example.com`. Its main differentiation is its direct, interactive nature, serving as a reference implementation for those needing manual control over the DNS challenge process or adapting it to custom environments. While it requires manual intervention, it offers flexibility for environments where automated DNS provisioning isn't feasible or desired. It integrates seamlessly as a challenge handler within Greenlock's configuration.
Common errors
-
TypeError: require(...).create is not a function
cause Incorrect module import/access for the 'create' function, or an incompatibility between Greenlock and acme-dns-01-cli versions.fixEnsure you are using `const { create } = require('acme-dns-01-cli');` for CommonJS or `import { create } from 'acme-dns-01-cli';` for ES Modules. Verify your Greenlock version is compatible with acme-dns-01-cli v3.x (Greenlock v3.x+ is generally required). -
Error: Challenge verification failed.
cause The DNS TXT record was not correctly propagated or not set in time before the ACME server attempted verification.fixDouble-check the exact DNS Host and DNS Key Authorization Digest provided by the CLI. Ensure the TXT record is published correctly and has propagated across DNS servers (use tools like `dig` or online DNS checkers). Wait a few minutes after setting the record before pressing Enter in the CLI. -
ReferenceError: Greenlock is not defined
cause The Greenlock module was not imported or required correctly before use.fixAdd `const Greenlock = require('greenlock');` for CommonJS or `import Greenlock from 'greenlock';` for ES Modules at the top of your file, ensuring Greenlock is installed (`npm install greenlock`).
Warnings
- breaking Version 3.x of `acme-dns-01-cli` introduces breaking changes regarding compatibility with older Greenlock versions.
- gotcha This strategy is manual and interactive, requiring user intervention via the CLI to update DNS TXT records.
- gotcha Requesting a certificate for multiple domains (e.g., `example.com` and `www.example.com`) or multiple wildcards (`*.example.com`, `*.sub.example.com`) will trigger an individual DNS-01 challenge for each subject.
Install
-
npm install acme-dns-01-cli -
yarn add acme-dns-01-cli -
pnpm add acme-dns-01-cli
Imports
- create
const greenlockChallenge = require('acme-dns-01-cli');import { create } from 'acme-dns-01-cli'; - (CommonJS module access)
import acmeDns01Cli from 'acme-dns-01-cli';
const acmeDns01Cli = require('acme-dns-01-cli'); - set (method)
import { set } from 'acme-dns-01-cli'; set(opts);const handler = create({ debug: true }); handler.set(opts);
Quickstart
import Greenlock from 'greenlock';
import { create as createDns01CliChallenge } from 'acme-dns-01-cli';
// Configure the acme-dns-01-cli challenge handler
const challengeConfig = createDns01CliChallenge({
debug: true // Enable debug output for the CLI handler
});
// Initialize Greenlock with the custom challenge handler
const greenlock = Greenlock.create({
package: {
name: 'my-greenlock-app',
version: '1.0.0',
},
configDir: './greenlock.d/', // Specify a configuration directory
maintainerEmail: 'your-email@example.com',
cluster: false, // Set to true for multi-process environments
challenges: {
'dns-01': challengeConfig // Register the interactive DNS-01 challenge
},
// Define how domains are approved (customize as needed)
approveDomains: async (opts) => {
console.log(`Greenlock is requesting approval for: ${opts.subject || opts.altnames.join(', ')}`);
// For acme-dns-01-cli, the manual interaction will occur via the challengeConfig
return opts;
},
});
// Function to request a certificate (this will trigger the CLI prompt)
async function obtainCertificate() {
const domainsToSecure = ['example.com', '*.example.com']; // Example domains
console.log(`Attempting to obtain certificate for: ${domainsToSecure.join(', ')}`);
try {
const cert = await greenlock.add({
subject: domainsToSecure[0], // Primary domain
altnames: domainsToSecure, // All domains including wildcard
email: 'your-email@example.com', // Email for renewal notices
});
console.log('Successfully obtained certificate:', cert);
} catch (err) {
console.error('Failed to obtain certificate:', err);
if (err.challenge && err.challenge.dnsHost && err.challenge.dnsAuthorization) {
console.warn(`Please verify the TXT record for ${err.challenge.dnsHost} with value ${err.challenge.dnsAuthorization} is correctly set.`);
}
}
}
// Execute the certificate acquisition process
obtainCertificate();
// In a real application, Greenlock would also manage a server
// to handle certificate renewals and serve HTTPS traffic.
// Example (requires 'greenlock-express'):
/*
import greenlockExpress from 'greenlock-express';
greenlockExpress.create({
package: greenlock.defaults.package,
configDir: greenlock.defaults.configDir,
maintainerEmail: greenlock.defaults.maintainerEmail,
cluster: greenlock.defaults.cluster,
challenges: greenlock.defaults.challenges,
approveDomains: greenlock.defaults.approveDomains,
// Add your server options here
}).listen(80, 443);
*/