Configuring OpenWRT for WiFi Matter Devices on an Offline VLAN
I recently bought some WiFi Matter smart bulbs and wanted to set them up on my pre-existing offline IoT VLAN, which I was using for mostly MQTT-based devices. However, when searching for information on how I should configure my network to support these devices, I found lots of incomplete info, unhelpful posts, straight-up misinformation, and threads full of frustrated people who just gave up. This made it seem much more complicated than it actually turned out to be. I hope this tutorial on setting up your WiFi Matter devices on an offline IoT VLAN using OpenWRT clears that up. First, Iām going to clear up some of the common misconceptions that I saw.
Common Misconceptions about WiFi Matter Device Networking + Offline IoT VLANs + IPv6
-
HomeAssistant + Matter WiFi devices need to be on the same network and Matter devices must have access to the internet for commissioning.
Matter WiFi devices can be on a seperate VLAN if the network is configured for it. Only the Matter server (python-matter-server) needs internet access and only during device commissioning to download the DCL certificates. -
You need a smartphone on the same network as the Matter device to commission it.
You do not even need a smartphone at all to commission a WiFi Matter device. If you have a bluetooth adaper forwarded into the python-matter-server docker container, you can commission directly from the python-matter-server web interface. If you are running a non-GAPPS Android ROM, like a lot of people who would be interested in an IoT privacy tutorial like this one, you can not commission Matter devices using the HA app and the easiest way to do it is with a forwarded bluetooth adapter while physically close to your Homeassistant server. -
Configuring a seperate offline IoT VLAN is complicated
Not really, you need to do much less than you think and OpenWRT provides all of the capabilities required to do it on a wide variety of hardware in any price range. You may even be able to flash your current router. -
Using WiFi Matter devices requires an ISP that supports IPv6
You can configure ULA IPv6 addressing so that your devices get a local IPv6 address irrespective of what your ISP does or does not do. I would recommend doing this anyways, so your devices will continue to work as expected, even when you have an internet outage. -
IPv6 = All of your devices are publicly accessable
IPv6 can (but does not have to) provide a globally-routable address for every device. However, your router still acts as a stateful firewall and can block or allow public traffic to any device on your network as you see fit. You can also choose if you only want devices to have ULA (local) IPv6 addresses on a network, GUA (globally routable), or both. Devices in our IoT network in this tutorial will only have ULA addresses, while our HomeAssistant server will have both. With carrier-grade NAT becoming the new norm for many home internet connections, learning IPv6 may help you solve the networking problems CGN causes for you in a more direct way than CGN-bandaids like cloudflare tunnels, tailscale, pangolin, etc.
Prerequisites (this is really all you need)
- HomeAssistant + python-matter-server Docker containers setup on your HomeAssistant server
- An OpenWRT-flashed router + SSH access to it (all config changes below will be done by editing config files)
- Some basic knowledge of IPv6 is desirable to understand the steps below, but not required.
Objectives
- Configure 2 seperate networks for HomeAssistant (online) and IoT devices (offline)
- Implement IPv6 ULA addressing for both networks to allow for expected operation without a WAN connection
- Configure mDNS reflector to forward mDNS between IoT and Homeassistant broadcast domains
- Configure OpenWRT firewall rules to allow Homeassistant to discover and control Matter IoT devices while keeping them isolated from the internet + the rest of your network
Configure Network
First, configure the homeassistant and iot networks. You will need to create a couple of devices, called br-hass and br-iot, for your VLANs, then add them to the networks shown in the config below. Configuring the VLANs for the switch ports varies depending on whether your router uses swconfig or DSA, but OpenWRT has guides for both. After you have added the network, you can also add a wireless interface to it if you want in /etc/config/wireless. You could also connect an access point to the ethernet interface you configured and put it on a seperate, non-conflicting 2.4Ghz channel and use that to connect your IoT devices to if you expect to have a lot of Wifi devices. Note option ip6class ālocalā in the iot network. IoT devices will only get a ULA address, while HomeAssistant will get both ULA and GUA addressing if a WAN connection is available or ULA-only otherwise.
/etc/config/network
config globals globals
option ula_prefix 'fda7::/48'
config interface 'homeassistant'
option proto 'static'
option ipaddr '192.168.2.1'
option netmask '255.255.255.0'
option device 'br-hass'
option ip6assign '64'
option ip6hint '2'
config interface 'iot'
option proto 'static'
option ipaddr '192.168.3.1'
option netmask '255.255.255.0'
option device 'br-iot'
option ip6assign '64'
option ip6hint '3'
option ip6class 'local'
Configure DHCP
Next, configure DHCP. I used DHCPv6 addressing only on the homeassistant network and SLAAC addressing only on the IoT network. I wouldāt count on DHCPv6 working with all IoT devices (Android, for example, doesnāt support it) and thereās not much of a use case for static leases there anyways, so I just use SLAAC on that network. The dhcp_option lines set the OpenWRT router as the NTP server. You can omit them if you do not want to do this. Also, set a static lease for your HA server while youāre here.
/etc/config/dhcp
config dhcp 'homeassistant'
option interface 'homeassistant'
option start '100'
option limit '150'
option leasetime '12h'
option dhcpv4 'server'
option dhcpv6 'server'
option ra 'server'
option ra_slaac '0'
list ra_flags 'managed-config'
list ra_flags 'other-config'
option ra_default '2'
list dhcp_option '42,192.168.2.1'
list dhcp_option '56,fda7:0:0:2::1'
config dhcp 'iot'
option start '100'
option limit '150'
option leasetime '12h'
option interface 'iot'
option dhcpv4 'server'
option dhcpv6 'server'
option ra 'server'
option ra_slaac '1'
list ra_flags 'other-config'
option ra_default '2'
list dhcp_option '42,192.168.3.1'
list dhcp_option '56,fda7:0:0:3::1'
config host
option name 'homeassistant'
option dns '1'
option ip '192.168.2.3'
option duid 'your_homeassistant_server_duid'
option mac 'your_homeassistant_server_mac_address'
option hostid '3'
Configure Avahi-Daemon
Matter relies on mDNS for device discovery, however, mDNS does not normally traverse broadcast domains. To allow it do do so, you need to setup an avahi-daemon mDNS reflector, which will forward the traffic between VLANs.
opkg update && opkg install avahi-daemon
Edit the /etc/avahi/avahi-daemon.conf file and make the following changes to the lines shown below.
/etc/avahi/avahi-daemon.conf
[server]
use-ipv4=no
use-ipv6=yes
allow-interfaces=br-hass,br-iot
[reflector]
enable-reflector=yes
reflect-ipv=no
Configure Firewall
Here are the firewall rules that I use for my IoT VLAN as it relates to Matter devices. Note that there are some personal preferences in this config (DROP vs REJECT, hijacking NTP to force using OpenWRTās builtin NTP server). If this is a new IoT network and you are just going to use Matter devices, the config below is all you need. Otherwise, add your existing rules for devices using other protocols such as MQTT and HTTP. Note that thereās no IPv4 rules in regards to mDNS or Matter communication. The Matter spec does not require IPv4 support at all, while it does require IPv6, so no point in supporting IPv4 here.
/etc/config/firewall
config zone
option name 'homeassistant'
option output 'ACCEPT'
option forward 'DROP'
list network 'homeassistant'
option input 'DROP'
config forwarding
option src 'homeassistant'
option dest 'wan'
config rule
option name 'Allow-MLD'
option src 'homeassistant'
option proto 'icmp'
option src_ip 'fe80::/10'
list icmp_type '130/0'
list icmp_type '131/0'
list icmp_type '132/0'
list icmp_type '143/0'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Input'
option src 'homeassistant'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
list icmp_type 'router-solicitation'
list icmp_type 'neighbour-solicitation'
list icmp_type 'router-advertisement'
list icmp_type 'neighbour-advertisement'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Forward'
option src 'homeassistant'
option dest '*'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'homeassistant-DHCP'
option proto 'udp'
option src 'homeassistant'
option src_port '68'
option dest_port '67'
option target 'ACCEPT'
config rule
option name 'homeassistant-DHCPv6'
option proto 'udp'
option src 'homeassistant'
option dest_port '547'
option src_port '546'
option target 'ACCEPT'
config rule
option name 'homeassistant-DNS'
option src 'homeassistant'
option dest_port '53'
option target 'ACCEPT'
config rule
option name 'homeassistant-NTP'
option proto 'udp'
option src 'homeassistant'
option dest_port '123'
option target 'ACCEPT'
config redirect
option target 'DNAT'
option proto 'udp'
option family 'any'
option src 'homeassistant'
option src_dport '123'
option name 'Use-Router-NTP-homeassistant'
config zone
option name 'iot'
option output 'ACCEPT'
option forward 'DROP'
list network 'iot'
option input 'DROP'
config rule
option name 'Allow-MLD'
option src 'iot'
option proto 'icmp'
option src_ip 'fe80::/10'
list icmp_type '130/0'
list icmp_type '131/0'
list icmp_type '132/0'
list icmp_type '143/0'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Input'
option src 'iot'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
list icmp_type 'router-solicitation'
list icmp_type 'neighbour-solicitation'
list icmp_type 'router-advertisement'
list icmp_type 'neighbour-advertisement'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'Allow-ICMPv6-Forward'
option src 'iot'
option dest '*'
option proto 'icmp'
list icmp_type 'echo-request'
list icmp_type 'echo-reply'
list icmp_type 'destination-unreachable'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'bad-header'
list icmp_type 'unknown-header-type'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
config rule
option name 'iot-DHCP'
list proto 'udp'
option src 'iot'
option src_port '68'
option dest_port '67'
option target 'ACCEPT'
config rule
option name 'iot-DHCPv6'
option proto 'udp'
option src 'iot'
option dest_port '547'
option src_port '546'
option target 'ACCEPT'
config rule
option name 'iot-DNS'
option src 'iot'
option dest_port '53'
option target 'ACCEPT'
config rule
option name 'iot-NTP'
list proto 'udp'
option src 'iot'
option dest_port '123'
option target 'ACCEPT'
config redirect
option target 'DNAT'
list proto 'udp'
option src 'iot'
option src_dport '123'
option name 'Use-Router-NTP-iot'
config rule
option name 'homeassistant-MDNS-v6'
option src 'homeassistant'
option dest_port '5353'
option target 'ACCEPT'
option proto 'udp'
option dest_ip 'ff02::fb'
option family 'ipv6'
config rule
option name 'homeassistant-iot-matter-v6'
option src 'homeassistant'
option dest 'iot'
option target 'ACCEPT'
option family 'ipv6'
option dest_port '5540'
list src_ip '::2:0:0:0:3/-60'
option proto 'tcp udp'
config rule
option name 'iot-MDNS-v6'
option src 'iot'
option dest_port '5353'
option target 'ACCEPT'
option proto 'udp'
option dest_ip 'ff02::fb'
option family 'ipv6'
You can then either restart all of the relevant services, or just reboot your router, then you will be ready to start adding your WiFi Matter devices.
Hope this helped you understand what you actually need to get WiFi Matter devices working on your offline IoT VLAN. Please follow up in the comments with any questions.