diff --git a/certbot-apache/certbot_apache/_internal/http_01.py b/certbot-apache/certbot_apache/_internal/http_01.py index 83a1a8e08..872704db8 100644 --- a/certbot-apache/certbot_apache/_internal/http_01.py +++ b/certbot-apache/certbot_apache/_internal/http_01.py @@ -95,10 +95,10 @@ class ApacheHttp01(common.ChallengePerformer): def _mod_config(self): selected_vhosts: List[VirtualHost] = [] http_port = str(self.configurator.config.http01_port) + + # Search for VirtualHosts matching by name for chall in self.achalls: - # Search for matching VirtualHosts - for vh in self._matching_vhosts(chall.domain): - selected_vhosts.append(vh) + selected_vhosts += self._matching_vhosts(chall.domain) # Ensure that we have one or more VirtualHosts that we can continue # with. (one that listens to port configured with --http-01-port) @@ -107,9 +107,13 @@ class ApacheHttp01(common.ChallengePerformer): if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs): found = True - if not found: - for vh in self._relevant_vhosts(): - selected_vhosts.append(vh) + # If there's at least one elgible VirtualHost, also add all unnamed VirtualHosts + # because they might match at runtime (#8890) + if found: + selected_vhosts += self._unnamed_vhosts() + # Otherwise, add every Virtualhost which listens on the right port + else: + selected_vhosts += self._relevant_vhosts() # Add the challenge configuration for vh in selected_vhosts: @@ -167,6 +171,10 @@ class ApacheHttp01(common.ChallengePerformer): return relevant_vhosts + def _unnamed_vhosts(self) -> List[VirtualHost]: + """Return all VirtualHost objects with no ServerName""" + return [vh for vh in self.configurator.vhosts if vh.name is None] + def _set_up_challenges(self): if not os.path.isdir(self.challenge_dir): old_umask = filesystem.umask(0o022) diff --git a/certbot-apache/tests/http_01_test.py b/certbot-apache/tests/http_01_test.py index 71f2db500..1ce47ed1a 100644 --- a/certbot-apache/tests/http_01_test.py +++ b/certbot-apache/tests/http_01_test.py @@ -125,6 +125,18 @@ class ApacheHttp01Test(util.ApacheTest): domain="duplicate.example.com", account_key=self.account_key)] self.common_perform_test(achalls, vhosts) + def test_configure_name_and_blank(self): + domain = "certbot.demo" + vhosts = [v for v in self.config.vhosts if v.name == domain or v.name is None] + achalls = [ + achallenges.KeyAuthorizationAnnotatedChallenge( + challb=acme_util.chall_to_challb( + challenges.HTTP01(token=((b'a' * 16))), + "pending"), + domain=domain, account_key=self.account_key), + ] + self.common_perform_test(achalls, vhosts) + def test_no_vhost(self): for achall in self.achalls: self.http.add_chall(achall) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index e536ec5ba..7d82559b6 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -16,6 +16,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). of the Certbot package will now always require acme>=X and version Y of a plugin package will always require acme>=Y and certbot=>Y. Specifying dependencies in this way simplifies testing and development. +* The Apache authenticator now always configures virtual hosts which do not have + an explicit `ServerName`. This should make it work more reliably with the + default Apache configuration in Debian-based environments. ### Fixed