diff --git a/README.md b/README.md index f21fa74..bbac36b 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ | [netbird-selfhosted-setup.md](./netbird-selfhosted-setup.md) | 完整安裝指南(含原理說明) | | [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 無法改名的繞道做法 | +| [stun-port-conflict.md](./stun-port-conflict.md) | STUN 3478 被 Headscale 佔用 → NetBird 改用 3479 的解法 | | [SUMMARY.md](./SUMMARY.md) | 部署摘要與疑難排解記錄 | ## 快速開始 @@ -51,6 +52,7 @@ netbird up --management-url http://192.168.42.127 |------|-----| | 主機 | `192.168.42.127` | | 系統 | Ubuntu 24.04 LTS | +| STUN port | **3479/udp** (非標準 — 3478 被 Headscale 佔用) | | 容器類型 | Proxmox LXC (非特權) | | Docker | 29.4.0 | | OCI Runtime | crun 1.20 | diff --git a/SUMMARY.md b/SUMMARY.md index 4fd6730..643bc8f 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -82,6 +82,7 @@ reopen fd 8: permission denied | 502 Bad Gateway(所有 API 端點) | netbird-server 下載 GeoLite2 中,尚未開始監聽 port 80 | 等待 2-5 分鐘 | | 手機 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) | +| 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) | ## 檔案位置 @@ -93,7 +94,8 @@ reopen fd 8: permission denied ├── SUMMARY.md ← 本檔(部署摘要) ├── netbird-selfhosted-setup.md ← 完整安裝指南 ├── 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 佔用) ``` ### 遠端伺服器(192.168.42.127:/opt/netbird/) diff --git a/netbird-selfhosted-setup.md b/netbird-selfhosted-setup.md index 2da8226..2defca6 100644 --- a/netbird-selfhosted-setup.md +++ b/netbird-selfhosted-setup.md @@ -269,7 +269,7 @@ Client Request (:80) | 端口 | 協定 | 用途 | |------|------|------| | 80 | TCP | Dashboard + API + Signal + Relay | -| 3478 | UDP | STUN (NAT 穿透) | +| 3478 | UDP | STUN (NAT 穿透) — **本部署改用 3479;見 [stun-port-conflict.md](./stun-port-conflict.md)** | ## 常用維運指令 diff --git a/stun-port-conflict.md b/stun-port-conflict.md new file mode 100644 index 0000000..99743fc --- /dev/null +++ b/stun-port-conflict.md @@ -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 README(OpenWrt port 表,3479 在這裡記錄) + +## 為什麼不關掉 Headscale? + +使用者仍在使用 Headscale,沒有遷移計畫。兩套 overlay 網路並存是有意的安排。