Configuring OpenWRT for WiFi Matter Devices on an Offline VLAN

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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

1 Like

Matter instructions: Scan the QR code and it will work. Simplez. Guaranteed.

Above: Lots of details. Well documented, but involved.

Sighs. We aren’t there yet folks. Somebody told fibs…

Well there’s obviously easier ways to connect a matter device if you just don’t care about network security or privacy, but this guide was intended for people who do to find the info in one place.

I’ll admit that this config is not ā€œeasyā€ for a non-technical audience, but that audience isn’t going to be using OpenWRT or care about network security or privacy anyways. The audience I wrote for has some technical skill and is willing to learn new concepts and improve their skills + knowledge for things they don’t know. I always appreciate reading a technical + comprehensive guide like this and wanted to write one of my own to contribute back.

I appreciate the time and effort you took to write this and collate it into one place. Bravo. No criticism directed at you whatsoever. Only respekt.

It is the sheeple, blindly following AI slurp, that hopefully will finally stumble here after trying all the possible permutations they have been fed, that I feel sorry for.

Until it works, automagically, in all circumstances, we are not there yet. A sad reflection on the state of the art, and the computer industry overall.