Aatish Neupane

Turning an OpenWrt router into a wireless bridge with relayd

Posted on

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.

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:

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:

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:

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:

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.