You’ve done the right thing: you put your IoT gadgets on their own VLAN, locked down the firewall rules, and tested that your phone can still ping the Chromecast. Everything looks good—until you open the Google Home app and it reports “device not found.” Home Assistant, sitting on the main LAN, can’t discover that new WiFi plug. The IP connectivity is perfect, but discovery is dead. The culprit is multicast DNS (mDNS), a protocol that makes “it just works” possible on a single subnet and ensures it breaks the moment you introduce VLAN boundaries. The fix isn’t to flatten your network or poke holes in the firewall; it’s to deploy an mDNS repeater—a lightweight listener that selectively echoes discovery packets across subnets. By the end of this article, your Home Assistant server will see devices on VLAN 20 as if they were plugged into the same switch, and you’ll understand exactly why your firewall rules were never going to help.
What mDNS Actually Does (and Why It Stays in Its Lane)
Multicast DNS is the engine behind zero-configuration naming and service discovery. When your phone looks for a printer, it doesn’t query a traditional DNS server; it sends a multicast query to the well-known group address 224.0.0.251 (IPv4) or ff02::fb (IPv6), asking “who has the name photosmart.local?” The printer, listening on that address, answers directly with its IP and a list of services. This is how Apple Bonjour, Chromecast, HomeKit, and Home Assistant’s own integrations find each other without any manual setup.
The protocol is deliberately link-local. Every mDNS packet carries an IPv4 Time‑To‑Live of 1, meaning routers drop it at the first hop. IPv6 multicast uses a link-local scope by default, achieving the same effect. This isn’t an oversight; it’s a guardrail that prevents a single query from cascading across a large network and causing a broadcast storm. The trade-off is that discovery stays confined to the subnet where the device physically or logically lives.
Now layer in VLAN segmentation. Home Assistant on VLAN 10 (subnet 192.168.10.0/24) can send a TCP request to a Shelly relay on VLAN 20 (192.168.20.0/24) without issue, because your router’s firewall allows that unicast traffic. But the Shelly’s mDNS announcements—the periodic “I’m here, I’m a _http._tcp service” messages—never reach the 224.0.0.251 address on VLAN 10. The router doesn’t forward them. Home Assistant’s integration scan listens for those announcements, hears nothing, and reports no new devices. The network is working, yet discovery fails silently.
The Repeater Mental Model: Forward, Don’t Route
An mDNS repeater is not a router. It doesn’t rewrite packet headers, NAT addresses, or consult a routing table. Instead, it listens on one interface for mDNS traffic, collects the queries and responses, and then re-advertises them out of other interfaces in their original multicast format. Think of it as a selective echo: a service announcement appearing on VLAN 20 is heard by the repeater’s interface there, and the repeater repeats it verbatim onto VLAN 10. The target devices see a legitimate multicast packet that appears to have originated on their own subnet, even though the real source is a hop away.
This distinction clears up the most common misconception: “I already have an inter-VLAN firewall rule, why doesn’t discovery work?” Firewall rules operate on unicast IP traffic—they can permit or deny packets between specific source and destination IPs. Multicast operates below that logic. A multicast frame is addressed to a group address, not to a host, and it never enters the routing pipeline. The router’s firewall can’t “allow” a multicast packet from one VLAN to another because the router’s job is to drop it at the interface boundary without inspection. The repeater works around this by generating new, locally-scoped multicast packets, not by forwarding the original ones.
It’s equally important to understand what the repeater does not handle. It forwards the discovery metadata—the service type strings like _googlecast._tcp.local, _hap._tcp.local for HomeKit, and _home-assistant._tcp.local—and it resolves .local hostnames. It does not proxy the actual data streams. After your phone discovers the Chromecast via the repeated mDNS, it still needs a direct TCP connection to the Chromecast’s IP to stream video. That traffic must have its own firewall rule. The repeater bridges the discovery gap, but the data plane remains your responsibility.
Choosing Your Repeater: Avahi-Daemon vs. OPNsense Plugin vs. Docker
The right implementation depends on where your VLAN gateway lives. Three options cover most home‑lab setups. The table below outlines the trade-offs; the following sections add the details.
| Approach | Where it runs | Pros | Cons | Best for |
|---|---|---|---|---|
| Avahi‑daemon reflector | Linux box acting as router (e.g., Debian router‑on‑a‑stick, dedicated Pi) | Full mDNS stack, parses and filters records, battle‑tested | Requires a Linux host with an interface in each VLAN; needs careful allow‑interfaces config | DIY routers where you control the OS |
| OPNsense/pfSense UDP Broadcast Relay plugin | OPNsense or pfSense firewall | No extra VM; config lives in the firewall GUI; simple to toggle | Generic relay, not mDNS‑aware—relays all UDP 5353 verbatim; can leak traffic if interfaces are misconfigured | Networks where the firewall is already the inter‑VLAN router |
| Docker container (Avahi) | Any machine with a leg in each VLAN and Docker | Isolated, self‑contained; can run on a NAS or a small server without touching the router | Requires host networking (--net=host); container must be privileged to bind to multiple interfaces; needs manual interface mapping |
Environments with a managed L3 switch or a router you can’t modify |
Avahi-Daemon on a Linux Box or VM
Avahi is the open‑source implementation of the Zeroconf protocol suite, the same stack that underpins Bonjour on Linux. Its reflector mode turns an Avahi instance into an mDNS repeater. The configuration is straightforward: set enable-reflector=yes in /etc/avahi/avahi-daemon.conf, and then restrict the interfaces with allow-interfaces=eth0.10,eth0.20. Without that restriction, Avahi will happily reflect mDNS traffic onto your WAN interface, advertising your internal devices to the internet—a serious privacy and security mistake. This approach is ideal when your inter‑VLAN router is a Linux machine that already has a VLAN subinterface in each subnet. A dedicated Raspberry Pi with a trunk port can also fill this role.
OPNsense/pfSense UDP Broadcast Relay Plugin
If your firewall is the gateway, the os-udpbroadcastrelay plugin is a pragmatic choice. It’s not a true mDNS daemon; it’s a generic multicast and broadcast relay that can forward UDP traffic on a specific port—5353 for mDNS—between interfaces. After installation, you add a relay entry: listen on the IoT interface, forward to the LAN interface (and vice versa), set the source port and destination port to 5353, and point the destination address to 224.0.0.251. Because it relays packets without parsing them, it cannot filter by service type, but for simple home setups that’s rarely a problem. The risk is that if you accidentally include the WAN interface, you’ll leak mDNS outside. Always double‑check the interface selection.
Home Assistant Add-On or Docker Container
When you don’t control the router—say, you’re using a UniFi USG or a managed L3 switch that handles inter‑VLAN routing—an Avahi container can sit on a machine that has a trunk connection or a dedicated NIC in each VLAN. The container must run with --net=host so it can see the physical interfaces, and it needs to be configured with the exact interface names visible inside the container. The avahi-daemon Docker image supports environment variables to set the reflector and allowed interfaces. This setup keeps the repeater independent of the network hardware, but it does add a dependency on that host remaining online for cross‑VLAN discovery to work.
Worked Example: Avahi Reflector on a Debian Router-on-a-Stick
Here’s a concrete walkthrough with real addresses. The network has two VLANs:
- VLAN 10 (Main):
192.168.10.0/24, router interfaceeth0.10at192.168.10.1 - VLAN 20 (IoT):
192.168.20.0/24, router interfaceeth0.20at192.168.20.1
Home Assistant is at 192.168.10.50. A Sonos speaker sits on the IoT VLAN at 192.168.20.100. The Debian router already routes between the subnets, and firewall rules allow TCP traffic from the main LAN to the IoT network. Discovery is broken.
Step 1: Install Avahi.
sudo apt update && sudo apt install avahi-daemon
sudo systemctl stop avahi-daemon
Step 2: Edit the configuration.
Open /etc/avahi/avahi-daemon.conf and locate the [reflector] section. Change it to:
[reflector]
enable-reflector=yes
reflect-ipv=yes
allow-interfaces=eth0.10,eth0.20
reflect-ipv=yes is only needed if you use IPv6 for discovery. The allow-interfaces line is critical—without it, Avahi will reflect mDNS onto every interface, including eth0 if it’s your WAN. That would expose internal device names to your ISP’s network.
Step 3: Start the daemon and verify.
sudo systemctl start avahi-daemon
sudo systemctl status avahi-daemon
Look for lines indicating the reflector is active and bound to the listed interfaces. No errors should appear.
Step 4: Test discovery from the Home Assistant box.
On the HA machine (or any Linux host on VLAN 10), run:
avahi-browse -a -r
You should see entries like Sonos Room _googlecast._tcp local with the IoT IP address 192.168.20.100. From a macOS machine on the main LAN, the equivalent command is dns-sd -B _googlecast._tcp local. The Sonos now appears as if it were on the same subnet.
The three things that will trip you up:
- No
allow-interfaces: If you skip this, Avahi reflects onto every interface. On a router with a WAN link, you’ll leak mDNS to the internet. Always lock it down. - Host firewall on the router itself: The repeater emits new multicast packets from the router’s own interface IPs. If the router’s local firewall (iptables/nftables) blocks outbound UDP 5353 to
224.0.0.251on those VLAN interfaces, the reflected packets will be dropped before they leave the router. Check that the output chain allows this traffic—most default setups do, but a hardened router might not. - Confusing mDNS with SSDP: This fix only handles mDNS. Many media devices and UPnP/DLNA services use SSDP (multicast to
239.255.255.250on port 1900) for discovery. That’s a separate protocol and requires a different relay, such assocator a dedicated SSDP forwarder. Don’t expect your smart TV’s DLNA server to appear just because the Chromecast now works.
Integrating with Home Assistant and Verifying Discovery
Home Assistant’s integrations use the host operating system’s mDNS stack, so once the repeater is running, no special configuration is needed. The discovery scanner runs periodically—typically every few minutes—and picks up the now‑visible _home-assistant._tcp and device‑specific service types. New devices will show up automatically under Settings > Devices & Services in the “Discovered” section.
If you want to force an immediate scan, you can restart Home Assistant, or use the service homeassistant.update_entity on an existing discovery entity, but the simplest method is to wait. To verify that the repeater is doing its job without waiting, log into the Home Assistant host via SSH and run avahi-browse -a -r (or dns-sd -B _http._tcp on macOS). If you see the IoT devices, Home Assistant will see them too. Also, from a device on the IoT VLAN, ping homeassistant.local—the name resolution should now return the HA server’s IP on VLAN 10, confirming that the repeater is working in both directions.
Once discovery is healthy, go back to your firewall rules and ensure that the actual data connections (HTTP to the Shelly, TCP to the Chromecast) are allowed. The repeater has opened the door; now you need to let the traffic through.
An mDNS repeater is a small, surgical addition that restores the “just works” feeling of a flat network while preserving the security isolation of VLANs. Pick the implementation that aligns with where your gateway brain lives—a Linux router, a firewall, or a separate container—and pay close attention to the interface allowlist. With that in place, your Home Assistant dashboard will populate with devices from every subnet, and you’ll have one less reason to wonder if your network is lying to you.