monitor

部署

反向代理

nginx、caddy、Cloudflare 隧道的完整配置,以及必须注意的四件事。

一键脚本装出来的 hub 只监听 127.0.0.1,公网访问不到——凭证不会在链路上明文传输, 也没有端口需要防火墙。把域名指过来是反向代理的活。

配好之后 hub 的参数一个都不用改。 面板用浏览器地址栏里的地址拼安装命令, 所以你改用 https://hub.example.com 进后台,就能添加节点并拿到 --server https://hub.example.com 的安装命令;会话 cookie 的 Secure 跟着请求的 X-Forwarded-Proto 走。

caddy

证书、X-Forwarded-Proto、WebSocket 都自动处理,一行就够:

hub.example.com {
    reverse_proxy 127.0.0.1:28080
}
caddyfile

caddy 默认不限请求体大小,所以下面那条 8 MiB 的注意事项对它不适用。

nginx

map $http_upgrade $connection_upgrade { default upgrade; '' close; }
 
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name hub.example.com;
    ssl_certificate     /etc/letsencrypt/live/hub.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/hub.example.com/privkey.pem;
 
    location / {
        proxy_pass http://127.0.0.1:28080;
        proxy_http_version 1.1;
 
        # 导入备份和上传主题是分片传的,单片 4 MiB,所以这个数只跟分片大小
        # 有关,跟数据库多大无关。其余路径 hub 自己卡在 64 KiB。
        client_max_body_size 8m;
 
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
 
        # WebSocket:/api/agent/ws 与 /api/ws 是长连接
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_buffering off;
        proxy_read_timeout  1h;
        proxy_send_timeout  1h;
    }
}
nginx

顺手把 80 端口跳到 443:

server {
    listen 80;
    listen [::]:80;
    server_name hub.example.com;
    return 301 https://$host$request_uri;
}
nginx

Cloudflare 隧道

不用开任何入站端口,纯 IPv4 的机器也能拿到双栈入口——cloudflared 的隧道是出站建立的。

tunnel: <tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json
 
ingress:
  - hostname: hub.example.com
    service: http://127.0.0.1:28080
  - service: http_status:404
yaml
cloudflared tunnel create monitor
cloudflared tunnel route dns monitor hub.example.com
cloudflared service install     # 或 cloudflared tunnel run monitor
bash

在边缘做了路径白名单的话,升级 hub 时记得同步。 新版本加的路由会被上一版的名单挡在外面, 而且 403 来自边缘,hub 侧一行日志都没有。面板用到的全部路径见架构与协议

四件必须注意的事

1. 转发 WebSocket 头,关掉缓冲,把超时放大

/api/agent/ws(agent 上报)和 /api/ws(浏览器实时推送)都是长连接。 Upgrade / Connection 头没转发、或者读写超时留在默认的 60 秒,症状是节点周期性掉线又自己回来

2. 请求体上限设 8 MiB,不用更大

导入备份和上传主题都是分片传的:单片 4 MiB,hub 侧单请求硬上限 8 MiB。 所以这个数不随数据库增长——256 MiB 的备份也只是 64 个 4 MiB 的请求。

nginx 默认的 client_max_body_size 1m 连一片都放不过去。被反代拒掉时 413 来自反代, hub 这边一行日志都没有,所以面板收到 413 会直接把 client_max_body_size 念给你看。

Cloudflare 免费版 100 MB 的上传上限因此也不是天花板,单个请求离它差一个数量级。

3. 透传 X-Forwarded-ProtoX-Forwarded-For

  • 没有 X-Forwarded-Proto,会话 cookie 拿不到 Secure
  • 没有 X-Forwarded-For,登录限流会按代理地址计数——所有人共用一个桶

hub 取 X-Forwarded-For最后一跳,而且只在 peer 本身是本地地址时才采信。 文档里这两种反代都是追加而不是覆盖,所以链尾才是代理真正看到的地址。

本地反代前面再套一层 CDN 时,链尾是边缘的地址,所有访客共用一个限流桶。 那种部署得让边缘自己写客户端地址(Cloudflare 的 CF-Connecting-IP),再由本地反代覆盖 X-Forwarded-For

proxy_set_header X-Forwarded-For $http_cf_connecting_ip;
nginx

4. 放行 POST / PUT / DELETE

面板的写操作用到这三个方法。有些默认只放行 GET / HEAD 的 WAF 规则会把整个后台变成只读。

验证

# 面板打得开,且是 https
curl -sI https://hub.example.com/admin | head -1
 
# WebSocket 能升级(应答 101)
curl -sI -o /dev/null -w '%{http_code}\n' \
  -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
  -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
  https://hub.example.com/api/ws
bash

面板里能看到「添加节点」并生成不带 --insecure 的安装命令,就说明 TLS 和 X-Forwarded-Proto 都对了——这两件事面板自己会检查,你不用猜