Skip to content

Add configurable DNS search domains for supervised containers#6893

Open
joshuaboniface wants to merge 4 commits into
home-assistant:mainfrom
joshuaboniface:custom-dns-search
Open

Add configurable DNS search domains for supervised containers#6893
joshuaboniface wants to merge 4 commits into
home-assistant:mainfrom
joshuaboniface:custom-dns-search

Conversation

@joshuaboniface

@joshuaboniface joshuaboniface commented May 29, 2026

Copy link
Copy Markdown

Proposed change

Currently, the HA Supervisor forces a DNS search domain of local.hass.io in /etc/resolv.conf on all containers due to the Supervisor's management of the entire Docker stack on a host. However, there can be advanced usecases where someone might want a different DNS search domain, for instance to easily enable DNS short names within a different domain. In my case, my entire home automation network uses a.domain.tld, and thus, containers like the ESPHome Builder would simply fail to resolve any short names, since those hosts are not resolvable in the local.hass.io domain.

This PR, in combination with a peer PR in the CLI, allow operators to override the DNS search domain list written into every supervised container's /etc/resolv.conf (previously hardcoded to local.hass.io). The new search_domains option is persisted in dns.json and exposed via the DNS REST API. When no custom domains are configured the existing default (local.hass.io) is preserved for backward compatibility.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (which adds functionality to the supervisor)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • The code change is tested and works locally. Yes, I've been running it locally since February.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Ruff (ruff format supervisor tests)
  • Tests have been added to verify that the new code works.

If API endpoints or add-on configuration are added/changed:

  • Documentation added/updated for developers.home-assistant.io I haven't see anywhere where most of this CLI is documented; happy to update something if you can point me to the right place!
  • CLI updated (if necessary)
  • Client library updated (if necessary) N/A

Allow operators to override the DNS search domain list written into
every supervised container's /etc/resolv.conf (previously hardcoded to
local.hass.io). The new `search_domains` option is persisted in dns.json
and exposed via the DNS REST API. When no custom domains are configured
the existing default (local.hass.io) is preserved for backward
compatibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@joshuaboniface joshuaboniface marked this pull request as ready for review May 29, 2026 04:12
@mdegat01 mdegat01 added breaking-change Change which breaks existing functionality or API. new-feature A new feature labels Jun 1, 2026
@mdegat01

mdegat01 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

This is a pretty significant breaking change. The local.hass.io search domain was only intended for use within the docker network to allow addons, home assistant and plugins to talk to each other. It was never about making a search domain that functioned on the larger network. We'd have to try and evaluate the impact of this to see what all would break... Perhaps we could make the configured search domains add to the default one of local.hass.io? Then it would no longer be a breaking change.

Though how would the internal search domain have an impact on your larger network? Do you have routing setup to expose all containers on your lan? If so you may want to reconsider that, a lot of addons use host binding in lieu of traditional auth and assume they are unreachable outside the docker network. For example, any addon which uses ingress

@joshuaboniface

joshuaboniface commented Jun 1, 2026

Copy link
Copy Markdown
Author

@mdegat01 Thank you for the feedback. It should only be breaking if the default is changed explicitly by the administrator; it remains local.hass.io otherwise.

The issue I ran into was simply, that the ESPHome Builder container could not resolve the short names of my devices. To provide a bit more detail...

  1. All devices do DHCP to my routers and are provisioned in the a.domain.tld DNS zone. So a device called garage-door has a DNS address of garage-door.a.domain.tld.
  2. In Home Assistant + ESPHome Builder, devices are adopted, etc. with a short name, i.e. garage-door.
  3. With the search domain set to local.hass.io, the ESPHome Builder container tries to resolve this as garage-door.local.hass.io, which fails, because that is not a valid hostname. It never tries to resolve garage-door.a.domain.tld because it has no knowledge of this domain.

The ESPHome Builder example is just one; another could be security cameras + Frigate, or other similar integrations.

Last year, this all worked as expected, so at first I thought this might be a bug, but I wasn't able to find any commits that changed this behaviour in any of the main projects. At that point I began suspecting there was something deeper, and that's when I stumbled upon this. I won't claim to say that it's the best solution, but it does seem to work so far.

I'm happy to have it always include "local.hass.io" and just append additional domains, if that is the better design, but I also haven't noticed any issues running this for a few months and with a number of apps communicating with each other.

@mdegat01 mdegat01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok we're on the same page now, I understand your use case. Two things though:

  1. This is currently a breaking change because of the use case of inter-container communication I detailed in the comment below. Lets keep local.hass.io in the list so I can remove that label.
  2. That _create_container_config method is only run to set up a new container. Once the container exists you have to rebuild it to change its config. Fortunately we already encountered this use case when we had to change the PropagationMode for mounts so you can leverage an existing check here:

def _check_docker_config(self) -> None:
"""Check docker config and make issues."""
new_issues: set[Issue] = set()
if _check_container(self.sys_homeassistant.core.instance):
new_issues.add(Issue(IssueType.DOCKER_CONFIG, ContextType.CORE))
for app in self.sys_apps.installed:
if _check_container(app.instance, app):
new_issues.add(
Issue(
IssueType.DOCKER_CONFIG, ContextType.ADDON, reference=app.slug
)
)
for plugin in self.sys_plugins.all_plugins:
if _check_container(plugin.instance):
new_issues.add(
Issue(
IssueType.DOCKER_CONFIG,
ContextType.PLUGIN,
reference=plugin.slug,
)
)
# Make an issue for each container with a bad config
for issue in new_issues - self.current_issues:
self.sys_resolution.add_issue(
issue, suggestions=[SuggestionType.EXECUTE_REBUILD]
)
# Dismiss issues when container config has been fixed
for issue in self.current_issues - new_issues:
self.sys_resolution.dismiss_issue(issue)

If you update this _check_container method used in there:

def _check_container(container: DockerInterface, app=None) -> bool:
"""Check if container has mount propagation issues requiring recreate.
For apps, only validates mounts explicitly configured (not Docker VOLUMEs).
For Core/plugins, validates all /media and /share mounts.
"""
# For apps, check mounts against their actual configured targets
if app is not None:
app_mapping = app.map_volumes
configured_targets = set()
# Get actual target paths from app configuration
if MappingType.MEDIA in app_mapping:
target = app_mapping[MappingType.MEDIA].path or PATH_MEDIA.as_posix()
configured_targets.add(target)
if MappingType.SHARE in app_mapping:
target = app_mapping[MappingType.SHARE].path or PATH_SHARE.as_posix()
configured_targets.add(target)
if not configured_targets:
return False
# Check if any configured targets have propagation issues
for mount in container.meta_mounts:
if (
mount.get("Destination") in configured_targets
and mount.get("Propagation") != PropagationMode.RSLAVE
):
return True
return False
# For Home Assistant Core and plugins, check default /media and /share paths
return any(
mount.get("Propagation") != PropagationMode.RSLAVE
for mount in container.meta_mounts
if mount.get("Destination") in [PATH_MEDIA.as_posix(), PATH_SHARE.as_posix()]
)

you can have it take a look at the DnsSearch option and ensure it reflects the current value of search_options then Supervisor should handle this part for you. It'll pop an repair for each container that is not setup correctly that can be used to easily rebuild the container when the user is ready since this issue has already been added:
https://github.com/home-assistant/core/blob/c22f10bf8742c9a4408e22cfce904e34e2e1d3a5/homeassistant/components/hassio/issues.py#L87

This is what the repair will say which is fortunately generic enough to still work fine for this use case 😆
https://github.com/home-assistant/core/blob/c22f10bf8742c9a4408e22cfce904e34e2e1d3a5/homeassistant/components/hassio/strings.json#L149-L161

This change will also handle plugins without any additional steps as they are automatically rebuilt without requiring user input.

Although just an FYI healthchecks are run once per hour so it may take up to an hour before Supervisor notices the config is out of date when you're doing testing. If you want it to notice faster you can add a call to healthcheck directly when search_domains changes via dns/options or dns/reset

Comment thread supervisor/docker/manager.py Outdated
Comment thread supervisor/api/dns.py
@home-assistant home-assistant Bot marked this pull request as draft June 1, 2026 16:41
@home-assistant

home-assistant Bot commented Jun 1, 2026

Copy link
Copy Markdown

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@agners agners left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to give a quick comment on this topic: DNS suffixes came up in the past, e.g. in home-assistant/plugin-dns#118. I definitely think we should support local DNS suffixes, but ideally also the ones learned through DHCP. Our DHCP client is on the OS side, so we'd have to transfer the information from NetworkManager to CoreDNS.

I am not very convinced that deploying CoreDNS as a Supervisor plug-in is a good solution for our DNS needs, exactly for such DHCP/DNS interactions it's rather cumbersome. I was considering dropping the DNS plug-in/CoreDNS in favor of just using systemd-resolved, but haven't gotten around to it.

Each additional features added to todays solution will make this transition a bit harder, so I am not very found of adding more features right now. But if apply toa systemd-resolved based solution cleanly, maybe it also won't be very hard to just migrate once we get around to make that transition 🤔 🤷 .

Always append DNS_SUFFIX to the effective search domain list at render
time, stripping any user-supplied duplicate first. This guarantees
local.hass.io is present in every container's resolv.conf and Docker
DnsSearch config regardless of operator-configured search domains.

Avoids the breaking change that removing `local.hass.io` will cause if
an override is set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joshuaboniface

Copy link
Copy Markdown
Author

Interesting @agners I didn't see that - I only checked this repo not the DNS plugin repo. Thanks for that!

Do you think simply reading from the host system's resolv.conf, perhaps on supervisor startup, is a sensible solution there? That would cover the DHCP case without too much additional logic I don't think.

- Use set union for DnsSearch in container config per reviewer suggestion,
  ensuring local.hass.io is always present without assuming list ordering
- Re-render Supervisor's resolv.conf immediately when search_domains
  changes via dns/options or dns/reset, not only at startup
- Add DnsSearch validation to _check_container so the docker config
  health check flags containers whose DnsSearch no longer matches the
  configured search domains, triggering a rebuild suggestion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joshuaboniface

joshuaboniface commented Jun 3, 2026

Copy link
Copy Markdown
Author

Pushed changes for review feedback, going to do some local testing myself before marking ready for further review.

I can also do up a PoC of the "read from the host resolv.conf" if we think this will be beneficial!

Testing results:

  • I successfully get the "The default configuration for apps and Home Assistant has changed. To update the configuration with the new defaults, a restart is required for the following:" prompt as expected.
  • Search list now includes local.hass.io as expected, as the last entry behind my overrides.

Only check DnsSearch against configured search domains for containers
that were started with DNS enabled (i.e. have a Dns key in HostConfig).
Containers created with dns=False never receive DnsSearch and were
incorrectly flagged on every health check cycle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@joshuaboniface

Copy link
Copy Markdown
Author

So far so good, no issues to report from my side. I didn't do the "read resolv.conf" portion yet, but I think that could be a separate PR if we want it. Marking ready for review again!

@joshuaboniface joshuaboniface marked this pull request as ready for review June 7, 2026 18:10
@home-assistant home-assistant Bot requested a review from mdegat01 June 7, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Change which breaks existing functionality or API. cla-signed new-feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants