反向代理与 HTTPS
放到公网时,在 evstats 前面加一层反向代理终止 HTTPS。这一页给出 Nginx 和 Caddy 的配置,以及两个必须填的设置。
三条规则
- 整个站点都转给 evstats:所有路径,不要只转
/api。仪表盘、采集、Agent、OpenAPI 都在同一个进程上。 - Agent 的路径关掉缓冲:
/dash/agent/下的回答是 SSE 流,被缓冲就会等到最后才一次性出来,甚至超时。 - 用独立的域名或子域名:本期不支持挂在子路径下(例如
https://example.com/evstats/)。
evstats 听哪里
evstats 默认对所有网卡听 51321,不占用 Nginx 的 80 端口。反代与 evstats 在同一台机器上时,转到 127.0.0.1:51321。进程不能改成只绑某一张网卡;要限制谁能连,用防火墙,或让容器只把端口映射到本机。
| 部署方式 | 怎么设 |
|---|---|
| 容器 | 不写 EVS_PORT。宿主机映射写成 "127.0.0.1:51321:51321",公网只走 Nginx(见 生产环境部署) |
| 二进制 | 不写 EVS_PORT 即听 51321。同机 Nginx 转发到 127.0.0.1:51321,再用防火墙挡住从外面直接访问这个端口(见 二进制与 systemd) |
要换端口时设置 EVS_PORT(或启动参数 -port),反代和端口映射一起改。
反代在另一台机器上时,防火墙只放行反代访问这个端口。
Nginx
# evstats 的 HTTPS 反向代理示例。把整个站点(所有路径)转给 evstats,不要只转 /api。
# 这里假设 evstats 与 Nginx 在同一台机器,evstats 默认听 :51321:
# - 容器部署:deploy/production/evstats/compose.yaml(映射 127.0.0.1:51321:51321)
# - 二进制部署:不设 EVS_PORT 即对所有网卡听 51321;用防火墙挡住从外面直接访问这个端口
# 配好之后:
# - 系统配置 → 站点:site.public_url 填 https://stats.example.com(找回密码的邮件链接用它)
# - 系统配置 → 采集调优:http.trusted_proxies 填 127.0.0.1/32,否则访客 IP 都是反代自己
server {
listen 80;
server_name stats.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name stats.example.com;
ssl_certificate /etc/nginx/certs/stats.example.com.crt;
ssl_certificate_key /etc/nginx/certs/stats.example.com.key;
# 采集请求体最大 1MB,回放单块最大 2MB,这里留出余量
client_max_body_size 4m;
# 过程指标只给本机或内网监控
location = /metrics {
allow 127.0.0.1;
deny all;
proxy_pass http://127.0.0.1:51321;
}
location / {
proxy_pass http://127.0.0.1:51321;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Agent 的回答是 SSE 流:关掉缓冲,留足读超时
location /dash/agent/ {
proxy_pass http://127.0.0.1:51321;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 180s;
}
}这份文件在源码仓库的 deploy/nginx/evstats.conf,也可以直接下载:curl -fsSLO https://evstats.mosong.cc/deploy/nginx/evstats.conf。client_max_body_size 4m 给采集(单个请求最大 1MB)和会话回放(单块最大 2MB)留出余量。Agent 一次提问最长 120 秒,proxy_read_timeout 要大于它。
Caddy
Caddy 自动申请证书,也会自己带上 X-Forwarded-For 和 X-Forwarded-Proto:
stats.example.com {
request_body {
max_size 4MB
}
@metrics path /metrics
respond @metrics 404
reverse_proxy /dash/agent/* 127.0.0.1:51321 {
flush_interval -1
}
reverse_proxy 127.0.0.1:51321
}flush_interval -1 让 Agent 的流立即转发,不做缓冲。
填上可信代理
在「系统配置 → 采集调优」里把反代的地址填进 http.trusted_proxies,逗号分隔的 CIDR,例如反代和 evstats 在同一台机器时填 127.0.0.1/32。
- 这一项留空时,evstats 不采信任何
X-Forwarded-For/X-Real-IP,只用 TCP 连接的对端地址。于是在反代后面,所有访客的 IP 都会是反代自己,地域也就全是「未知」。 - 填了之后,只有对端落在这些网段里时才读转发头,并从右往左取第一个不在可信网段里的地址。伪造的转发头骗不过它。
- 登录失败限流按「用户名 + 客户端 IP」计数,同样用这个规则取 IP。
多台负载均衡时,把所有负载均衡的网段都填上。
填上对外地址
在「系统配置 → 站点」里填 site.public_url,例如 https://stats.example.com,不带末尾的 /。找回密码的邮件链接只用这个地址拼接,不看请求里的 Host 头,这样伪造的 Host 骗不走重置令牌。不填就不能找回密码。
HTTPS 与 Cookie
登录用的 Cookie evstats_sid 带 HttpOnly 和 SameSite=Lax。检测到 HTTPS 时再加 Secure:
- 在反代后面:对端是可信代理,并且带
X-Forwarded-Proto: https。 - 没有可信代理时:只有直接用 TLS 连到 evstats 才算。
所以上一节的 http.trusted_proxies 不填,Cookie 就不会带 Secure。
检查
curl -sS https://stats.example.com/health
curl -sS -o /dev/null -w '%{http_code}\n' https://stats.example.com/metrics # 应当是 403 或 404然后在浏览器里登录、打开 Agent 问一个问题,回答应当逐字出现,而不是等很久一次出来。