VTS模块需三处配置对齐才能按server_name实时统计流量:声明vhost_traffic_status_zone共享内存区、启用vhost_traffic_status_filter_by_host、将/status接口置于server块内。

要让 VTS 模块真正按每个虚拟主机(即 server_name)实时统计流量,关键不是“开了模块就行”,而是三处配置必须对齐:共享内存区声明、host 过滤启用、状态接口落位。缺一不可,否则看到的全是 default 或 unknown。
vhost_traffic_status_zone 必须显式声明
这个指令是数据归集的根基,不写它,VTS 就没有地方存各虚拟主机的独立计数。
- 放在
http块顶部,格式为:vhost_traffic_status_zone shared:vts:10m;,其中shared:vts是共享内存区名称,10m是分配大小(百个域名建议至少 16m) - 如果用了
upstream,对应 upstream 块里也要加同名 zone,例如:upstream api_backend { vhost_traffic_status_zone vts; } - 避免用变量做
proxy_pass,比如proxy_pass http://$backend,VTS 解析不出目标,所有流量都会进unknown
开启 host 级过滤才能看到域名维度
默认情况下,VTS 的 JSON 接口返回的是 zone 名,不是你配置的 server_name。要让指标真正对应到域名,得靠 host 过滤。
- 在
http块开头加:vhost_traffic_status_filter_by_host on; - 每个
server块的server_name必须写明确域名,不要用通配符(如*.example.com),否则匹配失败,数据仍归default - 验证方式:访问
/status/format/json,检查serverZones下是否出现"api.example.com"这类键名,而不是"default"
status 接口必须放在 server 块内
VTS 需要从请求上下文中提取 Host 头,才能把请求归属到对应虚拟主机。把 location /status 放在 http 层,就拿不到这个上下文。
- 正确写法:
server { server_name example.com; location /status { vhost_traffic_status_display; vhost_traffic_status_display_format json; allow 127.0.0.1; deny all; } } - URI 必须严格匹配
/status,不能带尾部斜杠或子路径;只响应 GET 请求 - 生产环境建议关闭 HTML 页面(删掉
vhost_traffic_status_display_format html),仅暴露 JSON,减少资源开销
按业务维度再细分流量(可选但实用)
光分到域名还不够细?可以用 vhost_traffic_status_filter_by_set_key 打标,把流量按客户、地区或路径自动分组。
- 按客户 ID(取 URL 参数):
vhost_traffic_status_filter_by_set_key $arg_cid client::$server_name;,JSON 中会出现"client::api.example.com" - 按国家(需 GeoIP):
vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; - 按接口路径前缀:
set $route "$host:$request_uri"; vhost_traffic_status_filter_by_set_key $route route::$server_name;










