总体思路与指标设计
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",'
'"http_host":"$host","url":"$uri","referer":"$http_referer","status":"$status"}';
access_log /var/log/nginx/access.log json;
以上做法便于后续用脚本、日志导出器或流式计算做指标统计与告警。快速落地方案 Shell脚本分钟级统计与告警
#!/usr/bin/env bash
set -euo pipefail
LOG=/var/log/nginx/access.log
NOW=$(date +%H:%M:%S)
START=$(date -d '1 minute ago' +%H:%M:%S)
# 1) 按时间窗口筛选、统计Top IP;2) 阈值判断与告警
tac "$LOG" | awk -v st="$START" -v et="$NOW" '
{
# 假设时间字段在第4列,形如 [24/Nov/2025:10:20:10 +0800]
t = substr($4, 2, 8) # 10:20:10
if (t >= st && t <= et) print $1
}' \
| sort | uniq -c | sort -nr \
| tee /tmp/ip_top10.txt \
| while read cnt ip; do
if (( cnt > 300 )); then
# 发送告警(示例调用 Python 邮件脚本)
/usr/bin/python /opt/send_mail.py "$ip" "$cnt"
fi
done
要点:
自动封禁与防护策略
#!/usr/bin/env bash
LOG=/var/log/nginx/access.log
TIME_WIN=$(date --date='1 minute ago' "+%d/%b/%Y:%H:%M") # 与日志时间格式匹配
THRESHOLD=200
WHITELIST=("127.0.0.1" "192.168.0.0/24")
is_whitelisted() {
local ip=$1
for w in "${WHITELIST[@]}"; do
if [[ $w == *"/"* ]]; then
ipcalc -nb "$w" "$ip" 2>/dev/null | grep -q "YES" && return 0
elif [[ $ip == "$w" ]]; then
return 0
fi
done
return 1
}
grep "$TIME_WIN" "$LOG" | awk '{print $1}' | sort | uniq -c | sort -nr | while read cnt ip; do
if (( cnt > THRESHOLD )) && ! is_whitelisted "$ip"; then
if ! iptables -C INPUT -s "$ip" -j DROP 2>/dev/null; then
echo "$(date) BAN $ip ($cnt req/min)" >> /var/log/nginx/ban.log
iptables -A INPUT -s "$ip" -j DROP
# 可选:定时解封(示例1小时后)
(sleep 3600; iptables -D INPUT -s "$ip" -j DROP) &
fi
fi
done
规模化与可视化方案
进阶 基于时间序列的异常检测