概述 链接到标题

用 NetBird 自建控制平面,替换现有的 WireGuard VPN 手动组网。控制平面部署在云服务器上,所有节点通过 P2P WireGuard 隧道互联。

步骤 链接到标题

1. Traefik v2 → v3 升级 链接到标题

现有 Traefik 版本是 v2.10.7,先升级到 v3.7.5 为后续路由做准备。

兼容性分析:

  • 文件配置文件(File provider)的 YAML 语法完全兼容,无需改动
  • --serversTransport.insecureSkipVerify CLI 参数名不变
  • ipwhitelist 中间件重命名为 ipAllowList,在 v3 中需要手动迁移
  • 升级时需要加 --core.defaultrulesyntax=v2 保持路由语法兼容,确认稳定后移除

升级步骤:只需改 Docker Compose 的 image tag,重启即可。

2. NetBird 控制平面部署 链接到标题

控制平面用 Docker Compose 部署,使用 NetBird v0.65+ 的合并容器架构,不再需要分开的 management/signal/relay/coturn 四个容器。

架构:

  • netbirdio/netbird-server — 合并容器,包含 management + signal + relay + STUN
  • netbirdio/dashboard — Web 管理界面
  • SQLite 存储(无需 PostgreSQL)

Traefik 路由:

  • nb.example.com → dashboard(Web UI)
  • api.nb.example.com → combined server(gRPC + REST API + WebSocket)

3. 内网 DNS 服务器 链接到标题

在办公室的节点上用 Docker 部署 dnsmasq 2.93,提供 *.lan 域名解析。

选型:dnsmasq 仍然是最轻量的内网 DNS 方案。2026年5月 dnsmasq 被通报了 6 个 CVE(CVE-2026-2291 等),修复版本 2.93,务必使用最新版。

镜像:使用 dockurr/dnsmasq(GitHub 开源,500K+ pulls),支持 arm64。由于 Docker Hub 被墙,通过 DaoCloud 镜像拉取。

4. NetBird Agent 安装 链接到标题

两个节点安装 agent:

  • 云服务器(控制平面所在节点)— 也需要装 agent,控制平面和 agent 是两回事,可以共存
  • 办公室节点(同时跑 dnsmasq)

踩坑记录 链接到标题

Signal 连接不上 链接到标题

现象:agent 的 Management 显示 Connected,但 Signal 始终 Disconnected。日志报错 missing port in address

原因:NetBird 合并容器的 exposedAddress 配置中必须包含端口号。例如 https://api.example.com:443,否则客户端解析 Signal URI 时获取不到端口,gRPC 拨号失败。

解决:在 config.yamlserver.exposedAddress 中显式加上 :443

DNS 端口冲突 链接到标题

现象:dnsmasq 无法启动,报错 Address in usess 发现 NetBird agent 内部 DNS 代理占用了 53 端口。

原因:NetBird agent 收到 Nameserver Group 配置后,会在本地启动 DNS 代理监听 53 端口。与已有 dnsmasq 冲突。

解决:在 DNS 服务器所在的节点上禁用 NetBird 的 DNS 代理:

{"disable_dns": true}

写入 /etc/netbird/config.json 后重启 agent。

FQDN 解析失败 链接到标题

现象:短名 server-a 能解析,但 server-a.lan(FQDN)返回 NXDOMAIN。

原因:dnsmasq 的 expand-hosts 只对 /etc/hosts 中的短名生效,自动添加 domain 后缀。但通过 NetBird Nameserver Group 发来的查询已经是 FQDN 格式(server-a.lan),expand-hosts 不会再次匹配。

解决:使用 dnsmasq 的 address=/ 指令显式声明 FQDN 映射:

address=/server-a.lan/10.0.0.50
address=/server-b.lan/10.0.0.51

而非依赖 /etc/hosts + expand-hosts

STUN 端口未开放 链接到标题

现象:两个 agent 注册后无法建立 P2P 连接,Nameserver 显示 required key not available

原因:STUN UDP 3478 端口未在云服务器安全组中开放,NAT 穿透失败。

解决:在安全组中添加 UDP 3478 入站规则。

最终拓扑 链接到标题

云服务器 (控制平面 + agent)
  ├── Traefik v3 (nb.example.com / api.nb.example.com)
  ├── NetBird combined server (Docker)
  └── NetBird agent (WireGuard peer)
        │ P2P 隧道
办公室节点 (agent + dnsmasq)
  ├── NetBird agent
  └── dnsmasq 2.93 (Docker, host network)
        │
        └── 解析 *.lan 域名

所有节点 → Nameserver Group → 办公室节点:53 → 解析 *.lan

总结 链接到标题

NetBird 的自建方案已经成熟,合并容器架构让部署简化很多。关键点是配置文件中的细节(端口号、DNS 代理冲突、FQDN 格式),踩过一遍就清楚了。