Turning an OpenWrt router into a wireless bridge with relayd
Posted on
Contents
I had a spare TP-Link Archer AX21 running a plain OpenWrt snapshot, and a room with a couple of wired-only devices and no ethernet run to it. I wanted the router to join the existing WiFi and hand that connection over to its ethernet ports, so the wired devices show up on the main network like they were plugged into the main router. Basically, a wireless bridge.
The OpenWrt relay configuration docs cover what relayd is actually doing under the hood. Here’s the full set of commands on a plain install with no LuCI.
Before you start
Plug your laptop into one of the LAN ports and ssh in. On a fresh install there’s no root password yet.
1ssh [email protected]
Everything below runs on the router. My upstream network is 192.168.0.0/24 with the main router at 192.168.0.1. Swap that for yours.
Move the LAN off 192.168.1.x
Out of the box OpenWrt puts its LAN on 192.168.1.1/24, and odds are your upstream network is 192.168.1.0/24 as well. The router can’t get a 192.168.1.x address from upstream while it’s also serving 192.168.1.x on the LAN side, so if that’s your situation, move the LAN first:
1uci set network.lan.ipaddr='192.168.99.1'
2uci commit network
3reload_config
Your ssh session drops because the router’s address just changed. Unplug and replug the cable so your laptop picks up a 192.168.99.x lease, then ssh back in at the new address:
1ssh [email protected]
This is temporary. The LAN ends up with an address in the upstream subnet at the end anyway.
Join the upstream WiFi as a client
First figure out which radio to use. Each radio is one band:
root@OpenWrt:~# uci show wireless | grep band
wireless.radio0.band='2g'
wireless.radio1.band='5g'
Match that to the band your upstream network is on. If it’s the same SSID on both bands, go with 5 GHz. You can confirm the router actually sees it:
1iwinfo radio1 scan | grep ESSID
Mine is on radio1, which is what the rest of this uses. Swap in radio0 if yours is on 2.4 GHz.
1uci set network.wwan=interface
2uci set network.wwan.proto='dhcp'
3uci commit network
4
5uci set wireless.radio1.disabled='0'
6uci set wireless.radio1.country='US'
7uci set wireless.default_radio1.disabled='1'
8uci set wireless.wwan=wifi-iface
9uci set wireless.wwan.device='radio1'
10uci set wireless.wwan.network='wwan'
11uci set wireless.wwan.mode='sta'
12uci set wireless.wwan.ssid='MyUpstreamWiFi'
13uci set wireless.wwan.encryption='psk2'
14uci set wireless.wwan.key='MyUpstreamPassword'
15uci commit wireless
16
17uci add_list firewall.@zone[1].network='wwan'
18uci commit firewall
19
20reload_config
A few things going on here:
wwanis a new interface that gets its address from the upstream router over DHCPdefault_radio1is the stock AP that ships on every radio. It’s an open network called “OpenWrt”, and turning the radio on for the client would turn it on too. Disable it.@zone[1]is the wan zone on a stock firewall config and@zone[0]is lan.wwangoes in wan for now.reload_configpokes every service whose config changed, so network, wireless and firewall all pick this up
Give it a few seconds and check it got a lease:
1ifstatus wwan | jsonfilter -e '@["ipv4-address"][0].address'
At this point the router is online as a regular NAT router. Anything on the LAN ports gets an address from the router and goes out through the WiFi. Not what we want yet, but we need the internet for the next step.
Fix the clock and install relayd
A router with no RTC boots up thinking it’s the firmware build date, and TLS refuses certificates that aren’t valid yet. So sync the clock first, by IP so it doesn’t depend on DNS either:
1ntpd -q -n -p 162.159.200.123 -p 216.239.35.0 -p 129.6.15.28
2apk update
3apk add relayd
relayd ships both the daemon and the netifd relay protocol handler, which is all we need. If you do have LuCI, also add luci-proto-relay so the interface shows up properly there. On 24.10 and older it’s opkg instead of apk.
Turn the LAN into a relay
This is the step that changes the router’s address, so your ssh session will die at the end of it. That’s expected.
Pick a free address for the router in the upstream subnet, ideally outside the upstream DHCP pool. I used .250 and gave it a static reservation on the main router so nobody else gets handed it.
1uci set network.lan.proto='static'
2uci set network.lan.ipaddr='192.168.0.250'
3uci set network.lan.netmask='255.255.255.0'
4uci set network.lan.gateway='192.168.0.1'
5uci set network.lan.dns='192.168.0.1'
6uci -q delete network.lan.ip6assign
7uci set dhcp.lan.ignore='1'
8uci set network.stabridge=interface
9uci set network.stabridge.proto='relay'
10uci add_list network.stabridge.network='lan'
11uci add_list network.stabridge.network='wwan'
12uci del_list firewall.@zone[1].network='wwan'
13uci add_list firewall.@zone[0].network='wwan'
14uci commit
15
16reload_config
What this does:
langets a static address in the upstream subnet instead of its own- the local DHCP server is turned off, so clients get their leases from upstream
stabridgeis the relay interface that tieslanandwwantogetherwwanmoves from the wan zone into the lan zone, because bridged traffic shouldn’t be NATed
Your laptop still has its old lease from the router at this point, so unplug and replug the cable to get a fresh one from upstream.
Check it works
The laptop should now have an address from the upstream router, in my case 192.168.0.x, and you can ssh back in at the new address:
1ssh [email protected]
relayd should be running with both interfaces:
root@OpenWrt:~# ps | grep '[r]elayd'
2941 root 1104 S relayd -I br-lan -I phy1-sta0 -D -B -t 30 -p 60
And from any other machine on the main network, ping the laptop that’s plugged into the bridge. If that answers, you’re done. It’s a switch now.
If the router never comes back and you can’t reach it at either address, don’t overthink it. Hold the reset button for a factory reset and start over from the top. Worst case you lose ten minutes.
What’s next
If something goes wrong and you end up factory resetting, you have to reinstall LuCI and relayd all over again. You can of course fold them into one image, which I will cover in a subsequent post.