Loading... ## 前言 之前有用 [wireguard](https://www.wireguard.com/) 来做服务器间的互联(服务暴露),但是一直都是手动配置的,有些繁琐。遂有考虑服务器间的 full mesh 互联方案,偶然间了解到了 [netbird](https://netbird.io),基于 wireguard 的零信任方案,对比 [tailscale](https://tailscale.com/),服务端/客户端全开源,果断选择了它。 netbird 的整个部署过程,早期还是比较繁琐的,主要还是 IDP 部分,坑很多,当初自建颇费了一番功夫。不过随着发展,目前部署已经相当方便了。之前想着写文章记录下的,但是太懒了搁置了(~~看我更新频率就知道了 (~~)。然后前段时间 netbird 更新了 [reverse-proxy 功能](https://docs.netbird.io/selfhosted/migration/enable-reverse-proxy),我感觉还是很方便的: 1. 基础反向代理功能,支持 L4/L7 代理; 2. 支持自动申请证书; 3. 相同的 proxy 域名自动组成 cluster,可以在不同区域部署多个 proxy 实例,结合分区域解析的 DNS 可以快速构建一个简单的类 CDN 的加速方案; 4. 支持增加各种认证,保护后端服务 刚好,这两天又搞了个 netbird-proxy 实例,那就……记录下吧。 ## 限制 反代 http/https 服务的话,由于 netbird-proxy 对外提供 HTTPS,且必须要在 netbird-proxy 上进行证书验证(它目前要么通过 ACME 自动申请,要么提供泛域名证书),所以 netbird-proxy 之前如果还有代理的话,必须进行 tls 透传。目前官方是要求使用 [traefik](https://traefik.io/),但是我习惯了使用 nginx,也有一些服务已经依托于 nginx 了,所以不想切换到 traefik,所以本文也是基于 nginx 做前置进行部署。 另外,对于多个 proxy 实例,由于每个实例都是自助进行证书申请的,那么在需要反代的 service 很多、实例很多的时候,很大概率会达到 Lets‘ Encrypt 的速率限制。官方建议使用泛域名证书,但是却只能指定一个证书,我有多个域名,并不想合并到一个证书中,这个方法行不通。本来想了一个方案,一个主 proxy 负责证书申请,然后同步到其他 proxy 中,但是发现若关闭了 proxy 的自动证书申请,那它就自动要读取本地的泛域名证书,没有的话 proxy 压根就跑不起来了,路又被堵住了。目前这个没想到什么好办法解决,暂时控制下 proxy 数量,看看后续 netbird 是否提供更好的方案。 ## 部署过程 ### Nginx 透传 TLS netbird-proxy 本身完全可以自己独立工作(监听 443 端口),但由于我有一些需求需要通过 nginx 实现,所以要考虑这俩共存。 在限制一节中已经提到,netbird-proxy 需要其前的代理透传 TLS,但是 nginx 的 http 块是不支持 TLS 透传的,需要采用 stream 模块进行 L4 代理。但是,同时,也要确保 http 块的反代请求正常。 所以,方案如下: 1. 使用 stream 模块,监听所有的 443 端口请求; 2. 根据 sni 进行分流: 1. 需要 nginx http 反代的走 nginx http 监听端口; 2. 需要 netbird proxy 反代的走 netbird proxy 监听端口 具体的配置示例如下: ```shell # 省略部分内容,请勿直接复制使用,根据实际情况修改 # ========================================================================= # 1. STREAM 块 (负责 443 端口的四层 SNI 分流) # ========================================================================= stream { # 开启 SNI 预读 ssl_preread on; # 根据域名映射后端 map $ssl_preread_server_name $stream_map { netbird.10101.io nginx_http_backend; default netbird_proxy_backend; # 默认透传给 netbird-proxy } # 监听 443 端口 server { listen 443; listen [::]:443; proxy_pass $stream_map; proxy_protocol on; # 开启 proxy protocol,向后端保留客户端 IP proxy_connect_timeout 60s; proxy_timeout 30m; } # 后端:Netbird 代理 upstream netbird_proxy_backend { server 127.0.0.1:18443; } # 后端:本机的 HTTP/HTTPS 服务块 upstream nginx_http_backend { server 127.0.0.1:8443; } } # ========================================================================= # 2. HTTP 块 (负责七层业务处理,如证书解密、静态资源、反向代理) # ========================================================================= http { # 使用 real_ip 模块从 PROXY PROTOCOL 中提取真实的客户端 IP # 这样后端应用就能拿到真实的客户端 IP set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; # 业务服务器:接收来自 stream 块分流过来的请求 server { # 【重要】这里必须加上 ssl 和 proxy_protocol listen 8443 ssl proxy_protocol; listen [::]:8443 ssl proxy_protocol; server_name netbird.10101.io; } } ``` 需要特别注意的是 `proxy protocol` 的处理,否则 netbird 端的 access log 会缺失真实的客户端 IP。 ### Netbird Proxy 部署 netbird-proxy 部署就比较简单了,docker compose 一把梭。 #### 完整 docker-compose.yml ```yaml services: proxy: image: netbirdio/reverse-proxy:latest container_name: netbird-proxy restart: unless-stopped networks: [netbird] ports: - 127.0.0.1:18443:8443 env_file: - ./proxy.env volumes: - ./certs:/certs depends_on: crowdsec: condition: service_healthy logging: driver: "json-file" options: max-size: "500m" max-file: "2" crowdsec: image: crowdsecurity/crowdsec:v1.7.8 container_name: netbird-crowdsec restart: unless-stopped networks: [netbird] environment: COLLECTIONS: crowdsecurity/linux volumes: - ./crowdsec/config:/etc/crowdsec - ./crowdsec/db:/var/lib/crowdsec/data healthcheck: test: ["CMD", "cscli", "lapi", "status"] interval: 10s timeout: 5s retries: 15 logging: driver: "json-file" options: max-size: "500m" max-file: "2" networks: netbird: ipam: config: - subnet: 172.30.0.0/16 gateway: 172.30.0.1 ``` 如上,除了 proxy 外,还加了个 crowdsec service,下面具体说明下 #### Crowdsec [Crowdsec](https://www.crowdsec.net/) 是一款社区维护的威胁情报引擎,目前 netbird 集成了 crowdsec,可多提供一层保护,可以跟随 netbird proxy 一起部署。 ```shell # 1. 启动 crowdsec docker compose up -d crowdsec # 2. 查看状态 docker compose exec crowdsec cscli lapi status # 3. 获取 key docker compose exec crowdsec cscli bouncers add netbird-proxy -o raw ``` 复制好生成的 API key,后续 proxy 注册需要用到 #### Proxy ##### 创建 proxy token ```bash # 1. 生成新的 token docker exec -it netbird-server /go/bin/netbird-server --name "my-proxy1" --config <netbird-data-dir>/config.yaml token create # 2. 查看所有的 token docker exec -it netbird-server /go/bin/netbird-server --name "my-proxy1" --config <netbird-data-dir>/config.yaml token list # 3. 撤销 token docker exec -it netbird-server /go/bin/netbird-server --name "my-proxy1" --config <netbird-data-dir>/config.yaml token revoke <token-id> ``` netbird 官方建议每个 proxy 实例使用不同的 token。 ##### 配置环境变量 配置 proxy 的环境变量文件 `proxy.env`,具体内容参考如下: ```bash # proxy 域名,cname 用 NB_PROXY_DOMAIN=proxy.netbird.10101.io NB_PROXY_TOKEN={生成的 proxy token} # netbird management 地址 NB_PROXY_MANAGEMENT_ADDRESS=https://netbird.10101.io:443 NB_PROXY_ALLOW_INSECURE=false NB_PROXY_ADDRESS=:8443 NB_PROXY_ACME_CERTIFICATES=true NB_PROXY_ACME_CHALLENGE_TYPE=tls-alpn-01 NB_PROXY_CERTIFICATE_DIRECTORY=/certs NB_PROXY_CROWDSEC_API_URL=http://crowdsec:8080 NB_PROXY_CROWDSEC_API_KEY={生成的 crowdsec API key} # Enable PROXY protocol to preserve client IPs through L4 proxies (TCP passthrough) NB_PROXY_PROXY_PROTOCOL=true # Trust Proxy's IP for PROXY protocol headers # NB_PROXY_TRUSTED_PROXIES=172.30.0.10 NB_PROXY_PRIVATE=true ``` 这里需要注意的是 `NB_PROXY_PROXY_PROTOCOL`,开启 `proxy protocol` 支持,确保 netbird 能正确显示访问者源 IP 配置好后,启动即可: ```bash docker compose up -d proxy ``` ## 参考资料 - [netbird 官方文档](https://docs.netbird.io) 最后修改:2026 年 06 月 24 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏