Need help setting up netbird on openwrt router

Hello,

I have a Nanopi R3S LTS 2GB as an Openwrt router.
On my main-lan:
I configured Adguard Home and Unbound as my DNS Server. All my traffic exits through a Protonvpn server via Wireguard, port 51820. Ipv6 fully configured.

On my guest-lan:
No AGH, no protonvpn exit. Ipv6 fully configured.

I use PBR for routing traffic from guest-lan through wan, and for something else aswell.

I want to be able to connect to my home network from anywhere with my mobile devices, such that it’s like I’m at home in my main-lan with AGH, proton exit etc. In the past I used a direct wireguard connection with the wireguard app on my mobile devices, but I wanted to switch to netbird because I need the netbird features especially in the future.

Here is my current config, please tell me if you need to see something else:



root@nanopi:~# uci show network
network.loopback=interface
network.loopback.device='lo'
network.loopback.proto='static'
network.loopback.ipaddr='127.0.0.1/8'
network.globals=globals
network.globals.dhcp_default_duid='00047c79411fe9c14cb0807b16885eebad65'
network.globals.ula_prefix='fd39:9497:bd6::/48'
network.globals.packet_steering='1'
network.@device[0]=device
network.@device[0].name='br-lan'
network.@device[0].type='bridge'
network.@device[0].ports='eth1'
network.@device[1]=device
network.@device[1].name='eth1'
network.@device[1].macaddr='f6:44:20:63:01:15'
network.lan=interface
network.lan.device='br-lan'
network.lan.proto='static'
network.lan.ip6assign='64'
network.lan.ipaddr='192.168.10.1'
network.lan.multipath='off'
network.lan.netmask='255.255.255.0'
network.lan.defaultroute='0'
network.lan.delegate='0'
network.@device[2]=device
network.@device[2].name='eth0'
network.@device[2].macaddr='f6:44:20:63:01:14'
network.wan=interface
network.wan.device='eth0'
network.wan.proto='pppoe'
network.wan.username='...'
network.wan.password='...'
network.wan.ipv6='0'
network.wan.multipath='off'
network.wan.peerdns='0'
network.wan.delegate='0'
network.wan.sourcefilter='0'
network.wan.force_link='1'
network.wan6=interface
network.wan6.device='@wan'
network.wan6.proto='dhcpv6'
network.wan6.reqaddress='try'
network.wan6.reqprefix='auto'
network.wan6.norelease='1'
network.wan6.multipath='off'
network.wan6.peerdns='0'
network.wan6.force_link='1'
network.lan_guest=interface
network.lan_guest.proto='static'
network.lan_guest.device='eth1.2'
network.lan_guest.ipaddr='192.168.20.1'
network.lan_guest.netmask='255.255.255.0'
network.lan_guest.defaultroute='0'
network.lan_guest.multipath='off'
network.lan_guest.delegate='0'
network.lan_guest.ip6assign='64'
network.@wireguard_protonvpn[0]=wireguard_protonvpn
network.@wireguard_protonvpn[0].public_key='tBLnlY4CJsNGmh6qbDZTAogZZ+jIOvt4b2mCA8i97U4='
network.@wireguard_protonvpn[0].persistent_keepalive='25'
network.@wireguard_protonvpn[0].endpoint_host='2a02:6ea0:1703:3087::10'
network.@wireguard_protonvpn[0].endpoint_port='51820'
network.@wireguard_protonvpn[0].route_allowed_ips='1'
network.@wireguard_protonvpn[0].allowed_ips='::/0' '0.0.0.0/0' '::/1' '8000::/1'
network.@device[3]=device
network.@device[3].name='pppoe-wan'
network.@device[4]=device
network.@device[4].name='eth1.2'
network.@device[4].type='8021q'
network.@device[4].ifname='eth1'
network.@device[4].vid='2'
network.@device[4].macaddr='02:1A:2B:3C:4D:5E'
network.protonvpn=interface
network.protonvpn.proto='wireguard'
network.protonvpn.force_link='1'
network.protonvpn.private_key='...'
network.protonvpn.addresses='2a07:b944::2:2/128' '10.2.0.2/32'
network.protonvpn.multipath='off'
network.protonvpn.delegate='0'
network.protonvpn.mtu='1420'
network.@device[5]=device
network.@device[5].name='protonvpn'
network.@wireguard_homevpn[0]=wireguard_homevpn
network.@wireguard_homevpn[0].description='iPad'
network.@wireguard_homevpn[0].public_key='umiA/e8eyJq5eNP1PHs+BUOtu2u1MQcQuDMtJI+saD8='
network.@wireguard_homevpn[0].route_allowed_ips='1'
network.@wireguard_homevpn[0].persistent_keepalive='25'
network.@wireguard_homevpn[0].allowed_ips='fd10:10:10::3/128' '10.10.10.3/32'
network.@wireguard_homevpn[1]=wireguard_homevpn
network.@wireguard_homevpn[1].public_key='h8ovJJMP+7p74kOB41WnCDVspHf9YJl79VE+ObouaSk='
network.@wireguard_homevpn[1].route_allowed_ips='1'
network.@wireguard_homevpn[1].persistent_keepalive='25'
network.@wireguard_homevpn[1].description='iPhone'
network.@wireguard_homevpn[1].allowed_ips='fd10:10:10::2/128' '10.10.10.2/32'
network.netbird=interface
network.netbird.proto='none'
network.netbird.device='wt0'
network.netbird.defaultroute='0'
network.netbird.multipath='off'
network.netbird.delegate='0'
network.@device[6]=device
network.@device[6].name='wt0'



root@nanopi:~# uci show firewall
firewall.@defaults[0]=defaults
firewall.@defaults[0].input='REJECT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].forward='REJECT'
firewall.@defaults[0].synflood_protect='1'
firewall.@zone[0]=zone
firewall.@zone[0].name='lan'
firewall.@zone[0].input='ACCEPT'
firewall.@zone[0].output='ACCEPT'
firewall.@zone[0].forward='ACCEPT'
firewall.@zone[0].network='lan'
firewall.@zone[1]=zone
firewall.@zone[1].name='wan'
firewall.@zone[1].input='REJECT'
firewall.@zone[1].output='ACCEPT'
firewall.@zone[1].forward='REJECT'
firewall.@zone[1].masq='1'
firewall.@zone[1].mtu_fix='1'
firewall.@zone[1].network='wan' 'wan6'
firewall.@rule[0]=rule
firewall.@rule[0].name='Allow-DHCP-Renew'
firewall.@rule[0].src='wan'
firewall.@rule[0].proto='udp'
firewall.@rule[0].dest_port='68'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[0].family='ipv4'
firewall.@rule[0].enabled='1'
firewall.@rule[1]=rule
firewall.@rule[1].name='Allow-Ping'
firewall.@rule[1].src='wan'
firewall.@rule[1].proto='icmp'
firewall.@rule[1].icmp_type='echo-request'
firewall.@rule[1].family='ipv4'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[1].enabled='1'
firewall.@rule[2]=rule
firewall.@rule[2].name='Allow-IGMP'
firewall.@rule[2].src='wan'
firewall.@rule[2].proto='igmp'
firewall.@rule[2].family='ipv4'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[2].enabled='1'
firewall.@rule[3]=rule
firewall.@rule[3].name='Allow-DHCPv6'
firewall.@rule[3].src='wan'
firewall.@rule[3].proto='udp'
firewall.@rule[3].dest_port='546'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[3].enabled='1'
firewall.@rule[4]=rule
firewall.@rule[4].name='Allow-MLD'
firewall.@rule[4].src='wan'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].src_ip='fe80::/10'
firewall.@rule[4].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[4].family='ipv6'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[4].enabled='1'
firewall.@rule[5]=rule
firewall.@rule[5].name='Allow-ICMPv6-Input'
firewall.@rule[5].src='wan'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].family='ipv6'
firewall.@rule[5].target='ACCEPT'
firewall.@rule[5].enabled='1'
firewall.@rule[6]=rule
firewall.@rule[6].name='Allow-ICMPv6-Forward'
firewall.@rule[6].src='wan'
firewall.@rule[6].dest='*'
firewall.@rule[6].proto='icmp'
firewall.@rule[6].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[6].limit='1000/sec'
firewall.@rule[6].family='ipv6'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[6].enabled='1'
firewall.@rule[7]=rule
firewall.@rule[7].name='Allow-IPSec-ESP'
firewall.@rule[7].src='wan'
firewall.@rule[7].dest='lan'
firewall.@rule[7].proto='esp'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[7].enabled='1'
firewall.@rule[8]=rule
firewall.@rule[8].name='Allow-ISAKMP'
firewall.@rule[8].src='wan'
firewall.@rule[8].dest='lan'
firewall.@rule[8].dest_port='500'
firewall.@rule[8].proto='udp'
firewall.@rule[8].target='ACCEPT'
firewall.@rule[8].enabled='1'
firewall.@zone[2]=zone
firewall.@zone[2].name='lan_guest'
firewall.@zone[2].input='REJECT'
firewall.@zone[2].output='ACCEPT'
firewall.@zone[2].forward='REJECT'
firewall.@zone[2].network='lan_guest'
firewall.@forwarding[0]=forwarding
firewall.@forwarding[0].src='lan_guest'
firewall.@forwarding[0].dest='wan'
firewall.@rule[9]=rule
firewall.@rule[9].name='Allow-DHCP-Guest'
firewall.@rule[9].src='lan_guest'
firewall.@rule[9].proto='udp'
firewall.@rule[9].dest_port='67'
firewall.@rule[9].target='ACCEPT'
firewall.@rule[9].enabled='1'
firewall.@rule[10]=rule
firewall.@rule[10].name='Allow-ICMPv6-Guest'
firewall.@rule[10].src='lan_guest'
firewall.@rule[10].proto='icmp'
firewall.@rule[10].family='ipv6'
firewall.@rule[10].target='ACCEPT'
firewall.@rule[10].icmp_type='bad-header' 'destination-unreachable' 'neighbour-advertisement' 'neighbour-solicitation' 'packet-too-big' 'router-advertisement' 'router-solicitation' 'time-exceeded' 'unknown-header-type'
firewall.@rule[10].enabled='1'
firewall.@rule[11]=rule
firewall.@rule[11].name='Allow-DHCPv6-Guest'
firewall.@rule[11].src='lan_guest'
firewall.@rule[11].proto='udp'
firewall.@rule[11].dest_port='547'
firewall.@rule[11].target='ACCEPT'
firewall.@rule[11].enabled='1'
firewall.@zone[3]=zone
firewall.@zone[3].name='protonvpn'
firewall.@zone[3].input='REJECT'
firewall.@zone[3].output='ACCEPT'
firewall.@zone[3].forward='REJECT'
firewall.@zone[3].masq='1'
firewall.@zone[3].mtu_fix='1'
firewall.@zone[3].masq6='1'
firewall.@zone[3].network='protonvpn'
firewall.@forwarding[1]=forwarding
firewall.@forwarding[1].src='lan'
firewall.@forwarding[1].dest='protonvpn'
firewall.@rule[12]=rule
firewall.@rule[12].src='lan'
firewall.@rule[12].dest='wan'
firewall.@rule[12].name='Allow-fritzbox'
firewall.@rule[12].target='ACCEPT'
firewall.@rule[12].enabled='1'
firewall.@rule[12].src_ip='192.168.10.10'
firewall.@rule[12].family='ipv4'
firewall.@rule[12].proto='all'
firewall.@zone[4]=zone
firewall.@zone[4].name='netbird'
firewall.@zone[4].input='ACCEPT'
firewall.@zone[4].output='ACCEPT'
firewall.@zone[4].forward='ACCEPT'
firewall.@zone[4].network='netbird'
firewall.@zone[4].mtu_fix='1'
firewall.@zone[4].masq='1'
firewall.@zone[4].masq6='1'
firewall.@forwarding[2]=forwarding
firewall.@forwarding[2].src='netbird'
firewall.@forwarding[2].dest='lan'
firewall.@forwarding[3]=forwarding
firewall.@forwarding[3].src='lan'
firewall.@forwarding[3].dest='netbird'

pbr config:

config pbr 'config'
    option fw_mask 'ff000000'
    option uplink_mark '01000000'
    option uplink_ip_rules_priority '30000'
    option uplink_interface 'wan'
    option uplink_interface6 'wan6'

config policy
    option name 'Gastnetz wan'
    option src_addr '@eth1.2'
    option interface 'wan'

config policy
    option name 'Festnetz wan'
    option src_addr '192.168.10.10/32'
    option interface 'wan'

ip rule:

0:      from all lookup local
105:    from all lookup main suppress_prefixlength 0
110:    not from all fwmark 0x1bd00 lookup netbird
29997:  from all lookup main suppress_prefixlength 1
29998:  from all fwmark 0x3000000/0xff000000 lookup pbr_netbird
29999:  from all fwmark 0x2000000/0xff000000 lookup pbr_protonvpn
30000:  from all fwmark 0x1000000/0xff000000 lookup pbr_wan
32766:  from all lookup main

ip route table netbird:

$ ip route show table netbird
Error: ipv4: FIB table does not exist.
$ ip -6 route show table netbird
(empty)

Netbird nftables:

chain netbird-mangle-prerouting {
    iifname != "wt0" ct state new meta mark set 0x0001bd22
    iifname "wt0" ct state new meta mark set 0x0001bd21
}
chain netbird-rt-postrouting {
    meta mark 0x0001bd21 oifname != "lo" masquerade
    meta mark 0x0001bd22 oifname "wt0" masquerade
}

pbr Marking-Chains:

chain pbr_prerouting {
    meta mark & 0xff000000 != 0x00000000 return
    iifname "eth1.2" goto pbr_mark_0x1000000  # Gastnetz wan
    ip saddr 192.168.10.10 goto pbr_mark_0x1000000  # Festnetz wan
}

Netbird status:



root@nanopi:~# netbird status -d
Peers detail:
 laptop.netbird.cloud:
  NetBird IP: 100.114.2.124
  NetBird IPv6: fd72:d03:c98c:d80f:b70a:b9fa:4bb4:fca3
  Public key: iRBjgwUShGfFu0CS//OadnbliWDrwFl6w3xSfIGADn8=
  Status: Connecting
  -- detail --
  Connection type: -
  ICE candidate (Local/Remote): -/-
  ICE candidate endpoints (Local/Remote): -/-
  Relay server address:
  Last connection update: 1 hour, 36 minutes ago
  Last WireGuard handshake: -
  Transfer status (received/sent) 0 B/0 B
  Quantum resistance: false
  Networks: -
  Latency: 0s

 iphone.netbird.cloud:
  NetBird IP: 100.114.199.211
  NetBird IPv6: fd72:d03:c98c:d80f:1741:d463:3e4d:7803
  Public key: cLQ6rbKZqR+lM/k2nPWCk5jA2opLkizILOD4kgT9yDw=
  Status: Connecting
  -- detail --
  Connection type: -
  ICE candidate (Local/Remote): -/-
  ICE candidate endpoints (Local/Remote): -/-
  Relay server address:
  Last connection update: 59 minutes, 10 seconds ago
  Last WireGuard handshake: -
  Transfer status (received/sent) 0 B/0 B
  Quantum resistance: false
  Networks: -
  Latency: 0s

 ipad.netbird.cloud:
  NetBird IP: 100.114.244.103
  NetBird IPv6: fd72:d03:c98c:d80f:9b77:3e69:da17:fb05
  Public key: HmPwRV93qWe1mk1FwuzrYxtjaSqd+cFrxpWApGNXVlE=
  Status: Idle
  -- detail --
  Connection type: -
  ICE candidate (Local/Remote): -/-
  ICE candidate endpoints (Local/Remote): -/-
  Relay server address:
  Last connection update: -
  Last WireGuard handshake: -
  Transfer status (received/sent) 0 B/0 B
  Quantum resistance: false
  Networks: -
  Latency: 0s

Events:
  [INFO] SYSTEM (4f3e7de4-06ba-433e-aa1c-03aa1329d9dc)
    Message: Network map updated
    Time: 17 hours, 17 minutes ago
  [INFO] SYSTEM (5aed9101-fd4b-4927-9d4e-979d487d4dff)
    Message: daemon config changed (source=up_rpc)
    Time: 17 hours, 17 minutes ago
    Metadata: source: up_rpc, type: config_changed
  [INFO] SYSTEM (f3afe867-db2d-47e5-9586-8bd4ad71d5d4)
    Message: Network map updated
    Time: 17 hours, 17 minutes ago
  [INFO] SYSTEM (8a7d9f83-cfb6-4ac8-91f6-39306244c0b6)
    Message: Network map updated
    Time: 5 hours, 59 minutes ago
  [INFO] SYSTEM (12932bd3-417f-4c7f-b6bc-117b18e42711)
    Message: Network map updated
    Time: 5 hours, 55 minutes ago
  [INFO] SYSTEM (d7f14b8e-e9fd-40e2-b928-eadb73cb4e8f)
    Message: Network map updated
    Time: 5 hours, 21 minutes ago
  [INFO] SYSTEM (3967dc4f-21e4-4556-98c1-44ff6e03877e)
    Message: Network map updated
    Time: 5 hours, 21 minutes ago
  [INFO] SYSTEM (986a028f-d941-4522-9a16-7529b0390cb4)
    Message: Network map updated
    Time: 2 hours, 57 minutes ago
  [INFO] SYSTEM (ea392658-de42-45bf-bfe6-ccbda2401e04)
    Message: Network map updated
    Time: 2 hours, 38 minutes ago
  [INFO] SYSTEM (5f0f2de7-6cf4-4caf-bb9d-b33ded83f839)
    Message: Network map updated
    Time: 14 minutes, 58 seconds ago
OS: linux/arm64
Daemon version: 0.73.2
CLI version: 0.73.2
Profile: default
Management: Connected to https://api.netbird.io:443
Signal: Connected to https://signal.netbird.io:443
Relays:
  [stun:stun.netbird.io:443] is Available
  [stun:stun.netbird.io:5555] is Available
  [turns:turn.netbird.io:443?transport=tcp] is Available
  [rels://streamline-de-fra1-7.relay.netbird.io:443] is Available via ws
Nameservers:
FQDN: nanopi.netbird.cloud
NetBird IP: 100.114.9.95/16
NetBird IPv6: fd72:d03:c98c:d80f:7e8e:a5d1:f7ff:9818/64
Interface type: Kernel
Wireguard port: 51820
Quantum resistance: false
Lazy connection: true
SSH Server: Disabled
Networks: 0.0.0.0/0, ::/0
Peers count: 0/3 Connected

I set up netbird on my router just like the netbird doc suggested. I didn’t do the following step, because I believe I don’t need to:

DNS configuration

OpenWrt runs dnsmasq on port 53, which conflicts with NetBird’s managed DNS. To use NetBird DNS features such as domain resources and peer name resolution, run NetBird’s resolver on an alternative port and forward NetBird domains to it through dnsmasq.

  1. Set a custom DNS resolver address

    When port 53 is taken, NetBird automatically falls back to an
    alternative port, but pinning the address keeps the dnsmasq forwarding
    rule below valid:

    netbird up --dns-resolver-address 127.0.0.1:5053
    
    
  2. Forward NetBird domains in dnsmasq

    Add a server entry to /etc/config/dhcp under the dnsmasq section, replacing netbird.cloud with netbird.selfhosted or your custom DNS domain if you are self-hosting:

    uci add_list dhcp.@dnsmasq[0].server='/netbird.cloud/127.0.0.1#5053'
    uci commit dhcp
    /etc/init.d/dnsmasq restart
    

So in the netbird webinterface, I did the following:

I added my router and my mobile devices as peers.
I have a policy with source being a group with my mobile devices, direction only to the destination, which is the peer “router”. Proto&ports: all.
I set up my router as exit node with type routing peer. Distribution group is the mobile group, auto apply is checked.
I set up a DNS Nameserver with the Ipv4 of my router, port 53, match domain all. Groups: mobile.
In the settings, mobile group is Ipv6 enabled.

So at first I wasn’t able to connect to my home network from my cellular network for example. So because I am somewhat of a beginner, I used Claude to troubleshoot, and Claude told me that something with fmark from PBR was conflicting with fmark from netbird… Claude was confident so I changed some value in a PBR config file (see above). Then I also noticed a mistake I did in the netbird webinterface, and then it worked, so I don’t really know if it was necessary what I changed in the config file.

Right now, on my guest-lan, Ipv6 doesn’t seem to work (I’m checking on test-ipv6.com), and the connection to my home network is always relayed and not p2p. Other than that the connection seems to work as expected.

But I’m really sure that this is unstable and not correctly configured… Can you please help me out? Is my firewall correctly configured? Is the port netbird uses the same as the one from protonvpn? Do I need to maybe add a traffic rule? What’s up with the PBR stuff? Why has Ipv6 stopped working on my guest-lan? I don’t trust Claude anymore on this matter, and I can’t find articles on my specific setup…

I really am sorry for the length of this post, also for the grammar, I’m from Germany. On top of that I’m not an expert.

Please help me, I don’t know how to fix this or how to correctly set this up…

This post has been responded to with an AI, as this is such an advanced topic that it goes beyond my own range of support, but still an attempt to look at something that makes sense.

If the above warning is understood, click here to open up the details

1. What Went Wrong?

Issue A: Broken NetBird Connections (Relay vs. P2P & WireGuard Port Conflict)

  1. WireGuard Port Collision: In your config, ProtonVPN is set to endpoint_port 51820. However, NetBird was also configured to listen on Wireguard port: 51820. Having both try to bind or route on port 51820 causes conflicts.

  2. PBR Mark Collision: NetBird uses fwmark to route packets coming in and out of its virtual adapter wt0. By changing PBR config files, PBR started intercepting NetBird’s traffic or misrouting it. NetBird could no longer establish direct UDP holes through NAT, forcing it to fallback to a Relay server (high latency, slow speed).

Issue B: Guest-LAN IPv6 Breakdown

In OpenWrt firewall, lan_guest needs explicit forward/input rules for IPv6 router advertisements (ICMPv6) and DNS/DHCPv6 to function. When PBR rules were modified to catch all traffic or fwmarks, IPv6 return packets on VLAN 2 (eth1.2) began getting swallowed or routed out the wrong interface.

Issue C: DNS & Exit Node Behavior

Because NetBird creates its own interface wt0, OpenWrt’s zone model needs clear instructions on where traffic from wt0 is allowed to go (i.e., forwarding to lan for AdGuard Home, and forwarding to protonvpn for internet exit).

2. Step-by-Step Fix

Follow these steps directly on your NanoPi via SSH (root@nanopi).

Step 1: Change NetBird’s Listening Port

To avoid port conflicts with ProtonVPN (51820), force NetBird to use a different WireGuard port (e.g., 51821).

  1. Stop NetBird:

    Bash

    netbird down
    
    
  2. Start NetBird with a dedicated port and the recommended DNS binding:

    Bash

    netbird up --wireguard-port 51821 --dns-resolver-address 127.0.0.1:5053
    
    

Step 2: Open NetBird Port in OpenWrt Firewall

To ensure mobile devices can negotiate a direct P2P connection (instead of Relay), you must allow incoming UDP traffic on NetBird’s port (51821) on the WAN interface.

Run these UCI commands:

Bash

uci add firewall rule
uci set firewall.@rule[-1].name='Allow-NetBird-P2P'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].proto='udp'
uci set firewall.@rule[-1].dest_port='51821'
uci set firewall.@rule[-1].target='ACCEPT'
uci set firewall.@rule[-1].enabled='1'
uci commit firewall
/etc/init.d/firewall restart

Step 3: Fix Firewall Zones & Forwarding for NetBird

Your mobile devices connecting through NetBird (wt0) need to access both your Main LAN (for AdGuard Home / local devices) and ProtonVPN (for internet exit).

Run the following to configure proper zone forwardings:

Bash

# Allow NetBird traffic to reach ProtonVPN (Exit Node behavior)
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='netbird'
uci set firewall.@forwarding[-1].dest='protonvpn'

# Allow NetBird traffic to reach WAN (Fallback exit if Proton is down)
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='netbird'
uci set firewall.@forwarding[-1].dest='wan'

# Ensure NetBird zone accepts input (for local services like DNS on router)
uci set firewall.@zone[4].input='ACCEPT'
uci set firewall.@zone[4].forward='ACCEPT'

uci commit firewall
/etc/init.d/firewall restart

Step 4: Fix Policy-Based Routing (PBR)

We need to undo the PBR manual overrides that broke routing and IPv6 on Guest-LAN.

  1. Reset /etc/config/pbr to default clean settings, ensuring PBR ignores the NetBird interface (wt0) so it doesn’t break NetBird’s internal fwmarks:

Edit /etc/config/pbr and ensure the main config section includes wt0 under ignored interfaces:

Plaintext

config pbr 'config'
    option fw_mask 'ff000000'
    list reversed_option 'wt0'
    list ignored_interface 'wt0'
    list ignored_interface 'netbird'

  1. Restart PBR:

    Bash

    /etc/init.d/pbr restart
    
    

Step 5: Restore Guest LAN IPv6

To ensure Guest LAN (eth1.2) receives IPv6 properly:

  1. Verify lan_guest interface configuration in /etc/config/network:

    Plaintext

    config interface 'lan_guest'
        option proto 'static'
        option device 'eth1.2'
        option ipaddr '192.168.20.1'
        option netmask '255.255.255.0'
        option ip6assign '64'
    
    
  2. Verify DHCP/RA settings in /etc/config/dhcp:

    Bash

    uci set dhcp.lan_guest=dhcp
    uci set dhcp.lan_guest.interface='lan_guest'
    uci set dhcp.lan_guest.start='100'
    uci set dhcp.lan_guest.limit='150'
    uci set dhcp.lan_guest.leasetime='12h'
    uci set dhcp.lan_guest.ra='server'
    uci set dhcp.lan_guest.dhcpv6='server'
    uci set dhcp.lan_guest.ra_slaac='1'
    uci add_list dhcp.lan_guest.ra_flags='managed-config'
    uci add_list dhcp.lan_guest.ra_flags='other-config'
    uci commit dhcp
    /etc/init.d/dnsmasq restart
    /etc/init.d/odhcpd restart
    
    

3. NetBird Web Dashboard Configuration Check

Now, check your settings in the NetBird Admin Console:

  1. Network Routes / Exit Node:

    • Go to Network Routes $\rightarrow$ Add Route.

    • Network CIDR: 0.0.0.0/0 and ::/0.

    • Routing Peer: Select your nanopi.

    • Distribution Groups: mobile (or whatever group your phone/iPad belong to).

    • Masquerade: Enable (Checked).

  2. DNS Settings:

    • Go to DNS $\rightarrow$ Add Nameserver.

    • Name: AdGuard Home.

    • Nameserver IP: 192.168.10.1 (Your NanoPi Main LAN IP).

    • Port: 53.

    • Match Domains: Turn OFF “Match all domains” IF you only want it to resolve local stuff, OR leave it ON if you want 100% of your mobile device’s DNS requests to pass through AdGuard Home when away from home.

    • Distribution Groups: mobile.

4. Verification

After applying these steps:

  1. On your router, run:

    Bash

    netbird status -d
    
    
    • What to look for: Under your mobile peers (e.g., iphone.netbird.cloud), Connection type should say P2P (or Direct) instead of - or Relay.
  2. Turn off Wi-Fi on your iPhone/iPad, connect over Cellular (4G/5G), and enable NetBird.

  3. Visit test-ipv6.com on your mobile device—it should now pass IPv6 and display your ProtonVPN exit IPv6/IPv4 address.

  4. Test Guest LAN Wi-Fi/Ethernet on a client device to verify test-ipv6.com passes for guests via WAN.