Covers 0.0.0.0/0 route creation, opt-in client-side selection (different from subnet routes which auto-apply), and the extra trust exposure when routing through a third-party VPS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.1 KiB
9.1 KiB
NetBird 部署摘要
部署結果
NetBird Self-Hosted 已部署於 192.168.42.127
- 部署日期:2026-04-17
- 存取方式:
http://192.168.42.127 - 部署模式:HTTP-only(無 TLS)、IP-only(無域名)
部署時的關鍵決策
1. 為何不用官方 getting-started.sh 腳本?
官方腳本是互動式的(讀取 /dev/tty),且預設選項需要公網域名與 Let's Encrypt。本次為內網 IP 部署,手動產生設定檔更直接。
腳本原始碼中支援 NETBIRD_DOMAIN=use-ip 模式(line 308),會自動偵測 IP 並切換為 HTTP、port 80、rel:// relay 協定。本次部署採用了相同的邏輯但以手動設定檔實現。
2. 為何選 Caddy 而非 Traefik 作為反向代理?
- Traefik 內建 Let's Encrypt ACME,但無域名時會反覆嘗試失敗
- Caddy 設定檔更精簡(約 10 行),純 HTTP 路由對本場景足夠
- 兩者都能正確處理 gRPC (h2c) 後端
3. 為何需要 crun 取代 runc?
遇到的錯誤:
OCI runtime create failed: runc create failed: unable to start container process:
error during container init: open sysctl net.ipv4.ip_unprivileged_port_start file:
reopen fd 8: permission denied
根因分析:
- Proxmox 非特權 LXC 將
/proc/sys掛載為唯讀(ro) - runc 1.2+ 為防止 TOCTOU 攻擊,會用「reopen fd」機制存取 sysctl 檔案
- 此機制在 LXC 的
/procmount namespace 限制下失敗
嘗試但無效的方法:
--privilegedflag--security-opt apparmor=unconfined --security-opt seccomp=unconfinedmount -o remount,rw /proc/sys- apt 安裝的 crun 1.14.1(OCI spec 太舊,Docker 不接受)
最終解法: 下載 GitHub 最新 crun binary (1.20),並設為 Docker 預設 runtime。
安裝步驟摘要
1. apt 安裝前置套件 (curl, jq, openssl) ← 約 1 分鐘
2. 安裝 Docker Engine ← 約 2 分鐘(網速慢)
3. 下載 crun binary,設定為 Docker 預設 runtime ← 約 30 秒
4. 建立 /opt/netbird/ 下四個設定檔 ← 約 30 秒
5. docker compose pull + up -d ← 約 1 分鐘
6. 等待 netbird-server 下載 GeoLite2 資料庫 ← 約 2-5 分鐘
總耗時約 10 分鐘(含 GeoIP 下載)。
服務驗證
所有服務已驗證正常運作:
| 端點 | 狀態 | 說明 |
|---|---|---|
http://192.168.42.127/ |
200 | Dashboard Web UI |
http://192.168.42.127/oauth2/.well-known/openid-configuration |
200 | OIDC Discovery |
STUN :3478/udp |
NAT 穿透 | |
| 內部 gRPC (Signal + Management) | h2c via Caddy |
疑難排解記錄
| 問題 | 原因 | 解法 |
|---|---|---|
| 初次 apt install 卡住 | 背景執行的 apt 行程未結束就被觸發第二個,導致 lock 競爭 | 清除 /var/lib/dpkg/lock* 與 /var/lib/apt/lists/lock,重啟 apt |
curl: command not found |
apt 仍在安裝中 | 等待安裝完成 |
| 所有 Docker 容器啟動失敗 | LXC /proc/sys 唯讀 + runc 1.3 的 reopen fd 機制 |
改用 crun 1.20 |
Docker Compose crun runtime 未知 |
/etc/docker/daemon.json 設定未生效 |
systemctl restart docker |
apt 的 crun 1.14.1 報 unknown version specified |
crun 的 OCI spec 1.0.0 與 Docker 29.4 不相容 | 從 GitHub 下載 crun 1.20 |
| 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 |
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 |
peer 之間一直走 Relay,[stun:...:3478] is Checking... |
STUN port 3478 被 Headscale (.126) 搶先佔用 DNAT |
NetBird 改用 3479/udp(server config + OpenWrt DNAT);見 stun-port-conflict.md |
STUN 都通了,仍然 Connection type: Relayed、ICE candidate: -/- |
客戶端 Force Relay Connection 開關被打開,跳過 ICE gathering | App Settings → Advanced → 關掉 Force Relay;見 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 |
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 |
新 peer netbird status 顯示 Connected 但互 ping 都不通 |
主機同時跑 Tailscale kernel-mode,iptables-legacy ts-input 把 100.64.0.0/10 非 tailscale0 封包全 drop,NetBird 100.71.0.0/16 中彈 |
iptables-legacy -I INPUT 1 -i wt0 -j ACCEPT + FORWARD 同理;systemd 持久化;詳見 peer-deployment-ops.md |
加 subnet route 後部分裝置拿不到路由(Networks: -、Status: Connecting) |
既有 NetBird daemon 不會自動重新套用 route,卡在舊 state | 各裝置重連 daemon:macOS launchctl kickstart、iOS App Disconnect→Connect、Docker compose restart;見 network-routes.md |
| iPhone RTSP app 連不到 LAN 攝影機(Safari 打 HTTP 可以) | 某些 iOS app 不走系統 VPN 路由 | 換支援 VPN 的 app(VLC 等),或改用 NetBird FQDN |
Dashboard 顯示 "SSH Access is disabled" 但 ssh 指令照通 |
Dashboard 的 "SSH Access" 是 NetBird 內建 SSH 通道,不等於目標機器的 OpenSSH | 兩種 SSH 是不同東西,不用理會那個提示;見 ssh-access.md |
| 某 peer 一直顯示 Connecting,但其本機 status 看起來 Connected | DNS 短暫 timeout → daemon 的 management gRPC 連線卡死,不自癒(Signal 還 Connected,但 Management Disconnected) | 直接重啟 daemon / container;可選加 watchdog;見 peer-deployment-ops.md |
檔案位置
本機(/Users/timmy/dev/42_127/)
├── README.md ← 專案總覽
├── QUICKSTART.md ← 快速部署步驟
├── SUMMARY.md ← 本檔(部署摘要)
├── netbird-selfhosted-setup.md ← 完整安裝指南
├── 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 排錯
├── peer-deployment-ops.md ← Docker 部署客戶端、改名、Mac daemon 重啟
├── groups-and-policies.md ← Groups 與 Access Control 設計與操作
├── network-routes.md ← Subnet Router (home-lan) 與 Exit Nodes (exit-ct100、exit-virmach-lax)
└── ssh-access.md ← 一般 SSH vs NetBird 內建 SSH 的差別
遠端伺服器(192.168.42.127:/opt/netbird/)
├── docker-compose.yml ← 服務編排
├── Caddyfile ← 反向代理路由
├── config.yaml ← NetBird Server 設定
└── dashboard.env ← Dashboard 環境變數
Docker Volume
netbird_netbird_data:NetBird SQLite 資料庫與 GeoIP 資料
後續維運
日常指令
ssh root@192.168.42.127
cd /opt/netbird
# 查看日誌
docker compose logs -f
# 重啟
docker compose restart
# 更新映像
docker compose pull && docker compose up -d
# 備份資料庫
docker compose exec netbird-server sqlite3 /var/lib/netbird/store.db ".backup /tmp/backup.db"
docker cp netbird-server:/tmp/backup.db ./backup-$(date +%F).db
可能的擴展
- 加上 TLS:若之後取得域名,可切換為 Traefik + Let's Encrypt(或本機自簽憑證)
- 外部 IdP:需支援 OIDC 的 IdP(如 Authentik、Keycloak、Google)可取代內建 Dex
- 高可用性:SQLite 不支援叢集,需改用 PostgreSQL;Relay 可獨立部署
- 監控:已暴露
metricsPort: 9090的 Prometheus 指標
參考資料
- 官方文件:https://docs.netbird.io/selfhosted/selfhosted-quickstart
- Getting Started 腳本:https://github.com/netbirdio/netbird/releases/latest/download/getting-started.sh
- crun release:https://github.com/containers/crun/releases
- Proxmox LXC Docker 相容性:https://pve.proxmox.com/wiki/Linux_Container#_features