安装
反向代理
一键脚本装出的 hub 只监听 127.0.0.1,公网访问不到,域名由反向代理接进来。下面任选一种。
caddy
证书、X-Forwarded-Proto 和 WebSocket 都由 caddy 自动处理,请求体大小默认不限:
hub.example.com {
reverse_proxy 127.0.0.1:28080
}caddyfilenginx
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 分片上传,8m 足够,与数据库大小无关
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;
# /api/agent/ws 与 /api/ws 是 WebSocket 长连接
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
}nginx80 端口跳转到 HTTPS:
server {
listen 80;
listen [::]:80;
server_name hub.example.com;
return 301 https://$host$request_uri;
}nginx宝塔 / aapanel
面板里添加的反向代理可以直接用,目标地址填 http://127.0.0.1:28080。它生成的配置里没有
X-Forwarded-Proto,会话 cookie 因此拿不到 Secure 标志,要在站点配置文件的 location ^~ / 块里补一行:
proxy_set_header X-Forwarded-Proto $scheme;nginx改的是站点配置文件。改完不要再在反向代理的表单里点保存,那会重新生成这段配置,这一行随之丢失。
Cloudflare 隧道
隧道由 cloudflared 向外建立,不用开入站端口,只有 IPv4 的机器也能得到双栈入口。配置保存为
~/.cloudflared/config.yml:
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:404yaml# 建隧道,并把域名解析到它
cloudflared tunnel create monitor
cloudflared tunnel route dns monitor hub.example.com
# 装成系统服务;只想临时试跑用 cloudflared tunnel run monitor
cloudflared service installbash在 WAF 或边缘规则里按路径做了放行列表的,要覆盖 hub 的全部路径和主题的前端路由(默认主题的节点详情页是 /node/{id})。被挡的请求 403 来自边缘,hub 没有日志:升级 hub 后新增的接口不通,或详情页「点进去正常,一刷新就被拦」,都是这个原因。路径清单见架构与协议。
四项必需的设置
上面的 caddy 和 nginx 配置已经满足前三项。自己改写配置、或用别的反代时逐项核对。
1. 转发 WebSocket 头,关掉缓冲,放大超时
/api/agent/ws(agent 上报)和 /api/ws(浏览器实时推送)是长连接。没转发 Upgrade / Connection
头,或读写超时还是默认的 60 秒,节点会周期性掉线又自己回来。
2. 请求体上限 8 MiB
导入备份和上传主题按 4 MiB 分片上传,hub 对单个请求的上限是 8 MiB。这个数不随数据库变大:256 MiB 的备份也只是 64 个 4 MiB 的请求,Cloudflare 免费版每个请求 100 MB 的上限同样够用。
nginx 默认的 client_max_body_size 1m 连一片都放不过。这时 413 来自反代,hub 没有日志,面板收到 413
会直接提示调大 client_max_body_size。
3. 透传 X-Forwarded-Proto 和 X-Forwarded-For
- 没有
X-Forwarded-Proto:会话 cookie 拿不到Secure - 没有
X-Forwarded-For:登录限流按反代的地址计数,所有访客共用一个计数;节点的连接来源也记成反代地址,NAT 后面的节点显示不出出口地址,网卡上没有公网地址的节点也查不到国家(国家的首选地址是节点网卡上的公网地址,只有网卡上没有公网地址时才轮到连接来源,见地址与国家)
hub 只在连接来自本机或内网地址时才采信 X-Forwarded-For,并取最后一个值。上面的写法都是追加而不是覆盖,最后一个值就是反代实际看到的地址。
前面是 Cloudflare(域名开了代理,或走隧道)时,节点的出口地址和国家不用另外配置:hub 在通过 token
校验的 agent 连接上读取 Cloudflare 写入的 CF-Connecting-IP。登录限流不读这个头,因为从 Cloudflare
网络连到源站的不只有它的代理(Worker 也可以),这个头能被伪造;限流因此仍按边缘地址计,同一个边缘后面的访客共用一个计数。
前面是别家 CDN,或隧道先到本机的 nginx 再到 hub 时,最后一个值是边缘或隧道的地址,所有访客共用一个限流计数;别家 CDN 后面,NAT 节点的出口地址和国家也按边缘算。在反代上把边缘地址换回访客地址,只信任列出的网段:
# 写在 server 块里。每个回源网段一行,照 CDN 公布的列表填;隧道在本机时填 127.0.0.1
set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;nginxnginx 要带 realip 模块,nginx -V 2>&1 | grep realip 有输出即可。caddy 的写法:
{
servers {
trusted_proxies static 192.0.2.0/24
trusted_proxies_strict
}
}
hub.example.com {
reverse_proxy 127.0.0.1:28080 {
header_up X-Forwarded-For {client_ip}
}
}caddyfile不要写 proxy_set_header X-Forwarded-For $http_cf_connecting_ip;,本页早先的版本给过这一行,照抄过的请删掉。有人绕过 Cloudflare 直连源站时,这个头由他自己填:换着值试密码,登录限流就失效;填上你的地址,你会被锁在登录页外 15 分钟。
4. 放行 POST / PUT / DELETE
面板的写操作用到这三个方法。只放行 GET / HEAD 的 WAF 规则会让整个后台变成只读。
验证
# 面板能打开,且走 HTTPS:第一行是 200
curl -sI https://hub.example.com/admin | head -1
# WebSocket 能升级:输出 101。升级后连接保持,3 秒后由 --max-time 结束
curl -s --http1.1 --max-time 3 -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/wsbash面板节点页的「添加节点」能点,说明入口被判为可用:要么是从 HTTPS 域名进的,要么是同一内网直连(私网 IP + 明文,且没有经过反代,见内网直连可以用明文)。从公网的
IP 或明文地址进面板时它是灰的。hub 看三样:反代转发过来的 Host(必须是域名)、X-Forwarded-Proto(必须是 https,没给 hub 配 --site 时尤其重要),以及浏览器发来的 Origin(带了就必须和 Host 同源)。所以反代既要在 Host 里保留域名、透传
X-Forwarded-Proto,也不要清掉或改写 Origin。
上面那个「内网直连」的例外不会漏进来:它要求这次请求没有声明 X-Forwarded-Proto,且 hub 看到的客户端地址(本机反代会取 X-Forwarded-For 的最后一段)是私网地址。反代声明了 https、或转发的是一段公网地址,都回到老规矩。
X-Forwarded-Proto 是否生效,看登录后的会话 cookie 有没有 Secure 标志:浏览器开发者工具的应用 → Cookie 里,monitor_session 那一行。