nginx原生不支持正向代理,需借助ngx_http_proxy_connect_module等第三方模块才能实现;启用后可通过自定义log_format记录$request_length和$bytes_sent字段,并按$remote_addr聚合统计http明文流量,但https隧道内真实流量无法获取。

Nginx 本身不支持正向代理(即作为客户端出口代理,如 HTTP CONNECT 代理),它原生只支持反向代理。要实现正向代理并统计每个客户端的外网流量,必须借助第三方模块(如 ngx_http_proxy_connect_module)或改用专为正向代理设计的软件(如 Squid、TinyProxy)。但若你已通过编译该模块启用了 Nginx 正向代理能力,那么统计客户端外网流量需从日志格式和变量入手——核心在于记录请求体大小、响应体大小,并按客户端 IP 聚合分析。
确认 Nginx 已启用正向代理并捕获必要字段
使用 ngx_http_proxy_connect_module 后,Nginx 可处理 CONNECT 请求(用于 HTTPS 代理)和普通 HTTP 请求。默认 access_log 不含流量字段,需手动扩展日志格式:
- 在
http块中定义自定义日志格式,包含请求与响应的字节数:
其中:
$body_bytes_sent:响应体实际发送的字节数(不含响应头);
$request_length:整个请求(含请求行、头、正文)长度;
$bytes_sent:响应总字节数(含响应头 + 响应体),更适合作为“外网下行流量”指标;
$request_length 可近似视为“上行流量”,但注意:对 CONNECT 隧道,Nginx 不解析隧道内数据,因此该值仅反映 CONNECT 请求本身的开销(通常很小),真实 HTTPS 流量无法被 Nginx 日志直接记录。
按客户端 IP 统计流量的常用方法
日志生成后,需离线或实时聚合。以下为典型操作路径:
- 用 awk 按 IP 汇总上行($request_length)和下行($bytes_sent):
(假设 $bytes_sent 是倒数第二个字段,$request_length 是最后一个;请根据实际 log_format 字段顺序调整)
- 用 GoAccess、GoAccess 或自定义 Python 脚本做可视化汇总;
- 接入 ELK(Elasticsearch + Logstash + Kibana):Logstash 解析日志字段,Kibana 按 client_ip 分组 sum(bytes_sent) 即得各客户端外网下行总流量。
重要限制与注意事项
正向代理场景下,Nginx 的流量统计存在本质局限:
- HTTPS 流量(CONNECT 隧道)完全加密,Nginx 仅知道连接建立、断开时间及隧道元信息,无法获取隧道内传输的实际字节数;日志中的 $bytes_sent 仅反映 CONNECT 响应头大小(通常 200 OK + 头,约 100–200 字节),不代表真实外网流量;
- HTTP 明文请求可统计完整上下行($request_length 和 $bytes_sent),但若后端返回 304 或使用 gzip 压缩,$bytes_sent 为压缩后大小,与原始内容不等;
- 若需精确统计所有外网流量(尤其 HTTPS),应考虑在网络层抓包(如 tcpdump + tshark 按 client IP 过滤并统计 TCP payload),或改用支持透明代理和深度流量统计的方案(如 Squid 的
access_log+logformat支持 %>s 和 %
替代建议:更合适的正向代理选型
若流量统计是刚需,推荐切换到 Squid:
- 原生支持正向代理 + 完整 CONNECT 隧道日志(启用
logformat自定义字段,如 %>a 客户端IP、%>s 响应字节数、%- 提供
cache.log记录连接生命周期,结合access.log可估算隧道流量(需配合 netstat 或 conntrack 补充连接时长);- 社区有成熟脚本(如 squid-logs-analyzer)直接输出按 IP 的流量报表。
- 提供











