核心是盯住“4xx 占比突增”而非总数;可用 tail+awk 实时计算占比,goaccess 提供 json 接口告警,结合行为识别过滤扫描/爆破等干扰,elk 支持多维归因与自动抑制。

核心是盯住“4xx 占比突增”,而不是单纯统计 4xx 总数。一次爬虫扫描可能产生几千个 404,但占比稳定就未必是风险;而某分钟内 4xx 从 0.2% 飙到 8%,往往意味着前端资源加载崩了、API 路由配错、或灰度发布出问题。
用 tail + awk 实时滚动计算最近 N 条中的占比
适合开发或运维快速上手,不依赖额外服务:
- 确认 $status 在日志中的字段位置(比如
head -1 /var/log/nginx/access.log | awk '{print NF; print $0}'),常见是第 9 列 - 执行命令,每 5 秒输出一次最近 1000 条中 4xx 的百分比:
tail -n 1000 -f /var/log/nginx/access.log | \ awk '{ total++; if($9>=400 && $9 0 ? (fourxx / total * 100) : 0; print strftime("%H:%M:%S"), "4xx%", sprintf("%.2f", ratio), "("fourxx"/"total")"; total = fourxx = 0 } }' - 设置阈值:比如连续两次超过 3%,就手动检查或触发脚本发通知
用 goaccess 做带告警能力的终端监控
它能实时解析日志并暴露 JSON 接口,方便做阈值判断:
- 启动实时监听:
goaccess /var/log/nginx/access.log -o /dev/stdout --log-format=COMBINED --real-time-html --ws-url=ws://localhost:7890 & - 另起一个定时任务(如 cron 每 30 秒执行一次),调用
curl -s "http://localhost:7890/api?format=json",提取http_status中 4xx 类别总和与总请求数 - 当 4xx 占比连续 3 次 > 2%(业务敏感可设为 0.5%),执行:
echo "$(date) 4xx 突增!" | mail -s "Nginx 安全预警" admin@example.com
结合访问行为识别恶意模式,过滤“假爆发”
不是所有 4xx 都要告警,得排除干扰项:
- 大量 404 出现在
/wp-admin/、/.git/config、/phpmyadmin/—— 很可能是扫描,需告警 - 同一 IP 在 60 秒内发出 ≥15 个 400 或 403 请求 —— 可能是参数爆破或 UA 绕过,建议联动 fail2ban
- 429 Too Many Requests 集中出现 —— 属限流正常响应,不应计入异常爆发,可在 awk/grep 中显式排除:
grep ' 4[^29][0-9] ' - 健康检查请求(如
/healthz)返回 404 是配置问题,但不算安全事件,建议在 log_format 中加标记字段,分析时过滤
进阶:用 ELK 做多维归因与自动抑制
适合中大型站点,支持按时间、IP 段、UA 分组、URI 路径聚类:
- Logstash 过滤时,把
$status提取为字段,并新增is_4xx: true标签 - Kibana 中建视图,按 1 分钟粒度统计
4xx_count / total_count,叠加移动平均线(MA5)看趋势拐点 - 设置告警规则:当“过去 3 分钟 4xx 占比均值 > 基线(昨日同段均值 × 2.5)且绝对值 > 1.5%”时触发
- 自动抑制逻辑:若该时段同时出现大量
upstream_status: 502或request_time > 10s,则降级为“服务端问题”告警,而非安全类











