docs: document STUN port change to 3479

NetBird's default STUN port 3478/udp conflicts with Headscale on
192.168.42.126, which DNAT'd it first. Reconfigure NetBird to use
3479/udp end-to-end (server config + docker-compose + OpenWrt DNAT).

Updates server config:
- /opt/netbird/config.yaml: stunPorts: [3479]
- /opt/netbird/docker-compose.yml: 3479:3479/udp

OpenWrt DNAT rule added separately (42_10 repo commit 9cc6141).
This commit is contained in:
2026-04-18 10:24:50 +08:00
parent fc9d72e12d
commit 31a874f3be
4 changed files with 109 additions and 2 deletions

103
stun-port-conflict.md Normal file
View File

@@ -0,0 +1,103 @@
# NetBird STUN Port 衝突:改用 3479/udp
## 情境
家用 infra 同時跑 **Headscale (`192.168.42.126`)****NetBird (`192.168.42.127`)** 兩套 mesh VPN。兩者都想用標準 STUN port **`3478/udp`**,但單一 WAN port 只能 DNAT 到一個內網 host。
Headscale 比較早部署,已經占用了 WAN `:3478/udp → .126`。NetBird 因此必須改用其他 port 對外。
## 決策
採用「**NetBird 全面改用 3479/udp**」:
- 內部 netbird-server 的 STUN 監聽改為 `3479`
- Docker 容器對外 expose `3479:3479/udp`
- OpenWrt 新增 DNAT `WAN :3479/udp → 192.168.42.127:3479`
- 客戶端收到的 STUN URL 會是 `stun:netbird.timmy.us.kg:3479`
Headscale 那條 `3478/udp → .126` 完全不動。
## 實施步驟
### 1. 修改 `/opt/netbird/config.yaml`
```yaml
server:
# ...
stunPorts:
- 3479 # 原本是 3478
```
### 2. 修改 `/opt/netbird/docker-compose.yml`
```yaml
netbird-server:
# ...
ports:
- "3479:3479/udp" # 原本是 "3478:3478/udp"
```
### 3. 重新建立容器
```bash
cd /opt/netbird
docker compose up -d
```
`docker compose up -d` 會偵測到 port 變更、重建 `netbird-server` 容器。其他兩個caddy、dashboard不動。
### 4. OpenWrt 加 DNAT
`192.168.42.10` 上加 UCI redirect詳見 `42_10` repo
```
name: NetBird-STUN
src: wan → dest: lan
src_dport: 3479 → dest_ip: 192.168.42.127, dest_port: 3479
proto: udp
target: DNAT
```
### 5. 驗證
外部 UDP 連通性:
```bash
nc -zvu -w 3 125.229.110.50 3479
# Connection to 125.229.110.50 port 3479 [udp/...] succeeded!
```
客戶端 STUN 正確指向新 port
```bash
netbird status --detail | grep stun:
# [stun:netbird.timmy.us.kg:3479] is Available
```
## 既有客戶端要重連
已連線的 NetBird 客戶端會在啟動時向 management server 拿一次 STUN URL**變更後舊客戶端仍握著舊 URL**。每台已註冊裝置需:
```
Disconnect → Connect
```
或重啟 App / daemon 讓它重新抓設定。沒重連前仍會走 Relay不會斷線但無法 P2P。
## 疑難排解
| 症狀 | 可能原因 |
|------|---------|
| `[stun:...:3479] is Checking...` 長時間沒變 Available | OpenWrt DNAT 未生效或 NetBird 容器沒在新 port 監聽 |
| Available 但 `Connection type: Relayed` 不變 | 客戶端沒重連 / 兩邊都在嚴格 NAT 後 / iOS 省電模式阻擋 ICE |
| iPhone App 重連後仍是 Relay | 檢查 iOS 的 Low Data Mode 或 WiFi/行動網路切換P2P 對稱 NAT 時無解,保持 Relay 正常運作 |
## 相關檔案
- `/opt/netbird/config.yaml`(伺服器)
- `/opt/netbird/docker-compose.yml`(伺服器)
- `42_10` repo READMEOpenWrt port 表3479 在這裡記錄)
## 為什麼不關掉 Headscale
使用者仍在使用 Headscale沒有遷移計畫。兩套 overlay 網路並存是有意的安排。