certbot-dns-delegation
English | Simplified Chinese
A Certbot DNS-01 plugin with CNAME delegation that automatically creates and cleans up TXT validation records on Alibaba Cloud DNS, Tencent Cloud DNSPod, Cloudflare, or GoDaddy.
Supports Certbot 3.x and 5.x with a single plugin codebase for both host versions.
Two installation names are available: certbot-dns-alias and certbot-dns-delegation.
The latter is an installation alias that automatically installs the same version of the main
package. Both use the Certbot authenticator dns-alias.
How it works
Delegate your domain's _acme-challenge record to a centrally managed validation domain
using a CNAME:
_acme-challenge.example.com. 300 IN CNAME example-com.delegate.example.net.
Host delegate.example.net on Alibaba Cloud, Tencent Cloud, Cloudflare, or GoDaddy. When requesting
a certificate, the plugin:
- Follows the CNAME chain from
_acme-challenge.example.comto its final target. - Selects the cloud provider that manages the target's zone.
- Adds the required TXT value at
example-com.delegate.example.net. - Waits for DNS propagation so the certificate authority can complete DNS-01 validation.
- Cleans up the temporary TXT record using the record ID saved at creation time.
The original domain can use any DNS provider; only API credentials for the final target's managed zone are required. Multiple CNAME hops, wildcards, and multiple domains in one certificate are supported. Domains in the same request can delegate to different cloud providers. TXT values are managed individually, preserving other values at the same name. Existing valid records with the same value are reused and never deleted by the plugin.
Installation
Supports Python 3.9–3.14 and Certbot 3.x and 5.x in the following combinations:
| Python | Certbot 3.x | Certbot 5.x |
|---|---|---|
| 3.9 | Supported | Upstream requires Python ≥3.10 |
| 3.10–3.13 | Supported | Supported |
| 3.14 | Older josepy cannot be imported | Supported |
Certbot 4.x is not supported and is excluded from the package dependencies.
DNS names use non-transitional IDNA2008 normalization; Unicode names and their Punycode
forms identify the same zone (for example, faß.de and xn--fa-hia.de).
The plugin is loaded by your Certbot host and must be installed in the same Python environment.
Install in the Python environment containing Certbot:
python -m pip install certbot-dns-alias
Alternatively, use the installation alias. Choose either package:
python -m pip install certbot-dns-delegation
With the alias installed, the authenticator is still dns-alias, and options and credential
keys still use the dns-alias / dns_alias prefixes.
Here, python must be the interpreter running your Certbot host. With uv, specify the host
environment explicitly:
uv pip install --python /path/to/certbot-venv/bin/python certbot-dns-alias
Host dependency requirements depend on the Python version: Python 3.9 uses Certbot 3,
Python 3.14 uses Certbot 5, and Python 3.10–3.13 can use Certbot 3 or 5.
To preserve an exact host version, pin it explicitly during installation. For example,
for a 3.0.0 host. Every Certbot 3 host must use the certbot3 extra to constrain
ACME to 3.x and pyOpenSSL to >=24.3,<25, including on Python 3.10–3.13:
python -m pip install 'certbot==3.0.0' 'certbot-dns-alias[certbot3]'
The alias supports the same extra: certbot-dns-delegation[certbot3].
Default installations on Certbot 5 do not impose this legacy TLS dependency cap.
The extra is a compatibility option, not a security update for old dependencies; use a
maintained Certbot 5 host when possible. The extra's constraints apply on Python 3.9–3.13;
Python 3.14 supports only Certbot 5.
Use your deployment's constraints file to preserve any other host dependency requirements.
Check that the plugin is available:
certbot plugins --text
Credentials
Create credentials.ini with key = value entries and no INI section. Restrict file permissions:
chmod 600 credentials.ini
Alibaba Cloud
dns_alias_provider = aliyun
dns_alias_aliyun_access_key_id = YOUR_ACCESS_KEY_ID
dns_alias_aliyun_access_key_secret = YOUR_ACCESS_KEY_SECRET
dns_alias_aliyun_zones = delegate.example.net
Optional settings: dns_alias_aliyun_region_id (default: cn-hangzhou) and
dns_alias_aliyun_security_token (temporary STS credentials).
Tencent Cloud DNSPod
dns_alias_provider = tencent
dns_alias_tencent_secret_id = YOUR_SECRET_ID
dns_alias_tencent_secret_key = YOUR_SECRET_KEY
dns_alias_tencent_zones = delegate.example.net
Use Tencent Cloud SecretId / SecretKey credentials. Set dns_alias_tencent_token for temporary
session credentials.
Cloudflare
dns_alias_provider = cloudflare
dns_alias_cloudflare_api_token = YOUR_API_TOKEN
Use an API Token with Zone:DNS:Edit and Zone:Zone:Read for the delegated zones.
The plugin uses https://api.cloudflare.com/client/v4 and discovers zones visible to the token.
Global API keys are not supported.
To skip zone discovery and avoid the Zone:Zone:Read permission, provide zone-name:ID pairs:
dns_alias_cloudflare_zone_ids = delegate.example.net:0123456789abcdef0123456789abcdef
Replace the placeholder with the 32-character Zone ID from the Cloudflare dashboard.
Separate multiple pairs with commas. This mapping restricts eligible zones to the listed names.
You may further restrict them with dns_alias_cloudflare_zones; every listed name must have
an entry in dns_alias_cloudflare_zone_ids. Explicit Cloudflare zone names without IDs are
rejected because skipping discovery requires their IDs.
Cloudflare TXT record TTL is 1 (automatic) or 60–86400 seconds (30-second minimum for Enterprise).
The plugin's default 600 is valid. Keep delegation CNAME records in DNS-only mode so public
resolvers can follow them; Cloudflare proxying or CNAME flattening can hide the CNAME.
GoDaddy
dns_alias_provider = godaddy
dns_alias_godaddy_api_token = YOUR_GODADDY_PAT
dns_alias_godaddy_zones = delegate.example.net
The plugin uses the bundled GoDaddy Domains v3 client and a Personal Access Token (PAT)
at https://api.godaddy.com. Legacy API key/secret credentials are not supported.
The token needs domains.domain:read for queries and domains.dns:update for writes.
TXT TTL must be 600–86400 seconds; the plugin's default 600 is valid.
dns_alias_godaddy_zones is an optional allowlist that skips registered-domain discovery.
Use it for delegated subdomains or DNS zones not included in the account's registered domains.
When omitted, the plugin enumerates all registered domains and verifies DNS API access and
an apex SOA record for each candidate. Only candidates with an apex SOA are eligible.
Any API failure or incomplete pagination stops discovery without caching partial results;
if your account includes domains whose DNS is inaccessible, configure an explicit zone list.
Ensure the delegated zone is served by GoDaddy's authoritative nameservers.
Optional setting: dns_alias_godaddy_ote = true selects https://api.ote-godaddy.com with
separate OTE credentials. The default is false (production). This setting selects the
GoDaddy API environment independently of Certbot's --staging ACME environment.
Using multiple providers
dns_alias_provider = auto
dns_alias_aliyun_access_key_id = YOUR_ACCESS_KEY_ID
dns_alias_aliyun_access_key_secret = YOUR_ACCESS_KEY_SECRET
dns_alias_aliyun_zones = ali-delegate.example.net
dns_alias_tencent_secret_id = YOUR_SECRET_ID
dns_alias_tencent_secret_key = YOUR_SECRET_KEY
dns_alias_tencent_zones = tencent-delegate.example.org
dns_alias_cloudflare_api_token = YOUR_API_TOKEN
dns_alias_cloudflare_zone_ids = cf-delegate.example.net:0123456789abcdef0123456789abcdef
dns_alias_godaddy_api_token = YOUR_GODADDY_PAT
dns_alias_godaddy_zones = gd-delegate.example.net
Configure a delegation target for each domain:
_acme-challenge.example.com. 300 IN CNAME example-com.ali-delegate.example.net.
_acme-challenge.api.example.org. 300 IN CNAME api-example-org.tencent-delegate.example.org.
Pass both -d example.com -d api.example.org in the certificate request.
The auto mode requires at least one complete set of provider credentials; configuring only
one provider is also valid.
The *_zones settings are optional. Separate multiple zones with commas, and use actual zone
names hosted by the cloud provider, such as delegate.example.net, rather than complete TXT
hostnames. An explicit list restricts eligible zones; otherwise, the plugin discovers all zones
visible to the credentials. Cloudflare uses dns_alias_cloudflare_zone_ids to skip discovery;
explicit dns_alias_cloudflare_zones also requires IDs as described above. The plugin selects
the longest matching DNS suffix. If the same matching zone belongs to multiple providers,
adjust the zone lists or select a single provider to resolve the ambiguity.
GoDaddy discovery starts with registered domains and verifies their DNS API access as described above.
API permissions
Alibaba Cloud credentials require:
alidns:DescribeDomainRecordsalidns:AddDomainRecordalidns:DeleteDomainRecordalidns:DescribeDomainswhendns_alias_aliyun_zonesis not configured
Tencent Cloud credentials require:
dnspod:DescribeRecordListdnspod:CreateRecorddnspod:DeleteRecorddnspod:DescribeDomainListwhendns_alias_tencent_zonesis not configured
Cloudflare API Tokens require:
Zone:DNS:Editfor listing, creating, and deleting TXT recordsZone:Zone:Readwhendns_alias_cloudflare_zone_idsis not configured
Restrict the token's zone resources to the delegated zones. See Cloudflare DNS records and zone discovery.
GoDaddy Personal Access Tokens require:
domains.domain:readfor registered-domain discovery and DNS record queriesdomains.dns:updatefor creating and deleting individual TXT records
The plugin uses Domains v3 with the bundled REST client. See GoDaddy DNS documentation. A cleanup 404 is accepted only after a complete TXT query confirms the saved record ID is absent from the saved zone. Inaccessible or missing zones remain cleanup errors and can be retried.
Requesting a certificate
Configure the CNAME first and ensure it resolves through public DNS, then run:
certbot certonly \
--authenticator dns-alias \
--dns-alias-credentials /path/to/credentials.ini \
--dns-alias-require-cname \
--dns-alias-propagation-seconds 120 \
--non-interactive --agree-tos --email admin@example.com \
-d example.com -d '*.example.com'
Replace the credentials path, email address, and domains with your own values.
Add --staging for an initial test, then remove it to request a production certificate.
A domain and its wildcard share the same _acme-challenge name; the plugin preserves all TXT
values needed for both challenges.
Common options
| Option | Default | Description |
|---|---|---|
--dns-alias-credentials |
Required | Path to the credentials INI file |
--dns-alias-propagation-seconds |
60 |
Propagation wait in seconds after all TXT records are ready |
--dns-alias-ttl |
600 |
TXT record TTL; must satisfy the cloud plan's limits |
--dns-alias-cname-max-depth |
8 |
Maximum number of CNAME hops |
--dns-alias-dns-timeout |
10 |
Total timeout in seconds for each DNS query |
--dns-alias-dns-retries |
2 |
Additional retries after a timeout or unavailable nameservers |
--dns-alias-resolvers |
System DNS | Comma-separated IPv4/IPv6 DNS server addresses |
--dns-alias-require-cname |
Disabled | Reject writes when the original challenge name has no CNAME |
Without --dns-alias-require-cname, the plugin may also create TXT records directly in the
managed zone of the original challenge name. TTL and propagation wait are different settings.
Creating a validation hostname for the first time may encounter DNS negative caching;
increase the propagation wait if needed.
Renewal
Certbot saves the authenticator configuration and the absolute credentials file path. Run renewal in the same environment:
certbot renew --dry-run
certbot renew
Keep the credentials file available and refresh temporary credentials before they expire. The account running Certbot needs access to its configuration, work, and log directories. Creation state is stored only in the current Certbot process. Forced termination, a lost response after a successful creation, or a cleanup failure may leave TXT records behind in the delegated zone; remove these manually.
GoDaddy REST client
The package includes an internal synchronous GoDaddy Domains v3 client using httpx2.
The GoDaddy Certbot provider uses this client; it is also available for direct API calls.
The client uses a Personal Access Token (PAT), with domains.domain:read for queries and
domains.dns:update for writes. Legacy API key/secret credentials are not accepted by v3.
See GoDaddy DNS documentation.
from certbot_dns_alias.sdk.godaddy import GoDaddyClient
with GoDaddyClient("YOUR_GODADDY_PAT") as client:
records = client.list_records("example.com", type="TXT", name="_acme-challenge")
list_domains() and get_domain() return domain identities, status, and nameservers.
list_records() returns DNSRecord objects, including record_id, relative name, type,
data, and ttl. create_record(zone, record) and
replace_record(zone, record_id, record) accept a DNSRecord and return the server's record;
delete_record(zone, record_id) deletes only that ID. TXT TTLs must be 600–86400 seconds.
Registered domain enumeration does not establish that a domain's DNS is hosted on GoDaddy.
The client reads all pages or raises, uses a 10-second connection timeout and 30-second
read/write/pool timeouts, and performs no automatic retries or redirects. Errors subclass
Certbot's PluginError and omit sensitive API messages. A delete returning 404 remains a
GoDaddyAPIError; the Certbot provider verifies zone access and record absence before accepting it.
Use ote=True with separate OTE credentials
for the test environment. Close the client after use, preferably with a context manager.
Lost responses after successful writes can leave records behind; do not blindly retry writes.
Python 3.9 installs HTTPX2 2.0; Python 3.10–3.14 can use newer 2.x releases.
Security and release notes
See the security policy for private vulnerability reporting and legacy host limitations, and the changelog for changes and upgrade notes.
Metadata
Release files for certbot-dns-delegation 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| certbot_dns_delegation-1.0.0.tar.gz | 7.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| certbot_dns_delegation-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.9 kB
Release files / certbot_dns_delegation-1.0.0.tar.gz
| Download URL | certbot_dns_delegation-1.0.0.tar.gz |
|---|---|
| Size | 7.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5877aaa9f0d1bd151d04fe951bc8d98bd06ae331bc2a3b3b1f05985905ff687d
|
|
BLAKE2b-256 checksum How to use checksums |
f4e119c1cdc07118d8f2a4b8f3c62144df6030b34e91188140fc4ef478c38667
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / certbot_dns_delegation-1.0.0-py3-none-any.whl
| Download URL | certbot_dns_delegation-1.0.0-py3-none-any.whl |
|---|---|
| Size | 7.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3163e085cbf8ceff4330acf401999e6ae4c166ac340612e9472491ca1d930fc4
|
|
BLAKE2b-256 checksum How to use checksums |
228f160df05f21d4e01b6c0d28de6ca98ed43422955ede85114b281d2341b0ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency log