Document the 'Force relay connection' switch that silently disables ICE gathering on iOS NetBird (and similar on macOS), which was the real cause of all peers showing Connection type: Relayed despite STUN being correctly configured. Also document bufferbloat diagnosis via macOS networkQuality, which was a red herring during the P2P investigation (large RTT spikes were the WiFi/ISP, not NetBird).
4.4 KiB
4.4 KiB
NetBird 客戶端 Troubleshooting
記錄一些不容易猜到的客戶端問題與解法。
P2P 永遠打不通:先檢查 Force Relay Connection
症狀
netbird status --detail 顯示:
Connection type: Relayed
ICE candidate (Local/Remote): -/-
ICE candidate endpoints (Local/Remote): -/-
Relay server address: rels://...
兩端 ICE candidate 都是 -/-、長時間不變,連線可用但永遠走 Relay。
容易猜錯的方向
- 怪 STUN(DNAT、port 衝突、防火牆)
- 怪「Block Inbound Connections」
- 怪 iOS 平台限制(NetworkExtension 不支援 P2P UDP)
- 怪同 WiFi 下的 hairpin NAT
- 怪 Mac 防火牆
以上都檢查無誤後仍然 Relayed → 檢查客戶端的 Force Relay Connection。
真正原因
NetBird 客戶端有一個 「Force relay connection」 開關。打開後 NetBird 完全跳過 ICE gathering,直接走 Relay。
各平台位置
| 平台 | 路徑 |
|---|---|
| iOS | App → Settings → Advanced → 最下方「Force relay connection」 |
| macOS | 選單列 NetBird → Settings → Advanced Settings(或 menu 內找 Force Relay) |
| CLI / daemon | netbird up 沒有對應 flag;以 daemon 設定檔方式存在 |
修復
- 把開關關掉
- App 內 Disconnect → Connect(或
netbird down && netbird up) - 等 5-10 秒讓 ICE gathering 完成
驗證 P2P 成功
netbird status --detail 應顯示:
Connection type: P2P
ICE candidate (Local/Remote): host/prflx ← 或 srflx/srflx 等組合
ICE candidate endpoints (Local/Remote): 192.168.x.x:51820/192.168.x.x:51820
Latency: ~25 ms ← 同 LAN 應該 <50ms
Connection type 從 Relayed 變成 P2P 就成功。
高 RTT 大幅波動:先排除 bufferbloat
症狀
ping <peer-ip> 結果像這樣:
round-trip min/avg/max/stddev = 220.423/2230.078/4238.380/1420.726 ms
平均 2 秒、尖峰 4 秒。看起來像 NetBird 出問題。
診斷
在 macOS 跑:
networkQuality -v
如果輸出:
Responsiveness: Low (703 milliseconds | 85 RPM)
→ 這是你連的 WiFi/ISP 有 bufferbloat,跟 NetBird 無關。 RPM (Round-trips Per Minute) 應該 >500,<100 算很糟。Bufferbloat 在路由器/modem 有大量佇列堆積時會讓任何流量延遲爆衝。
修復方向
- 換更好的 WiFi AP(支援 SQM / fq_codel / cake)
- ISP modem 啟用 SQM(OpenWrt 上裝
luci-app-sqm) - 短期:避免在背景下載大檔時測 NetBird 延遲
客戶端配置驗證 checklist
當你覺得「明明設定都對,但 NetBird 行為怪怪的」,依序檢查:
# 1. 客戶端有連到正確的 management server?
netbird status | grep Management
# 2. STUN 是 Available?(這個案例的 STUN port 是 3479)
netbird status --detail | grep -E 'stun:|Relays:'
# 3. 看到對方 peer?
netbird status --detail | grep -A 1 <peer-fqdn>
# 4. Connection type 是 P2P 還是 Relayed?
netbird status --detail | grep 'Connection type'
# 5. ICE candidate 是什麼類型?(host/srflx/prflx/relay)
netbird status --detail | grep 'ICE candidate'
# 6. WireGuard 真的有 handshake?
netbird status --detail | grep 'Last WireGuard handshake'
# 7. 真的能 ping?
ping -c 5 <peer-netbird-ip>
如果 7 通但 4 是 Relayed 且 5 是 -/- → 99% 是 Force Relay 開著(見上)。
各平台 NetBird Settings 裡會踩雷的開關
| 開關 | 開啟後果 |
|---|---|
| Force relay connection | 永遠走 Relay,P2P 失效 |
| Block Inbound Connections | 對方主動連入會被擋,可能逼成單向 Relay |
| Disable Client Routes | 此 peer 不路由到其他 peer |
| Disable Server Routes | 此 peer 無法當別人的 router |
| Disable LAN Access | 當 exit node 時不能存取 exit node 的本地網路 |
| Lazy Connections | 連線延遲建立直到有流量才協商 |
| Enable Rosenpass | 量子抗性握手(實驗性,可能與舊 peer 不相容) |
預設值通常是「全部關閉」 — 如果你或別人不小心開了某個,行為就會變得難解釋。
為什麼客戶端版的 docs 不直接寫死「永遠關 Force Relay」
某些情境下強制 Relay 是合理的:
- P2P 隱私顧慮(不想暴露真實 IP 給對方 peer)
- 對方所在網路有 IDS 會偵測 P2P UDP 流量
- Debug 時希望流量都過 Relay 方便抓 log
所以 NetBird 把它做成可選。自宅 mesh / 個人裝置之間互通,沒理由開。