diff --git a/README.md b/README.md index 9fb21c6..0094a40 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ | [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 的解法 | | [client-troubleshooting.md](./client-troubleshooting.md) | 客戶端 P2P 失敗、bufferbloat、Force Relay 等坑 | +| [peer-deployment-ops.md](./peer-deployment-ops.md) | 在 LXC 用 Docker 部署客戶端、改名、Mac daemon 重啟 | | [SUMMARY.md](./SUMMARY.md) | 部署摘要與疑難排解記錄 | ## 快速開始 diff --git a/SUMMARY.md b/SUMMARY.md index 492caa6..276696a 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -85,6 +85,8 @@ reopen fd 8: permission denied | 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 無關 | +| Mac `netbird status` 卡在 `Management: Disconnected, rpc error` | daemon 本身卡死,`netbird up`/`down` 救不回 | `sudo launchctl kickstart -k system/netbird`(服務名是 `netbird` 而非 `io.netbird.client`);見 [peer-deployment-ops.md](./peer-deployment-ops.md) | +| LXC CT100 SSH root 密碼被擋(`Permission denied`) | sshd_config 內有 `PermitRootLogin prohibit-password` 比 `yes` 先出現,first-match-wins | 加 `/etc/ssh/sshd_config.d/99-allow-root.conf` 覆蓋;socket activation 不需重啟 sshd | ## 檔案位置 @@ -98,7 +100,8 @@ reopen fd 8: permission denied ├── npm-grpc-fix.md ← 經 NPM 對外公開時的 gRPC 修復 ├── setup-keys-and-pat.md ← Setup Keys / PAT 操作與 API 限制繞道 ├── stun-port-conflict.md ← STUN 改用 3479 (3478 被 Headscale 佔用) -└── client-troubleshooting.md ← 客戶端 Force Relay / bufferbloat 排錯 +├── client-troubleshooting.md ← 客戶端 Force Relay / bufferbloat 排錯 +└── peer-deployment-ops.md ← Docker 部署客戶端、改名、Mac daemon 重啟 ``` ### 遠端伺服器(192.168.42.127:/opt/netbird/) diff --git a/peer-deployment-ops.md b/peer-deployment-ops.md new file mode 100644 index 0000000..ee507da --- /dev/null +++ b/peer-deployment-ops.md @@ -0,0 +1,249 @@ +# Peer 部署與維運操作 + +記錄新增 peer、改名、daemon 維運等實際操作的 know-how。 + +## 在 LXC/VM 裡透過 Docker 部署 NetBird 客戶端 + +適合 headless 伺服器(沒有 GUI、沒有真人 SSO 登入流程)。本 NetBird 部署已在 `CT100`、`CT101` 用此方法上線。 + +### 前置 + +- 目標主機已裝 Docker +- 有可用的 PAT(見 `setup-keys-and-pat.md`) +- 對目標 NetBird management server 可連線 + +### 步驟 + +#### 1. 為這台機器建一把 one-off setup key + +```bash +TOKEN=<你的 PAT> + +curl -sf -X POST -H "Authorization: Token $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "CT100-SSH-JumpBox", + "type": "one-off", + "expires_in": 86400, + "revoked": false, + "auto_groups": [], + "usage_limit": 1, + "ephemeral": false + }' \ + https://netbird.timmy.us.kg/api/setup-keys | jq +``` + +命名慣例:`<主機名>-<用途>`(例 `CT100-SSH-JumpBox`、`CT101-RustDesk`),Dashboard 上一眼看得出這把 key 給誰。 + +- `type: one-off` + `usage_limit: 1` — 用一次就失效,最小攻擊面 +- `expires_in: 86400` — 24 小時內沒用就過期 +- `ephemeral: false` — 此 peer 離線後不自動清除(伺服器要持續存在) + +把回傳的 `key` 欄位(UUID)存起來,下一步要用。 + +#### 2. 在目標主機寫 docker-compose.yml + +```yaml +services: + netbird: + image: netbirdio/netbird:latest + container_name: netbird + restart: unless-stopped + network_mode: host + cap_add: + - NET_ADMIN + - SYS_RESOURCE + environment: + - NB_SETUP_KEY=<上一步拿到的 key UUID> + - NB_MANAGEMENT_URL=https://netbird.timmy.us.kg:443 + - NB_HOSTNAME=<主機名,例 CT100> + volumes: + - /opt/netbird/data:/var/lib/netbird + labels: + - com.centurylinklabs.watchtower.enable=true +``` + +放在 `/opt/netbird/docker-compose.yml`(跟 NetBird server 部署在 `.127` 的路徑一致,維運直覺)。 + +關鍵設定: +- `network_mode: host` — NetBird 需要能直接看到 host 的網路介面來做 ICE +- `cap_add: [NET_ADMIN, SYS_RESOURCE]` — 建 WireGuard 介面必要 +- `NB_HOSTNAME` — peer 註冊後的顯示名稱(日後可用 API 再改) +- Watchtower label — 讓 Watchtower 自動跟 upstream 更新 + +#### 3. 啟動 + +```bash +cd /opt/netbird +docker compose pull +docker compose up -d + +# 驗證 +sleep 10 +docker exec netbird netbird status +``` + +正常輸出應該有 `Management: Connected`、`Relays: 2/2 Available`、`Peers count: N/N Connected`。 + +### LXC 容器內的 TUN 問題 + +**理論上**:NetBird 需要 `/dev/net/tun` 來建立 WireGuard kernel 介面。 +**實際上**:在非特權 LXC 容器(如 Proxmox 的 `unprivileged: 1`)`/dev/net/tun` 不存在,但 NetBird client 容器透過 `network_mode: host` + `cap_add: NET_ADMIN` 能跑起來,並顯示 `Interface type: Kernel`(推測是透過 host namespace 繞過)。 + +如果未來遇到 TUN 不可用的情境: +- 選項 A:在 PVE CT config 加 `lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file,optional 0 0`(需重啟 CT) +- 選項 B:切 userspace WireGuard(參考 Tailscale 的 `--tun=userspace-networking` 作法,但 NetBird 沒有這個開關,需要手動 patch) + +## Peer 改名(API 做得到,setup key 做不到) + +### 對比: + +| 資源 | API PUT `name` | 其他方式 | +|------|--------------|---------| +| setup_keys | **不生效**(見 `setup-keys-and-pat.md`) | 改 `store.db` + 重啟 server | +| peers | **生效**,連 FQDN / dns_label 都自動同步 | — | + +### 用法 + +```bash +TOKEN=<你的 PAT> + +# 列出 peer IDs +curl -sf -H "Authorization: Token $TOKEN" \ + https://netbird.timmy.us.kg/api/peers | jq '.[] | {id, name, hostname, ip}' + +# 改名 +curl -X PUT -H "Authorization: Token $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "mbp-13-pro", + "ssh_enabled": false, + "login_expiration_enabled": false, + "inactivity_expiration_enabled": false, + "approval_required": false + }' \ + https://netbird.timmy.us.kg/api/peers/ +``` + +**注意**:PUT 需要帶完整的 peer 設定(不只 name),`ssh_enabled` 等欄位若不帶會用預設值覆蓋。先 GET 看看這個 peer 現況,再帶相同值 + 新的 name。 + +### 命名慣例 + +改名後的 `dns_label` 會是 `.netbird.selfhosted`,建議: + +- 全小寫、英數與連字號、不用空格/中文 +- 語意清楚:`mbp-13-pro`、`iphone-15-pro`、`ct100`、`ct101` +- 避免 `.local` 等 mDNS 後綴(macOS 預設 hostname 會自動帶,改掉) + +## Mac daemon 卡住:launchctl 重啟 + +### 症狀 + +`netbird status` 顯示 `Management: Disconnected, reason: rpc error: context canceled` 或類似 RPC 錯誤。Signal 可能還是 Connected,但 peers count 歸零。 + +UI 上 Disconnect → Connect 通常可以恢復,但 daemon 真的卡死時 UI 也不回應。 + +### 解法 + +直接重啟 launchd service: + +```bash +sudo launchctl kickstart -k system/netbird +``` + +⚠️ 服務名稱是 **`netbird`**,**不是** `io.netbird.client`、`com.netbird.daemon` 等常見猜測。 +確認方式: + +```bash +ls /Library/LaunchDaemons/ | grep -i netbird +# → netbird.plist + +cat /Library/LaunchDaemons/netbird.plist | grep -A 1 'Label' +# → netbird +``` + +launchd 語法 `system/