Network Routing from homelab to VPN hub IPs

Hello!

I set up Netbird on a Linux (Debian 13) host using Podman, then also installed Netbird on the host itself to connect as a peer as well to enable access to that host through the VPN itself as well - so as expected, I see the wt0 interface.

At home, I configured my OPNSense as per the guide (except static NAT at the bottom) and it connects as well.

So there are two peers right now:

  • 10.0.0.1 - VPN host acting as peer
  • 10.0.0.2 - OPNSense firewall

Next, I configured a Network Route to 10.1.0.0/24 and from my host I can ping and ssh into nodes on my home network totally fine; although ssh seems to use a custom configuration that Netbird set up there. That’s fine, I guess. Ping also works.

So the route 10.0.0.1 → 10.1.0.2 works (that home IP is my NAS, it does not have Netbird installed). However, when I want to ping from home into the VPN network, that does not work.

On my Windows client connected to the OPNSense, this path does not work: 10.1.0.20 → 10.1.0.1/10.0.0.2 → 10.0.0.1

To clarify:

  • 10.1.0.20 is my Windows PC,
  • whereas 10.1.0.1 is the LAN IP of my OPNSense and 10.0.0.2 is it’s VPN IP
  • and 10.0.0.1 is the VPN host I am trying to ping.

So where did I go wrong? I am a little confused here. Because, from the VPN host itself, I can ping everything fine, but not the other way around…?

Thank you and kind regards!

After spending literal hours, squeezing ChatGPT and Gemini out of their free limits, I found parts of my solution.

As it turns out, I am running into an ACL issue here; my packets are dropped:

root@drachennetz:/var/log/netbird# nft insert rule ip netbird netbird-acl-input-filter index 0 ip saddr 10.1.0.0/24 meta nftrace set 1
root@drachennetz:/var/log/netbird# nft monitor trace
trace id ee77c774 ip netbird netbird-acl-input-filter packet: iif "wt0" ip saddr 10.1.0.2 ip daddr 10.0.0.1 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 7257 ip length 84 icmp type echo-request icmp code 0 icmp id 27415 icmp sequence 1
trace id ee77c774 ip netbird netbird-acl-input-filter rule ip saddr 10.1.0.0/24 meta nftrace set 1 (verdict continue)
trace id ee77c774 ip netbird netbird-acl-input-filter rule iifname "wt0" jump netbird-acl-input-rules (verdict jump netbird-acl-input-rules)
trace id ee77c774 ip netbird netbird-acl-input-filter rule iifname "wt0" drop (verdict drop)
trace id 6792690a ip netbird netbird-acl-input-filter packet: iif "wt0" ip saddr 10.1.0.2 ip daddr 10.0.0.1 ip dscp cs0 ip ecn not-ect ip ttl 63 ip id 7319 ip length 84 icmp type echo-request icmp code 0 icmp id 27415 icmp sequence 2
trace id 6792690a ip netbird netbird-acl-input-filter rule ip saddr 10.1.0.0/24 meta nftrace set 1 (verdict continue)
trace id 6792690a ip netbird netbird-acl-input-filter rule iifname "wt0" jump netbird-acl-input-rules (verdict jump netbird-acl-input-rules)
trace id 6792690a ip netbird netbird-acl-input-filter rule iifname "wt0" drop (verdict drop)

I made two policies - each of which are single-direction:

  • Peers to Clients (src all, dest homelab-clients , all protocols)
  • Clients to Peers (src homelab-clients, dest all, all protocols)

homelab-clients is a group containing a resource to specify my home LAN 10.1.0.0/24. The idea was to fully allow packets to flow between the two.

Weirdly, outgoing connections worked: When I pinged from my VPN host into my LAN, responses were returned exactly as expected. The other way around did not work and was caught by the nftables rules and thus dropped.

So how do I set the ACLs correctly to achieve my goal here?

A little longer and I figured I could watch the firewall state with watch -n 1 nft list table ip netbird - and so I did.

No matter how I configured my LAN (either via “Networks” or “Network routes”), as a resource or as a route - no matter what, I could not get any of the created policies to straight up add the CIDR into nftables to enable responses to pings - at all, ever.

That said, if I use masquerading (both in the Netbird settings and on OPNSense), it works just fine - but does lose the source address which I really want to keep for monitoring/logging reasons.

I am at my wit’s end. Literally. No idea how else to now enable site-to-site with this… I am convinced this is literally just me not completely understanding the object hierachy in NetBird and how which parts fit together - but damn it is so frustrating…

NetBird treats your home subnet (10.1.0.0/24) differently from actual peers. Even though routing works, that subnet isn’t seen as a “trusted identity”, so incoming traffic from it gets dropped by the ACL on the VPN host. Try to see if you can enable masquerading and see if that works in the first place, or try using a resource if you haven’t already directly referring to the IP address and give that an ACL to work with.

Masquerading does work since the origin IP would now be within the peer subnet - I got this to work. But doing this would mean that all traffic from the LAN becomes headended by the relaying peer. That basically makes access logs and other metrics useless… It does work though.

I tried all kinds of ACLs, both network tabs (“Networks” and “Network routes”) with varying ACLs but none of them would place the apropriate rules in nftables