Files
netbird-selfhosted/SUMMARY.md
Timmy f091499ff3 docs: add NetBird exit nodes via CT100 (TW) and virmach-lax (US)
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>
2026-04-18 23:39:36 +08:00

9.1 KiB
Raw Permalink Blame History

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 的 /proc mount namespace 限制下失敗

嘗試但無效的方法

  • --privileged flag
  • --security-opt apparmor=unconfined --security-opt seccomp=unconfined
  • mount -o remount,rw /proc/sys
  • apt 安裝的 crun 1.14.1OCI 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 分鐘
手機 Appserver closed the stream without sending trailers 透過 NPM 對外公開時NPM 用 proxy_pass 而非 grpc_pass 轉 gRPC加上 Caddy :80 預設不支援 h2c NPM 加 advanced_configgRPC 路由)+ Caddy 全域啟用 protocols h1 h2 h2c;見 npm-grpc-fix.md
PUT /api/setup-keys/{id} 回 200 但 name 沒改 NetBird API 只更新 auto_groupsrevokedname 是 read-only store.dbsetup_keys.name → 重啟 netbird-server;見 setup-keys-and-pat.md
peer 之間一直走 Relay[stun:...:3478] is Checking... STUN port 3478 被 Headscale (.126) 搶先佔用 DNAT NetBird 改用 3479/udpserver config + OpenWrt DNATstun-port-conflict.md
STUN 都通了,仍然 Connection type: RelayedICE candidate: -/- 客戶端 Force Relay Connection 開關被打開,跳過 ICE gathering App Settings → Advanced → 關掉 Force Relayclient-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-passwordyes 先出現first-match-wins /etc/ssh/sshd_config.d/99-allow-root.conf 覆蓋socket activation 不需重啟 sshd
新 peer netbird status 顯示 Connected 但互 ping 都不通 主機同時跑 Tailscale kernel-modeiptables-legacy ts-input100.64.0.0/10 非 tailscale0 封包全 dropNetBird 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 各裝置重連 daemonmacOS launchctl kickstart、iOS App Disconnect→Connect、Docker compose restart;見 network-routes.md
iPhone RTSP app 連不到 LAN 攝影機Safari 打 HTTP 可以) 某些 iOS app 不走系統 VPN 路由 換支援 VPN 的 appVLC 等),或改用 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可選加 watchdogpeer-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_dataNetBird 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 不支援叢集,需改用 PostgreSQLRelay 可獨立部署
  • 監控:已暴露 metricsPort: 9090 的 Prometheus 指標

參考資料