Guide on fixing STUN/TURN “Unavailable” on OPNsense

Notes (Read First)

  • If your ISP router is in bridge mode (no double NAT), this works perfectly.
  • If you’re behind CGNAT, NetBird will often fall back to TURN/relay anyway.
  • You don’t need to open inbound ports; all rules are outbound only.
  • If you’re using Unbound with DNSBL/blocklists, make sure stun.netbird.io and turn.netbird.io are whitelisted. Otherwise, they’ll resolve to 0.0.0.0 or a sinkhole.

Symptoms

NetBird daemon shows:

[stun:stun.netbird.io:443] is Unavailable, reason: context deadline exceeded

[stun:stun.netbird.io:5555] is Unavailable, reason: context deadline exceeded
  • Peers only connect via relay, not directly.

Steps

1. Enable Static Port NAT for UDP

By default, OPNsense rewrites UDP source ports which breaks STUN mapping.
We need to preserve the original UDP source port.

  • Go to Firewall → NAT → Outbound
  • Set mode to Hybrid Outbound NAT
  • Add a new rule:
    • Interface: WAN
    • Protocol: UDP
    • Source: This Firewall (or NetBird interface if you want to be specific)
    • Destination: any
    • Translation / target: Interface address
    • Static Port: :white_check_mark: checked

Verify with:

pfctl -s nat

Should show:

nat on igc0 inet proto udp from (self) to any -> (igc0:0) static-port


2. Allow Outbound Firewall Rules for STUN/TURN

  • Go to Firewall → Rules → WAN
  • Add a rule:
    • Action: Pass
    • Interface: WAN
    • Protocol: UDP
    • Source: WAN address (self)
    • Destination: STUN/TURN server IPs
    • Destination Port: 443, 5555
    • Description: Allow NetBird STUN/TURN

How to get the IPs

Run this on OPNsense shell:

drill stun.netbird.io

drill turn.netbird.io

Example:

stun.netbird.io. 60 IN A 34.120.xxx.xxx

turn.netbird.io. 60 IN A 34.149.xxx.xxx

Use those IPs in your firewall alias/rules.


3. Test with stunclient

From a client behind OPNsense:

stunclient stun.netbird.io 443

Expected output:

Binding test: success

Local address: 10.10.10.xxx:xxxxx

Mapped address: <your_public_ip>:<same_port_or_random_port>

4. Verify from OPNsense

Check NetBird status:

netbird status

Should show:

[stun:stun.netbird.io:443] is Available

[stun:stun.netbird.io:5555] is Available

[turns:turn.netbird.io:443?transport=tcp] is Available

Troubleshooting

  1. Check DNS resolution
drill [stun.netbird.io](http://stun.netbird.io)

drill turn.netbird.io
  1. Inspect outbound packets with tcpdump
tcpdump -ni wan udp and host [stun.netbird.io](http://stun.netbird.io)

tcpdump -ni wan udp and host turn.netbird.io
  • Packets going out but no replies → ISP or upstream block.

  • Replies seen but NetBird still fails → check NAT static port rule again.


Result

After enabling UDP static-port NAT, whitelisting STUN/TURN in Unbound DNSBL, and creating outbound rules with the correct IPs, NetBird peers can now establish direct P2P connections. Relays are only used when necessary.

Thank you for this !

I wonder which stunclient you use for testing. I work under debian and the stun-client package installs stunwhich has no option to give a port number.