docs: add peer deployment ops guide
Document the operational patterns established while adding CT100 and CT101 as peers via Docker, plus incidental fixes: - Docker compose template for headless peer containers - One-off setup key naming convention and API creation - Peer rename via API PUT (works, unlike setup keys) - Mac daemon kickstart via 'sudo launchctl kickstart -k system/netbird' (service name is 'netbird', not 'io.netbird.client') - UPNP auto-port-mapping discovery in NetBird client - CT100 PermitRootLogin drop-in override (first-match-wins sshd quirk)
This commit is contained in:
@@ -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) | 部署摘要與疑難排解記錄 |
|
||||
|
||||
## 快速開始
|
||||
|
||||
@@ -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/)
|
||||
|
||||
249
peer-deployment-ops.md
Normal file
249
peer-deployment-ops.md
Normal file
@@ -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/<PEER_ID>
|
||||
```
|
||||
|
||||
**注意**:PUT 需要帶完整的 peer 設定(不只 name),`ssh_enabled` 等欄位若不帶會用預設值覆蓋。先 GET 看看這個 peer 現況,再帶相同值 + 新的 name。
|
||||
|
||||
### 命名慣例
|
||||
|
||||
改名後的 `dns_label` 會是 `<name>.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 '<key>Label</key>'
|
||||
# → <string>netbird</string>
|
||||
```
|
||||
|
||||
launchd 語法 `system/<Label>` 所以完整 domain 是 `system/netbird`。
|
||||
|
||||
### 重啟後驗證
|
||||
|
||||
```bash
|
||||
netbird status
|
||||
# Management: Connected
|
||||
# Peers count: N/N Connected ← 應該是 N/N 而非 0/0
|
||||
```
|
||||
|
||||
## 其他平台
|
||||
|
||||
Linux systemd:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart netbird
|
||||
```
|
||||
|
||||
Windows:
|
||||
```
|
||||
Restart-Service -Name "Netbird"
|
||||
```
|
||||
|
||||
Docker 容器(本文部署的方式):
|
||||
```bash
|
||||
docker restart netbird
|
||||
```
|
||||
|
||||
## 意外發現:NetBird 內建 UPNP 自動打洞
|
||||
|
||||
觀察 CT101 的啟動日誌:
|
||||
|
||||
```
|
||||
client/internal/portforward/manager.go:162: discovered NAT gateway: UPNP (IG2-IP2)
|
||||
client/internal/portforward/manager.go:204: created port mapping: 51820 -> 10935 via UPNP (IG2-IP2) (external IP: 125.229.110.50)
|
||||
```
|
||||
|
||||
NetBird client 啟動時會主動向 NAT gateway 發 UPNP/IGD 請求,自動 map 一個 public port 到自己的 `51820`。
|
||||
|
||||
好處:
|
||||
- 不需要手動在路由器上加 DNAT 也能讓 peer 做 P2P inbound
|
||||
- 等於 NetBird 自己處理 port forwarding
|
||||
|
||||
前提:
|
||||
- 路由器支援 UPNP / NAT-PMP 且開啟
|
||||
- OpenWrt 通常需裝 `miniupnpd` 套件並在 firewall zone 允許
|
||||
|
||||
本部署的 OpenWrt 有啟用 UPNP,所以 CT101 才能自動打這個洞。如果未來發現某台 peer 一直走 Relay、查 log 沒看到 UPNP 訊息,先檢查閘道器有沒有開 UPNP。
|
||||
|
||||
## CT100 部署時意外踩的雷
|
||||
|
||||
CT100 原本 root SSH 密碼登入完全被擋(`Permission denied`),不是 root 密碼錯,而是 sshd config 有個較早的 drop-in 設了 `PermitRootLogin prohibit-password`。
|
||||
|
||||
### 診斷
|
||||
|
||||
```bash
|
||||
pct exec 100 -- sshd -T | grep -iE 'permitrootlogin|passwordauthentication'
|
||||
# permitrootlogin without-password ← 擋 root 密碼登入
|
||||
# passwordauthentication yes
|
||||
```
|
||||
|
||||
`grep -l -r PermitRootLogin /etc/ssh/` 只找到 `/etc/ssh/sshd_config`,但該檔內有兩個 `PermitRootLogin` 指令(先 `prohibit-password` 後 `yes`),**OpenSSH 是 first-match-wins**,所以前者有效。
|
||||
|
||||
### 修復
|
||||
|
||||
覆蓋寫一個更晚載入的 drop-in:
|
||||
|
||||
```bash
|
||||
pct exec 100 -- bash -c 'echo "PermitRootLogin yes" > /etc/ssh/sshd_config.d/99-allow-root.conf'
|
||||
|
||||
# 驗證
|
||||
pct exec 100 -- sshd -T | grep permitrootlogin
|
||||
# permitrootlogin yes
|
||||
```
|
||||
|
||||
**不需重啟 sshd**:CT100 用 `ssh.socket` 做 systemd socket activation,每個新連線都 fork 新 sshd 重讀設定。
|
||||
|
||||
### 密碼也要重設
|
||||
|
||||
CT100 原本的 root 密碼忘了,從 PVE host 繞過:
|
||||
|
||||
```bash
|
||||
ssh root@192.168.42.39
|
||||
pct exec 100 -- bash -c "echo 'root:25915525' | chpasswd"
|
||||
```
|
||||
Reference in New Issue
Block a user