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:
@@ -18,6 +18,7 @@
|
|||||||
| [npm-grpc-fix.md](./npm-grpc-fix.md) | 透過 Nginx Proxy Manager 對外公開時的 gRPC 修復 |
|
| [npm-grpc-fix.md](./npm-grpc-fix.md) | 透過 Nginx Proxy Manager 對外公開時的 gRPC 修復 |
|
||||||
| [setup-keys-and-pat.md](./setup-keys-and-pat.md) | Setup Keys 概念、PAT 用法、以及 API 無法改名的繞道做法 |
|
| [setup-keys-and-pat.md](./setup-keys-and-pat.md) | Setup Keys 概念、PAT 用法、以及 API 無法改名的繞道做法 |
|
||||||
| [stun-port-conflict.md](./stun-port-conflict.md) | STUN 3478 被 Headscale 佔用 → NetBird 改用 3479 的解法 |
|
| [stun-port-conflict.md](./stun-port-conflict.md) | STUN 3478 被 Headscale 佔用 → NetBird 改用 3479 的解法 |
|
||||||
|
| [client-troubleshooting.md](./client-troubleshooting.md) | 客戶端 P2P 失敗、bufferbloat、Force Relay 等坑 |
|
||||||
| [SUMMARY.md](./SUMMARY.md) | 部署摘要與疑難排解記錄 |
|
| [SUMMARY.md](./SUMMARY.md) | 部署摘要與疑難排解記錄 |
|
||||||
|
|
||||||
## 快速開始
|
## 快速開始
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ reopen fd 8: permission denied
|
|||||||
| 手機 App:`server closed the stream without sending trailers` | 透過 NPM 對外公開時,NPM 用 `proxy_pass` 而非 `grpc_pass` 轉 gRPC;加上 Caddy `:80` 預設不支援 h2c | NPM 加 `advanced_config`(gRPC 路由)+ Caddy 全域啟用 `protocols h1 h2 h2c`;見 [npm-grpc-fix.md](./npm-grpc-fix.md) |
|
| 手機 App:`server closed the stream without sending trailers` | 透過 NPM 對外公開時,NPM 用 `proxy_pass` 而非 `grpc_pass` 轉 gRPC;加上 Caddy `:80` 預設不支援 h2c | NPM 加 `advanced_config`(gRPC 路由)+ Caddy 全域啟用 `protocols h1 h2 h2c`;見 [npm-grpc-fix.md](./npm-grpc-fix.md) |
|
||||||
| `PUT /api/setup-keys/{id}` 回 200 但 `name` 沒改 | NetBird API 只更新 `auto_groups` 和 `revoked`,`name` 是 read-only | 改 `store.db` 的 `setup_keys.name` → 重啟 `netbird-server`;見 [setup-keys-and-pat.md](./setup-keys-and-pat.md) |
|
| `PUT /api/setup-keys/{id}` 回 200 但 `name` 沒改 | NetBird API 只更新 `auto_groups` 和 `revoked`,`name` 是 read-only | 改 `store.db` 的 `setup_keys.name` → 重啟 `netbird-server`;見 [setup-keys-and-pat.md](./setup-keys-and-pat.md) |
|
||||||
| peer 之間一直走 Relay,`[stun:...:3478] is Checking...` | STUN port 3478 被 Headscale (`.126`) 搶先佔用 DNAT | NetBird 改用 3479/udp(server config + OpenWrt DNAT);見 [stun-port-conflict.md](./stun-port-conflict.md) |
|
| peer 之間一直走 Relay,`[stun:...:3478] is Checking...` | STUN port 3478 被 Headscale (`.126`) 搶先佔用 DNAT | NetBird 改用 3479/udp(server config + OpenWrt DNAT);見 [stun-port-conflict.md](./stun-port-conflict.md) |
|
||||||
|
| STUN 都通了,仍然 `Connection type: Relayed`、`ICE candidate: -/-` | 客戶端 **Force Relay Connection** 開關被打開,跳過 ICE gathering | App Settings → Advanced → 關掉 Force Relay;見 [client-troubleshooting.md](./client-troubleshooting.md) |
|
||||||
|
| ping RTT 尖峰到 2-4 秒 | 當下 WiFi/ISP 有 bufferbloat | 用 `networkQuality -v` 確認(看 RPM),與 NetBird 無關 |
|
||||||
|
|
||||||
## 檔案位置
|
## 檔案位置
|
||||||
|
|
||||||
@@ -95,7 +97,8 @@ reopen fd 8: permission denied
|
|||||||
├── netbird-selfhosted-setup.md ← 完整安裝指南
|
├── netbird-selfhosted-setup.md ← 完整安裝指南
|
||||||
├── npm-grpc-fix.md ← 經 NPM 對外公開時的 gRPC 修復
|
├── npm-grpc-fix.md ← 經 NPM 對外公開時的 gRPC 修復
|
||||||
├── setup-keys-and-pat.md ← Setup Keys / PAT 操作與 API 限制繞道
|
├── setup-keys-and-pat.md ← Setup Keys / PAT 操作與 API 限制繞道
|
||||||
└── stun-port-conflict.md ← STUN 改用 3479 (3478 被 Headscale 佔用)
|
├── stun-port-conflict.md ← STUN 改用 3479 (3478 被 Headscale 佔用)
|
||||||
|
└── client-troubleshooting.md ← 客戶端 Force Relay / bufferbloat 排錯
|
||||||
```
|
```
|
||||||
|
|
||||||
### 遠端伺服器(192.168.42.127:/opt/netbird/)
|
### 遠端伺服器(192.168.42.127:/opt/netbird/)
|
||||||
|
|||||||
147
client-troubleshooting.md
Normal file
147
client-troubleshooting.md
Normal 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。
|
||||||
|
|
||||||
|
### 容易猜錯的方向
|
||||||
|
|
||||||
|
- 怪 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 設定檔方式存在 |
|
||||||
|
|
||||||
|
#### 修復
|
||||||
|
|
||||||
|
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 啟用 SQM(OpenWrt 上裝 `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** | 永遠走 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 / 個人裝置之間互通,沒理由開**。
|
||||||
Reference in New Issue
Block a user