Skip to main content

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, 4.x, and 5.x with a single plugin codebase for all three host series.

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:

  1. Follows the CNAME chain from _acme-challenge.example.com to its final target.
  2. Selects the cloud provider that manages the target's zone.
  3. Adds the required TXT value at example-com.delegate.example.net.
  4. Waits for DNS propagation so the certificate authority can complete DNS-01 validation.
  5. 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.15 and Certbot 3.x, 4.x, and 5.x in the following combinations:

Python Certbot 3.x Certbot 4.x Certbot 5.x
3.9 Supported Supported Upstream requires Python ≥3.10
3.10–3.13 Supported Supported Supported
3.14–3.15 Older josepy cannot be imported Supported Supported

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 can use Certbot 3 or 4, Python 3.14–3.15 can use Certbot 4 or 5, and Python 3.10–3.13 can use Certbot 3, 4, 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].

For a Certbot 4 host, pin its installed version without the legacy extra, for example:

python -m pip install 'certbot==4.0.0' 'acme==4.0.0' certbot-dns-alias

Default installations on Certbot 4 and 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–3.15 supports Certbot 4 and 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:DescribeDomainRecords
  • alidns:AddDomainRecord
  • alidns:DeleteDomainRecord
  • alidns:DescribeDomains when dns_alias_aliyun_zones is not configured

Tencent Cloud credentials require:

  • dnspod:DescribeRecordList
  • dnspod:CreateRecord
  • dnspod:DeleteRecord
  • dnspod:DescribeDomainList when dns_alias_tencent_zones is not configured

Cloudflare API Tokens require:

  • Zone:DNS:Edit for listing, creating, and deleting TXT records
  • Zone:Zone:Read when dns_alias_cloudflare_zone_ids is 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:read for registered-domain discovery and DNS record queries
  • domains.dns:update for 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 httpx. 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. GoDaddy and Cloudflare share the same httpx dependency on all supported Python versions. Custom transports must implement httpx.BaseTransport, such as httpx.MockTransport.

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.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for certbot-dns-delegation 1.0.1
File Size Uploaded
certbot_dns_delegation-1.0.1.tar.gz 7.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for certbot-dns-delegation 1.0.1
File Interpreter ABI Platform
certbot_dns_delegation-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 15.1 kB

Release files / certbot_dns_delegation-1.0.1.tar.gz

Download URL certbot_dns_delegation-1.0.1.tar.gz
Size 7.4 kB
Tags Source
SHA-256 checksum
How to use checksums
c2c3d2e4b1fd8df32722d1bed665b2b168ad49cf5bdc23efeb5f597a396b9d49
BLAKE2b-256 checksum
How to use checksums
00b20ca414eac21722e8bac8037e65b6c7cef9b53b4cb6a29a5e51c93d73009c
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 11, 2026.

Transparency log

Release files / certbot_dns_delegation-1.0.1-py3-none-any.whl

Download URL certbot_dns_delegation-1.0.1-py3-none-any.whl
Size 7.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2c19b5f8bc3095eb9518e613ac5d07f1eb8ccd3a62186a6c41b17fc551cdac34
BLAKE2b-256 checksum
How to use checksums
8e8cf2f7592a80650cdd9f446239d140763635996b14003acbd0763fd6b43d67
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 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page