Defeating Subnet-Locked IoT: Homebridge Across VLANs Without Cloud Relays
Running IoT devices on an isolated VLAN is good security practice. Keeping local smart home control working after you've done it is a genuinely difficult engineering problem — and one that most smart home platforms are not designed to help you solve.
This post documents how I got Homebridge-controlled TP-Link Tapo and Kasa devices working reliably across VLAN boundaries, with no cloud relay and no compromise to the network segmentation that made the isolation worthwhile in the first place.
The Setup
My home lab runs a Ubiquiti UniFi network with strict 802.1Q VLAN segmentation. IoT devices live on a dedicated IoT VLAN with firewall rules that prevent them from initiating connections to the trusted LAN. The Homebridge instance runs on a Docker container on the server VLAN, which has its own isolation profile.
The goal: Homebridge on the server VLAN needs to send commands to TP-Link smart plugs and switches on the IoT VLAN — locally, without any traffic leaving the building.
Why This Is Hard
Most smart home device control relies on two assumptions that VLAN segmentation violates:
1. mDNS / Bonjour discovery is subnet-scoped
mDNS (Multicast DNS) and Bonjour are the protocols devices use to announce themselves on a local network — "Hello, I'm a Tapo P115 at 192.168.x.x." These announcements use multicast IP addresses that routers, by design, do not forward across subnet boundaries. A device on the IoT VLAN simply cannot be discovered by a service on the server VLAN through standard mDNS.
2. TP-Link's KLAP protocol is encrypted and subnet-aware
More recently, TP-Link introduced the KLAP (Kasa Local API Protocol) authentication handshake across their device range. KLAP includes device-side checks that make cross-subnet requests fail — even if you know the device's IP address — because the handshake was designed to work within a single broadcast domain.
The combination of these two problems means that simply allowing traffic between VLANs is not sufficient. The discovery layer and the authentication layer both need to be addressed.
What Doesn't Work
Before covering the solution, it's worth documenting the approaches that failed:
- Enabling inter-VLAN routing alone: Traffic can flow, but Homebridge still can't discover devices and KLAP handshakes still fail.
- mDNS reflection (Avahi): Reflects mDNS traffic between VLANs — partially useful, but doesn't solve the KLAP authentication problem and introduces its own complexity.
- Cloud-based control: Works, but defeats the entire purpose of local control and introduces external dependency for a system that should work independently of internet connectivity.
The Solution: Direct IP Binding with Explicit JSON Configuration
The working approach bypasses automatic discovery entirely and forces Homebridge to talk to each device by its static IP address.
Step 1: Static IP assignment for all IoT devices
Every TP-Link device on the IoT VLAN is assigned a static DHCP lease in the UniFi controller, based on MAC address. This gives each device a predictable, permanent IP address that doesn't change on reboot or lease renewal.
Step 2: Firewall rules permitting specific traffic flows
Explicit Traffic Rules in the UCG Fiber firewall permit traffic from the server VLAN to each IoT device's static IP on the ports used by the Tapo/Kasa API (TCP 9999 for legacy protocol, port 80 for KLAP). All other IoT VLAN access from the server VLAN is denied.
This is a surgical permission, not a broad "allow server VLAN to IoT VLAN" rule — the IoT devices still cannot initiate connections to the trusted LAN or server VLAN.
Step 3: Explicit JSON payload configuration in Homebridge
The homebridge-tplink-smarthome and related plugins support manual device configuration when automatic discovery isn't available. Rather than relying on discovery, each device is defined explicitly in the Homebridge config.json:
{
"platform": "TplinkSmarthome",
"addCustomCharacteristics": true,
"devices": [
{
"host": "192.168.x.x",
"port": 9999
},
{
"host": "192.168.x.y",
"port": 9999
}
]
}
The host field forces direct IP-to-IP binding, completely bypassing the mDNS discovery mechanism. The plugin connects directly to the device without needing to find it first.
Step 4: Addressing KLAP handshake failures
For newer TP-Link devices using the KLAP protocol, the plugin version matters significantly. Plugin versions that implement KLAP authentication correctly can complete the handshake even from a different subnet, provided the firewall permits the traffic and the device credentials are correctly supplied.
The configuration requires explicit credential fields:
{
"host": "192.168.x.z",
"username": "tplink_account@email.com",
"password": "account_password"
}
Some older plugin versions do not implement KLAP at all and will silently fail against newer firmware. Updating to a plugin version with full KLAP support resolved persistent connection failures that weren't obviously related to the network configuration.
Verifying the Setup
With everything configured, testing follows a simple progression:
- Ping from Homebridge container to IoT device IP — confirms firewall permits the traffic
- curl/netcat to device port — confirms the service is reachable
- Homebridge plugin logs — confirm successful authentication and device control
- HomeKit command — end-to-end test from iPhone to physical device without internet
Lessons Learned
Static IPs are non-negotiable for cross-subnet IoT control. Dynamic addressing and explicit JSON binding are fundamentally incompatible — the config breaks every time the device gets a new lease.
Plugin versions matter. TP-Link's firmware updates have shifted devices from legacy protocol to KLAP progressively. A plugin that worked six months ago may silently fail against updated firmware.
Broadcast isolation is good, but it requires compensating controls. Blocking mDNS across VLANs is the right security decision. The cost is that you need to manage device addressing and configuration explicitly — which is actually a better operational posture than relying on automatic discovery anyway.
The cloud option is always there as a fallback, but shouldn't be the primary path. Local control is faster, more reliable, and doesn't break when Kasa's servers have an outage.
The Result
Every TP-Link device on the IoT VLAN is now fully controllable through Homebridge and HomeKit — locally, without cloud relay, and without any compromise to the network segmentation that keeps IoT traffic isolated from the rest of the network.
The setup has been stable across firmware updates and Homebridge plugin updates, provided the plugin version is kept current with TP-Link's protocol changes.
For anyone running a properly segmented home network and fighting the same problem: the solution is direct IP binding, explicit credentials, and surgical firewall permissions. The automatic discovery layer is the source of almost all the friction — bypass it entirely.