监控 Nginx 日志发现异常流量的实用方案
一 监控目标与关键指标
二 快速落地方案
三 参考配置与脚本
log_format json '{"@timestamp":"$time_iso8601",'
'"clientip":"$remote_addr",'
'"request":"$request",'
'"http_user_agent":"$http_user_agent",'
'"size":"$body_bytes_sent",'
'"responsetime":"$request_time",'
'"upstreamtime":"$upstream_response_time",'
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"url":"$uri",'
'"domain":"$host",'
'"referer":"$http_referer",'
'"status":"$status"}';
access_log /var/log/nginx/access.log json;
#!/usr/bin/env bash
set -euo pipefail
NGINX_LOG="/var/log/nginx/access.log"
THRESHOLD=500
TMP_IP="/tmp/abnormal_ips.txt"
DENY_IP="/tmp/denyip.txt"
# 1 分钟窗口(按日志时间字段匹配)
ts=$(date -d "1 minute ago" +"%Y-%m-%dT%H:%M")
awk -F'"' -v ts="$ts" '$2 ~ ts {print $8}' "$NGINX_LOG" \
| sort | uniq -c | sort -nr > "$TMP_IP"
while read cnt ip; do
if [ "$cnt" -gt "$THRESHOLD" ]; then
if ! grep -qFx "$ip" "$DENY_IP"; then
iptables -I INPUT -s "$ip" -j DROP
echo "$ip" >> "$DENY_IP"
echo "$(date) Banned $ip ($cnt req/min)" >> /var/log/nginx/ban.log
fi
fi
done < "$TMP_IP"
四 大规模与自动化架构
五 异常模式与处置建议