Repository navigation
Description
OS
Arch Linux on Docker
Installation method
pacman
Certbot Version
5.2.1
What happened?
Hey there!
Certbot cannot renew or create a certificate when multiple domain names are requested. Although it works as expected if only a single domain name is requested.
Error
An unexpected error occurred:
TypeError: DNSName SAN compared to non-SAN: <class 'str'>
Setup
#! /bin/bash
set -euo pipefail
IFS=$'\n\t'
HOSTS=(
"tanayg.com"
"tanayg.network"
)
PARAMETERS=()
for host in "${HOSTS[@]}"; do
path="/opt/certbot/webroot/$host"
mkdir -p "$path"
PARAMETERS+=("--webroot-path")
PARAMETERS+=("$path")
PARAMETERS+=("-d")
PARAMETERS+=("$host")
done
certbot --config-dir /opt/certbot --cert-name tanayg --non-interactive --agree-tos \
certonly --force-renewal -a webroot -i nginx -m [email protected] \
"${PARAMETERS[@]}"/opt/certbot is mounted on a docker volume shared with my nginx container. Also note that each domain has its own webroot path that my nginx container serves correctly.
This setup has worked for me for the past year.
Diagnosis
From the attached log, it looks like the commits for #10468 and #10478 are involved.
Fix?
This is just a hack. I don't know the code very well so I'm hoping this helps someone fix this properly.
Allow DNSName comparison with str
certbot/_internal/san.py
class DNSName(SAN):
def __eq__(self, other: Any) -> bool:
match other:
case DNSName():
return self.dns_name == other.dns_name
case IPAddress():
return False
case str():
return self.dns_name == other
case _:
raise TypeError(f"DNSName SAN compared to non-SAN: {type(other)}")configobj can't store non-strings
File "/usr/lib/python3.13/site-packages/configobj/__init__.py", line 579, in __setitem__
raise ValueError('The key "%s" is not a string.' % key)
ValueError: The key "tanayg.com" is not a string.
certbot/_internal/storage.py
def relevant_values(config: configuration.NamespaceConfig) -> dict[str, Any]:
...
rv = {
str(option): str(value)
for option, value in all_values.items()
if _relevant(namespaces, option) and config.set_by_user(option)
}
...With these changes, the certificate renewal works!
I appreciate your help! Thanks!
Expected behavior
Certbot should renew all requested domain names.
Relevant log output
2025-12-07 11:47:18,023:DEBUG:certbot._internal.log:Exiting abnormally:
Traceback (most recent call last):
File "/usr/sbin/certbot", line 8, in <module>
sys.exit(main())
~~~~^^
File "/usr/lib/python3.13/site-packages/certbot/main.py", line 18, in main
return internal_main.main(cli_args)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/main.py", line 1876, in main
return config.func(config, plugins)
~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/main.py", line 1588, in certonly
lineage = _get_and_save_cert(le_client, config, sans, certname, lineage)
File "/usr/lib/python3.13/site-packages/certbot/_internal/main.py", line 131, in _get_and_save_cert
renewal.renew_cert(config, sans, le_client, lineage)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/renewal.py", line 564, in renew_cert
new_cert, new_chain, new_key, _ = le_client.obtain_certificate(sans, new_key)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/client.py", line 432, in obtain_certificate
orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names)
File "/usr/lib/python3.13/site-packages/certbot/_internal/client.py", line 510, in _get_order_and_authorizations
authzr = self.auth_handler.handle_authorizations(orderr, self.config, best_effort)
File "/usr/lib/python3.13/site-packages/certbot/_internal/auth_handler.py", line 84, in handle_authorizations
resps = self.auth.perform(achalls)
File "/usr/lib/python3.13/site-packages/certbot/_internal/plugins/webroot.py", line 109, in perform
self._set_webroots(achalls)
~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/plugins/webroot.py", line 121, in _set_webroots
self.conf("map").setdefault(achall.domain, webroot_path)
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/certbot/_internal/san.py", line 90, in __eq__
raise TypeError(f"DNSName SAN compared to non-SAN: {type(other)}")
TypeError: DNSName SAN compared to non-SAN: <class 'str'>
2025-12-07 11:47:18,025:ERROR:certbot._internal.log:An unexpected error occurred:
Activity
fix finish_release.py on the 5.2.x point release branch (#10507)
bmw commentedon Dec 8, 2025
hey @0tanay
thanks so much for the detailed bug report. we'll get this fixed soon
just to be sure, when you say certificate renewal is also broken, you're renewing your certificates with the
certbot certonlysubcommand instead ofcertbot renewright? i've been able to reproduce the problem withcertbot certonlybut notcertbot renewand i want to make sure i'm not missing part of the problem here0tanay commentedon Dec 8, 2025
That's right. I've only tried
certbot certonly.jsha commentedon Dec 9, 2025
I've made a PR with a fix here: #10509
0tanay commentedon Dec 10, 2025
Just saw this was fixed. Thanks a lot, everyone!
fmonts commentedon Dec 10, 2025
Can you please tag and publish a release?
The issue is still present in certbot installed via snap on Ubuntu latest LTS, which basically broke a lot of production setups worldwide 🥲
Fix --webroot-path action (#10509)
Fix --webroot-path action (#10509) (#10510)