docs: add client-side troubleshooting (Force Relay, bufferbloat)

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).
This commit is contained in:
2026-04-18 10:40:04 +08:00
parent 31a874f3be
commit c5a8757da4
3 changed files with 152 additions and 1 deletions

147
client-troubleshooting.md Normal file
View File

@@ -0,0 +1,147 @@
# 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。
### 容易猜錯的方向
- 怪 STUNDNAT、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 設定檔方式存在 |
#### 修復
1. 把開關關掉
2. App 內 Disconnect → Connect`netbird down && netbird up`
3. 等 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 跑:
```bash
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 啟用 SQMOpenWrt 上裝 `luci-app-sqm`
- 短期:避免在背景下載大檔時測 NetBird 延遲
## 客戶端配置驗證 checklist
當你覺得「明明設定都對,但 NetBird 行為怪怪的」,依序檢查:
```bash
# 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** | 永遠走 RelayP2P 失效 |
| 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 / 個人裝置之間互通,沒理由開**。