最轻量准确的协议监控方式是用$scheme变量区分HTTP/HTTPS,在access log中按协议分组统计状态码;需在http块定义log_format scheme_log并server块启用,配合awk等命令可快速分析协议级异常分布。

直接用 $scheme 变量区分 HTTP 和 HTTPS 请求,在 access log 中按协议分组统计状态码,是最轻量、最准确的监控方式——它不依赖客户端头、不增加代理开销,且 nginx 原生支持。
在日志格式中嵌入 $scheme 变量
定义一个带协议标识的日志格式,让每条日志天然携带通道信息:
- 在
http块中添加自定义日志格式:log_format scheme_log '$scheme $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; - 在 server 块中启用该格式:
access_log /var/log/nginx/access_scheme.log scheme_log; - 重启 nginx 后,日志首字段即为
http或https,后续字段与标准日志一致,便于 grep、awk 或日志分析工具直接切分
按协议 + 状态码聚合统计
用简单命令快速发现异常分布,例如排查 HTTPS 下 502 是否集中出现:
- 统计 HTTPS 下各状态码数量:
awk '$1 == "https" {print $6}' /var/log/nginx/access_scheme.log | sort | uniq -c | sort -nr - 对比 HTTP/HTTPS 的 4xx 比率:
awk '$1 == "http" && $6 ~ /^4/ {h++} $1 == "https" && $6 ~ /^4/ {s++} END {print "http_4xx:", h, "https_4xx:", s}' /var/log/nginx/access_scheme.log - 导出最近 1 小时内协议与状态码组合频次(需日志含时间戳):
awk -v cutoff="$(date -d '1 hour ago' '+%d/%b/%Y:%H:%M:%S')" '$3 > "["cutoff {print $1, $6}' /var/log/nginx/access_scheme.log | sort | uniq -c
结合 map 指令做协议感知的条件记录
若只需关注特定状态码(如只记录 HTTPS 下的 500),可用 map 预过滤,降低日志体积:
- 定义映射变量:
map $scheme:$status $log_level {<br> default 0;<br> https:500 1;<br> http:500 0;<br>} - 配合 if(注意:仅限 access_log,不可用于 rewrite):
access_log /var/log/nginx/https_500.log scheme_log if=$log_level; - 这样只有 HTTPS 返回 500 的请求才写入该文件,便于专项告警或根因分析
避免常见误判陷阱
$scheme 是 nginx 解析连接层协议所得,但实际使用中需注意边界情况:
- 反向代理后端时,若前端 LB 终止 HTTPS 并以 HTTP 转发给 nginx,则
$scheme恒为http——此时应配合$http_x_forwarded_proto或自定义 header,并在 proxy_pass 中显式设置:proxy_set_header X-Forwarded-Proto $scheme; - HTTP/2 over TLS 不影响
$scheme值,仍为https;纯 HTTP/2 明文(h2c)极少部署,nginx 默认不启用,无需额外处理 - 不要用
$server_port替代$scheme判断通道,因为 80 端口可能被配置为 HTTPS(如调试场景),而 443 也可能跑 HTTP(非标配置),协议语义比端口更可靠


















