A Certbot DNS challenge proves domain control by publishing a temporary TXT record instead of serving a token from the web server. Use it when port 80 cannot be exposed, when the origin is private, or when the certificate order includes a name that cannot use HTTP-01 validation.
The manual DNS flow is deliberately interactive. Certbot prints the exact record name and value for the current ACME order, waits while you publish and verify the record, then continues only after you press Enter.
The manual challenge path fits one-time issuance and controlled break-glass work. For repeatable unattended renewal, use a provider DNS plugin or manual auth and cleanup hooks so the TXT record can be created and removed automatically.
$ sudo apt install --assume-yes certbot dnsutils Reading package lists... Done Building dependency tree... Done The following NEW packages will be installed: certbot dnsutils ##### snipped ##### Setting up certbot ...
Use the package manager that matches the server. The example uses the Debian and Ubuntu APT package layout.
$ certbot --help all
##### snipped #####
manual:
Authenticate through manual configuration or custom shell scripts.
##### snipped #####
--preferred-challenges PREF_CHALLS
A sorted, comma delimited list of the preferred
challenge to use during authorization
##### snipped #####
$ printf '%s\n' host.example.net host.example.net
For a wildcard certificate such as *.example.net, the DNS-01 owner is based on the parent name, so the TXT record goes under _acme-challenge.example.net instead of a name containing the literal asterisk.
$ sudo certbot certonly --manual --preferred-challenges dns --dry-run -d host.example.net -m admin@example.net --agree-tos Saving debug log to /var/log/letsencrypt/letsencrypt.log Simulating a certificate request for host.example.net Please deploy a DNS TXT record under the name: _acme-challenge.host.example.net. with the following value: <validation-string-from-certbot> Before continuing, verify the TXT record has been deployed.
Do not reuse an old TXT value. Each ACME order can produce a new value, and Certbot validates the value shown in the current prompt.
_acme-challenge.host.example.net. 300 IN TXT "<validation-string-from-certbot>"
Publish only the value from the active Certbot prompt. Remove stale validation strings from older attempts unless another active order still needs them.
$ dig +short TXT _acme-challenge.host.example.net "<validation-string-from-certbot>"
DNS providers, split-horizon views, and delegated validation zones can show different answers from different resolver locations. The ACME DNS Challenge Readiness Check can compare the expected value and DNS route before you let Certbot continue.
Press Enter to Continue Waiting for verification... The dry run was successful.
If Certbot reports NXDOMAIN, No TXT record found, or a mismatched value, leave the certificate request failed, fix the DNS owner or value, and start a fresh request so the prompt and TXT value match.
$ sudo certbot certonly --manual --preferred-challenges dns -d host.example.net -m admin@example.net --agree-tos Saving debug log to /var/log/letsencrypt/letsencrypt.log Requesting a certificate for host.example.net Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/host.example.net/fullchain.pem Key is saved at: /etc/letsencrypt/live/host.example.net/privkey.pem
The production request produces its own TXT value, so repeat the publish, verify, and continue sequence for the live order.
$ sudo certbot certificates --cert-name host.example.net
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found the following certs:
Certificate Name: host.example.net
Domains: host.example.net
Expiry Date: 2026-09-10 14:20:00+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/host.example.net/fullchain.pem
Private Key Path: /etc/letsencrypt/live/host.example.net/privkey.pem
$ sudo certbot renew --cert-name host.example.net --dry-run Saving debug log to /var/log/letsencrypt/letsencrypt.log Processing /etc/letsencrypt/renewal/host.example.net.conf PluginError: An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.
Manual DNS certificates are not safe to leave on unattended renewal unless an auth hook and cleanup hook, or a provider DNS plugin, can update the TXT record without an operator. For normal recurring certificates, use a DNS provider plugin instead.
_acme-challenge.host.example.net. 300 IN TXT "<validation-string-from-certbot>" # remove after validation
Certbot cannot remove a manually created DNS record. Clean up stale values so future checks show only active validation records.