nginx屏蔽某一时间段访问量过大的IP

#!/bin/bash
# 功能:强制英文环境生成月份,确保与日志格式一致
# 版本:v3.0(最终解决版)

# 1. 核心配置
LOG_DIR="/www/wwwlogs/"
LOG_PATTERN="*.log"
DENY_FILE="/data/wwwroot/deny_ip.conf"
SPIDER_UA="Baidu|Google|Sogou|Bing|360|Youdao|Shenma|Yisou|Bytespider"
THRESHOLD=1500
WEBHOOK="填写你的webhook_url"
NOTIFY_THRESHOLD=5
NO_NOTIFY_START=0
NO_NOTIFY_END=7

# 2. 确保目录存在
# mkdir -p "$(dirname "$DENY_FILE")" || { echo "错误:无法创建目录 $(dirname "$DENY_FILE")"; exit 1; }

# 3. 获取服务器IP
get_server_ip() {
    public_ip=$(curl -s --max-time 5 http://icanhazip.com || curl -s --max-time 5 http://ifconfig.me)
    if [ -n "$public_ip" ] && [[ "$public_ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        echo "$public_ip"
        return
    fi
    local_ip=$(hostname -I | awk '{for(i=1;i<=NF;i++) if($i !~ /^127\./) print $i; exit}')
    [ -n "$local_ip" ] && echo "$local_ip" || echo "未知IP"
}
SERVER_IP=$(get_server_ip)

# 4. 关键修复:强制使用英文环境生成月份(Sep而非9月)
# 解决系统本地化导致的月份格式不匹配问题
export LC_TIME=en_US.UTF-8
current_time=$(date +"%d/%b/%Y:%H:")
ten_min_ago=$(date -d "10 minutes ago" +"%d/%b/%Y:%H:")

# 正则转义:四个反斜杠确保正确匹配[
if [ "$current_time" != "$ten_min_ago" ]; then
    time_pattern="\\\\[($current_time|$ten_min_ago)"
else
    time_pattern="\\\\[$current_time"
fi

echo "当前时间正则(英文月份):$time_pattern" >&2

# 5. 清空旧规则
[ -f "$DENY_FILE" ] && sed -i '/^deny/d' "$DENY_FILE" || touch "$DENY_FILE"

# 6. 处理日志文件(增加调试输出)
find "$LOG_DIR" -maxdepth 1 -type f -name "$LOG_PATTERN" | while read -r log_file; do
    [ ! -f "$log_file" ] || [ ! -r "$log_file" ] && { echo "跳过不可读文件:$log_file"; continue; }
    
    echo "正在处理日志:$log_file" >&2
    # 临时输出匹配到的日志行,确认时间匹配是否生效
    grep -E "$(echo "$time_pattern" | sed 's/\\\\/\\/g')" "$log_file" | head -n 3 >&2
    
    # 提取符合条件的IP
    grep -E "$(echo "$time_pattern" | sed 's/\\\\/\\/g')" "$log_file" | awk -v s="$SPIDER_UA" \
        '$9 == 200 && $12 !~ s {print $1}'
done | sort | uniq -c | sort -nr \
| awk -v t="$THRESHOLD" '$1 >= t {print "deny " $2 "; # 次数:" $1}' >> "$DENY_FILE"

# 7. 重载Nginx
if command -v nginx &> /dev/null; then
    nginx -s reload 2>/dev/null && echo "Nginx配置已重载" >&2 || echo "Nginx重载失败" >&2
else
    echo "未找到nginx命令" >&2
fi

# 8. 统计结果
total=$(grep -c '^deny' "$DENY_FILE" 2>/dev/null)
echo "处理完成,共屏蔽 $total 个IP(服务器:$SERVER_IP)" >&2

# 9. 通知逻辑(保持不变)
if [ $total -gt $NOTIFY_THRESHOLD ]; then
    current_hour=$(date +%H)
    if ! ( [ $current_hour -ge $NO_NOTIFY_START ] && [ $current_hour -lt $NO_NOTIFY_END ] ); then
        blocked_ips=$(tail -n 10 "$DENY_FILE" | awk '{print $2}' | tr '\n' ', ' | sed 's/, $//')
        content="服务器IP屏蔽警报:\n服务器IP:$SERVER_IP\n时间:$(date "+%Y-%m-%d %H:%M:%S")\n屏蔽总数:$total 个IP\n部分IP:$blocked_ips\n阈值:$THRESHOLD 次/10分钟"
        
        if command -v curl &> /dev/null; then
            curl -s -H "Content-Type: application/json" -X POST "$WEBHOOK" -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$content\"}}" > /dev/null
            [ $? -eq 0 ] && echo "通知已发送" >&2 || echo "通知发送失败" >&2
        else
            echo "未安装curl" >&2
        fi
    else
        echo "当前在不通知时段" >&2
    fi
fi

默认分类 2025-09-12 12:56:20 通过 网页 浏览(132)

共有0条评论!

发表评论

更换一道题!
放大的图片