跳到主要内容

6 篇博文 含有标签「Nginx」

查看所有标签

Nginx日志轮转配置指南

· 阅读需 3 分钟

Nginx日志轮转配置指南

注:本文档基于nginx日志目录为 /etc/nginx/logs/ 的环境配置。 如果您的nginx日志在其他目录(如默认的/var/log/nginx/),请相应调整路径。

1. 检查系统环境

首先确认系统已安装logrotate:

# 检查是否安装logrotate
which logrotate

# 如果未安装,使用以下命令安装
# CentOS/RHEL系统
sudo yum install logrotate

# Ubuntu/Debian系统
sudo apt-get install logrotate

2. 创建Nginx日志轮转配置

创建nginx专用的logrotate配置文件:

sudo vim /etc/logrotate.d/nginx

配置文件内容:

/etc/nginx/logs/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

3. 配置参数说明

  • daily: 每天轮转一次
  • missingok: 如果日志文件丢失,不报错
  • rotate 52: 保留52个轮转文件(约1年)
  • compress: 压缩旧的日志文件
  • delaycompress: 延迟压缩,保留最近的一个文件不压缩
  • notifempty: 如果日志文件为空,不进行轮转
  • create 0640 nginx nginx: 创建新日志文件的权限和所有者
  • sharedscripts: 所有日志文件轮转后只执行一次脚本
  • postrotate: 轮转后执行的脚本,发送USR1信号给nginx重新打开日志文件

4. 测试配置

# 测试配置文件语法
sudo logrotate -d /etc/logrotate.d/nginx

# 强制执行轮转(用于测试)
sudo logrotate -f /etc/logrotate.d/nginx

5. 验证轮转效果

# 查看日志文件
ls -la /etc/nginx/logs/

# 查看轮转后的文件
ls -la /etc/nginx/logs/*.gz

6. 高级配置示例

按大小轮转

/etc/nginx/logs/*.log {
size 100M
missingok
rotate 10
compress
delaycompress
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

按小时轮转

/etc/nginx/logs/*.log {
hourly
missingok
rotate 168
compress
delaycompress
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}

7. 排查问题

检查logrotate服务状态

# 检查logrotate服务状态
sudo systemctl status logrotate

# 查看logrotate日志
sudo journalctl -u logrotate

检查权限问题

# 确保nginx用户有正确的权限
sudo chown -R nginx:nginx /etc/nginx/logs/
sudo chmod 755 /etc/nginx/logs/

手动测试

# 手动执行logrotate
sudo /usr/sbin/logrotate -v /etc/logrotate.d/nginx

8. 监控脚本

创建一个监控脚本来检查日志轮转状态:

#!/bin/bash
# /usr/local/bin/check_log_rotation.sh

LOG_DIR="/etc/nginx/logs"
MAX_SIZE=100M
ALERT_EMAIL="admin@example.com"

# 检查日志文件大小
for log_file in $LOG_DIR/*.log; do
if [ -f "$log_file" ]; then
size=$(du -h "$log_file" | cut -f1)
if [[ $size > $MAX_SIZE ]]; then
echo "Warning: $log_file size is $size" | mail -s "Log Size Alert" $ALERT_EMAIL
fi
fi
done

# 检查是否有过期的日志文件
find $LOG_DIR -name "*.gz" -mtime +30 -exec rm {} \;

9. 性能优化建议

  1. 合理设置轮转频率:根据日志量调整轮转频率
  2. 使用压缩:节省磁盘空间
  3. 定期清理:删除过期的日志文件
  4. 监控磁盘空间:避免日志文件占满磁盘

10. 注意事项

  • 确保nginx用户有足够权限访问日志目录
  • 在生产环境测试前,先在测试环境验证配置
  • 定期检查轮转是否正常工作
  • 考虑使用日志管理工具如ELK Stack进行集中管理

nginx + lua 实现 waf

· 阅读需 14 分钟

Lua脚本基础语法

lua是一个简介、轻量、可扩展的脚本语言

nginx + lua的优势:

- 充分的结合 Nginx 的并发处理epoll优势和Lua的轻量实现简单的功能且高并发的场景
//epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
- 场景:
- 统计IP
- 统计用户信息
- 安全WAF

安装lua

~]# yum install lua -y

lua的运行

~]# lua
> print("hello world")

~]# which lua
/usr/bin/lua

~]# vim test.lua
#!/usr/bin/lua
print("hello world")
print("test:",a)
~]# lua ./test.lua

Lua的注释

行注释:
--print("hi,boy")

多行注释:
--[[
xxxxxxx
]]

Lua的基础语法

变量定义
a = 123
~]# vim test.lua
#!/usr/bin/lua
print("test:",a) #不加$

~]# lua ./test.lua

while循环

~]# cat while.lua
#!/usr/bin/lua
sum =0
num =1
while num <= 100 do
sum = sum + num
num = num + 1
end
print("sum=",sum)
//执行结果
~]# lua while.lua
sum = 5050

for循环

~]# cat for.lua
#!/usr/bin/lua
sum = 0
for i = 1,100 do
sum = sum + 1
end
print("sum=",sum)
//执行结果
~]# lua for.lua
sum = 100

if 判断

~]# cat if.lua
#!/usr/bin/lua
if age == 40 and sex == "Man" then
print("男人大于40")
elseif age > 60 and sex ~= "Women" then
print("非女人而且大于60")
else
local age = io.read()
print("Your age is"..age)
end

// ~= 是不等于
// 字符串的拼接操作符 ".."
// io库的分别从stdin和stdout读写,read和write函数

Nginx加载Lua环境

默认情况下Nginx不支持Lua模块,需要安装luaJIT解释器,并且需要重新便宜Nginx,可选择使用openrestry

LuaJIT
Ngx_devel_kit 和 lua-nginx-module

环境准备

~]# yum -y install gcc gcc-c++ make pcre-devel zlib-devel openssl-devel

下载最新工具包

下载最新的luajit 和 ngx_devel_kit 以及 lua-nginx-module:

~]# mkdir -p /soft/src && cd /soft/src
~]# wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
~]# wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
~]# wget https://github.com/openresty/lua-nginx-module/archive/v0.9.16.tar.gz ##视频中后又修改为v0.10.13.tar.gz

解压

解压 ngx_devel_kit 和 lua-nginx-module

//解压后为 ngx_devel_kit-0.2.19
~]# tar xf v0.2.19.tar.gz
//解压后为 lua-nginx-module-0.9.16
~]# tar xf v0.9.16.tar.gz

安装LuaJIT

安装LuaJIT ,Luajit是Lua即时编译器

~]# tar zxvf LuaJIT-2.0.3.tar.gz
~]# cd LuaJIT-2.0.3
~]# make && make install

安装Nginx并加载模块

~]# cd /soft/src
~]# wget http://nginx.org/download/nginx-1.12.2.tar.gz
~]# tar xf nginx-1.12.2.tar.gz
~]# cd nginx-1.12.2

#### 编译参数:
./configure --prefix=/soft/nginx --with-http_ssl_module --with-http_stub_status_module --with-file-aio --with-http_dav_module --add-module=../ngx_devel_kit-0.2.19/ --add-module=../lua-nginx-module-0.9.16/
//lua-nginx-module-xxxx 这个版本如果换了就要重新再编译一次

make <-j2> && make install

//如果不建立软链接,会出现share object 错误
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

// 测试 openresty 安装
vim nginx.conf
location /test {
default_type text/html;
content_by_lua_block {
ngx.say("Hello world")
}
}

/soft/nginx/sbin/nginx -t //相当于nginx -t
/soft/nginx/sbin/nginx //启动nginx

使用浏览器访问:
例如:39.112.53.22/test

#//4.加载lua库,加入ld.so.conf文件
#echo "/usr/local/LuaJIT/lib" >> /etc/ld.so.conf
#ldconfig

也可以直接部署春哥的开源项目 OpenResty

安装依赖包

~]# yum install -y readline-devel pcre-devel openssl-devel
~]# cd /soft/src

下载编译 openresty

wget https://openresty.org/download/ngx_openresty-1.9.3.2.tar.gz
tar zxf ngx_openresty-1.9.3.2.tar.gz
cd ngx_openresty-1.9.3.2
./configure --prefix=/soft/openresty-1.9.3.2 \
--with-luajit --with-http_stub_status_module \
--with-pcre --with-pcre-jit

gmake && gmake install
ln -s /soft/openresty-1.9.3.2/ /soft/openresty

启动 openresty

echo "PATH=/soft/openresty/nginx/sbin:$PATH" >> ~/.bashrc
source ~/.bashrc

nginx
ps aux | grep nginx

测试openresty安装

vim /soft/openresty/nginx/conf/nginx.conf
location /test {
default_type text/html;
content_by_lua_block {
ngx.say("Hello world")
}
}

ps : 实际上openresty就是嵌套了nginx实现的

Nginx调用Lua指令

  • Nginx 调用 Lua 模块指令,Nginx的可插拔模块加载执行,共11个处理阶段
语法
set_by_lua
set_by_lua_file
设置Nginx变量,可以实现负载的赋值逻辑
access_by_lua
access_by_lua_file
请求访问阶段处理,用于访问控制
content_by_lua
content_by_lua_file
内容处理器,接受请求处理并输出响应
  • Nginx 调用 Lua API
变量
ngx.varnginx变量
ngx.req.get_headers获取请求头
ngx.req.get_url_args获取url请求参数
ngx.redirect重定向
ngx.print输出响应内容体
ngx.say输出响应内容体,最后输出一个换行符
ngx.header输出响应头

Nginx + Lua 实现代码灰度发布

使用Nginx结合lua 实现代码灰度发布,灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

按照一定的关系区别,分不分的代码进行上线,使代码的发布能平滑过渡上线

  1. 用户的信息cookie等信息区别
  2. 根据用户的ip地址,颗粒度更广
nginx+lua  通过Memcached校验IP。存在IP则成功-->访问成功即访问java_test,不成功即访问java_prod

执行过程L:

  • 1.用户请求到达前端代理Nginx,内嵌的lua模块会解析Nginx配置文件中Lua脚本
  • 2.Lua脚本会获取客户端IP地址,查看Memcached缓存中是否存在该键值
  • 3.如果存在则执行@java_test,否则执行@java_prod
  • 4.如果使@java_test,那么location会将请求转发至新版代码的集群组
  • 5.如果使@java_prod,那么location会将请求转发至原始版代码集群组
  • 6.最后整个过程执行后结束

实践环境准备:

系统服务地址
centos7Nginx+Lua+Memcached192.168.29.19
centos7Tomcat集群8080_prod192.168.29.20
centos7Tomcat集群9090_test192.168.29.21

1.安装两台服务器 Tomcat,分别启动8080 和9090 端口

## 两台服务器都需要配置java环境 //yum install -y java
20 ~]# cd /soft
20 ~]# ./tomcat-8080/bin/startup.sh

## 可以在这个环境中改一下那个端口,scp到另一个服务器中,然后直接启动

21 ~]# sh /soft/tomcat-9090/bin/startup.sh
21 ~]# netstat -lntp //端口已经起来了
21 ~]# cd /soft/tomcat-9090/webapps/ROOT
21 ~]# ll //有一个test.jsp

##
20 ~]# cd /soft/tomcat-9090/webapps/ROOT
20 ~]# rm -rf ./*
20 ~]# vim test.jsp
## 里面的内容从21的服务器上的test.jsp里复制过来,记得改一下`<TITLE>`内端口号: JSP 8080
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
`<HTML>`
`<HEAD>`
`<TITLE>`JSP 9090</TITLE>
</HEAD>
`<BODY>`
<h1> Jsp 9090-test </h1>
<%
Random rand = new Random();
out.println("<h1>Random number:</h1>");
out.println(rand.nextInt(99)+100);
%>
% </BODY>
% </HTML>

#######################################
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
`<HTML>`
`<HEAD>`
`<TITLE>`JSP 8080-prod</TITLE>
</HEAD>
`<BODY>`
<h1> Jsp 8080-prod </h1>
<%
Random rand = new Random();
out.println("<h1>Random number:</h1>");
out.println(rand.nextInt(99)+100);
%>
% </BODY>
% </HTML>

2.配置Memcached并让其支持Lua调用

//安装memcached服务
19 ~]# yum install memcached -y

//配置memcached支持lua
19 ~]# cd /soft/src
19 ~]# wget https://github.com/agentzh/lua-resty-memcached/archive/v0.11.tar.gz
19 ~]# tar xf v0.11.tar.gz
19 ~]# cp -r /soft/src/lua-resty-memcached-0.11/lib/resty/memcached.lua /soft/nginx/conf/lua
19 ~]# ll /soft/nginx/conf/lua ## 有一个memcached.lua这个文件


//启动memcached
19 ~]# systemctl start memcached
19 ~]# systemctl enable memcached

3.配置负载均衡调度

# 必须在http层 加一个include 包含conf。在conf中加入下面内容并且,删掉server 和 error的内容(不然会报错)
# 在conf目录里加上 lua.conf:
lua_package_path "/soft/nginx/conf/lua/memcached.lua";

upstream java_prod {
server ip:8080;
}

upstream java_test {
server ip:9090;
}

server {
listen 80;
#server_name 39.22.145.18;

location /test { #视频写的hello
default_type 'text/plain';
content_by_lua ngx.say("hello , lua scripts");
}

location /myip {
default_type 'test/plain';
content_by_lua '
clientIP = ngx.req.get_headers()["x_forwarded_for"]
ngx.say("Forwarded_IP:",clientIP)
if clientIP == nil then #视频中写的是nli
clientIP = ngx.var.remote_addr
ngx.say("Remote_IP:",clientIP)
end
';
}

location / {
default_type 'text/plain';
content_by_lua_file /soft/nginx/conf/lua/dep.lua; #这个dep.lua很重要
}
location @java_prod {
proxy_pass http://java_prod;
include proxy_params; #访问浏览器400需要加上这条信息(因为代理Tomcat必须加上这个,这个文件有一些设置的一些头部信息)
}
location @java_test {
proxy_pass http://java_test;
include proxy_params; #访问浏览器400需要加上这条信息
}
}

4.编写Nginx调用灰度发布Lua脚本

~]# cat /soft/nginx/conf/lua/dep.lua
-- 获取x-real-ip
clientIP = ngx.req.get_headers()["X-Real-IP"]

-- 如果IP为空 , 取x-forwarded-for
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end

-- 如果IP为空-取remote_addr
if clientIP == nil then
clientIP = ngx.var.remote_addr
end

-- 定义本地,加载memcached
local memcached = require "resty.memcached"
-- 实例化对象
local memc, err = memcached:new()
-- 判断连接是否存在错误
if not memc then
ngx.say("failed to instantiate memc: ", err)
return
end
-- 建立memcache连接
local ok, err = memc:connect("127.0.0.1",11211)
-- 无法连接往前端抛出错误信息
if not ok then
ngx.say("failed to connect: ",err)
return
end
----------------------
--获取对象中的ip-存在值赋给res
local res, flags,err = memc:get(clientIP)
--
-- ngx.say("value key: ",res.clientIP)
if err then
ngx.say("failed to get clientIP ", err)
return
end
-- 如果值为1 则调用local-@java_rest
if res == "1" then
ngx.exec("@java_test")
retuen
end
-- 否则调用 local-@java_prod
ngx.exec("@java_prod")
return
  • 验证
~]# /soft/nginx/sbin/nginx -t
~]# /soft/nginx/sbin/nginx -s reload

# 使用浏览器访问nginx 的 ip/(加/)
# 如果有问题 tail -f /soft/nginx/logs/error.log 查看报错信息

#########################################

访问浏览器nginx ip/myip<路径名(nginx上写的)>
想要访问新的代码 (tomcat 9090),则在nginx主机上修改一下memcached:
telnet 127.0.0.1 11211
set 211.161.160.201 0 0 1
1
#此页面变成了9090;如果delete 此ip
#会在此换成8080的页面
# 当然生产环境肯定不会是我们这样修改,会在memcache的后台管理界面直接怼ip就可以

Nginx+Lua实现WAF

  • 1.常见的恶意行为
    • 爬虫行为和恶意抓取,资源盗取
    • 防护手段
      • 1.基础防盗链功能不让恶意用户能够轻易的爬取网站对外数据
      • access_module -> 对后台,部分用户服务的数据提供IP防护

防护代码demo:

set ip = 0
if ($http_x_forward_for ^~ 211.161.160.201) {
set ip = 1
}
localtion ^~ /admin {
if ($ip ~ 0){
return 403
}
}
  • 常见的攻击手段
    • 后台密码撞库,通过猜测密码字典不断对后台系统登录性尝试,获取后台登录密码
    • 防护手段
      • 1.后台登录密码复杂性
      • 2.使用access_module 对后台提供IP防控
      • 3.预警机制
    • 文件上传漏洞,利用上传接口将恶意代码植入到服务器中,再通过url去访问执行代码
    • 执行方式xxx.com/1.jpg/1.php

解决方法:

location ^~ /upload {
root /soft/code/upload;
if ($request_filename ~* (.*)\.php){
return 403;
}
}
  • 3.常见的攻击手段
    • 利用未过滤/未审核的用户输入进行SQL注入的攻击方法,让应用运行本不应该运行的SQL代码
    • 防护手段
      • 1.php配置开启安全相关限制
      • 2.开发人员对sql提交进行审核,屏蔽常见的注入手段
      • 3.Nginx+Lua构建WAF应用层防火墙,防止SQL注入

编写WAF拦截sql注入

1.快速安装lnmp架构

# 在有waf的服务器上,yum快速安装下面软件及插件
~]# yum install mariadb mariadb-server php php-fpm php-mysql -y

2.配置Nginx + php

conf.d]# cat phpserver.conf
server {
server_name 47.104.250.169;
root /soft/code;
index index.html index.php;

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /soft/code/$fastcgi_script_name;
include fastcgi_params;
}
}

~]# systemctl start php-fpm
~]# systemctl start mariadb

3.配置MYSQL

# 创建数据库
MariaDB [(node)]> create database info;
MariaDB [(node)]> usr info;
MariaDB [info]> create table user(id int(11),username varchar(64),password varchar(64),email varchar(64));
MariaDB [info]> desc user;
xxxxxx
xxxxxx

# 插入数据
MariaDB [info]> insert into user (id,username,password,email) values(1,'xiaoyuan',('123'),'xiaoyuan@123456.com');
MariaDB [info]> select * from info.user;
xxxxxx
xxxxxx
exit

4.配置php代码

//配置html文件:

conf.d]# cat /soft/code/login.html
<html>
<head>
<title> Sql注入演示场景 </title>
<meta http-equiv="content-type"content="text/html;charset=utf-8">
</ead>
<body>
<form action='sql.php' method="post">
<table>
<tr>
<td> 用户: </td>
<td><input type="text" name="username"></td>
</tr>

<tr>
<td> 密码: </td>
<td><input type="test" name="password"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</form>
</body>
</html>

//被html调用的sql.php文件
conf.d]# cat /soft/code/sql.php
<?php
$conn = mysql_connect("localhost",'root','') or die("数据库连接失败");
mysql_select_db("info",$conn) or die("您选择的数据库不存在");
$name=$_POST['username'];
$pwd=$_POST['password'];
$sql="select * from user where username='$name' and password='$pwd'";
echo $sql."<br />";
$query=mysql_query($sql);
$arr=mysql_fetch_array($query);
if($arr){
echo "login success!<br />";
echo $arr[1];
echo $arr[3]."<br /><br />";
}else{
echo "login failed!";
}
\?>
  • 测试:
浏览器访问47.104.250.169/login.html
显示404打不开,先把lua.conf 改个名; mv lua.conf lua.conf.bak 继续访问

# 登录页面显示; (上面插入的数据用户账号密码为 xiaoyuan 123,此账号密码为正确的)
# 然后再用户框输入 ' or 1=1#' 直接提交;显示登陆成功

5.使用lua解决此类安全问题

nginx+lua ->拦截cookie类型工具;拦截异常post请求;拦截CC攻击;拦截URL;拦截arg -> java\PHP\Python

6.部署Waf相关防护代码

相关项目:https://github.com/loveshell/ngx_lua_waf

~]# cd /soft/src
~]# git clone https://github.com/loveshell/ngx_lua_waf.git

//把ngx_lua_waf 复制到nginx的目录下,解压命名为waf
~]# cp -r ngx_lua_waf /soft/nginx/conf/waf

//在conf.d的 phpserver.conf 最上面添加
lua_package_path "/soft/nginx/conf/waf/\?.lua"; #视频中为/etc/waf/\?.lua
lua_shared_dict limit 10m;
init_by_lua_file /soft/nginx/conf/waf/init.lua; #/etc/waf/init.lua
access_by_lua_file /soft/nginx/conf/waf/waf.lua; #/etc/waf/waf.lua

~]# /soft/nginx/sbin/nginx -t
~]# /soft/nginx/sbin/nginx -s reload

//配置config.lua里的waf规则目录(一般在waf/conf/目录下)
RulePath = "/soft/nginx/conf/waf/wafconf/"

# 绝对路径如有变动,需对应修改,然后重启nginx即可
  • 测试:
浏览器访问47.104.250.169/login.html

# 登录页面显示; (上面插入的数据用户账号密码为 xiaoyuan 123,此账号密码为正确的)
# 输入正确的和错误的账号密码尝试一下。
# 然后再用户框输入 ' or 1=1#' 直接提交;显示登陆成功。所以说需要配置wafconf/目录下的定义规则:

修改post文件(正则匹配):
首行添加:
\sor\s+

~]# /soft/nginx/sbin/nginx -t
~]# /soft/nginx/sbin/nginx -s reload

再次测试在用户框输入 ' or 1=1#' 直接提交; 显示被拦截

编写WAF拦截CC攻击

~]# cd /soft/nginx/conf/waf
~]# vim config.lua
CCDeny="on"
CCrate="600/60" #每分钟只能有600次请求,如果超过就会被拒绝掉

~]# /soft/nginx/sbin/nginx -t
~]# /soft/nginx/sbin/nginx -s reload

本地压测 ab -n 2000 -c 200 http://47.104.250.169/login.html //请求2000次,并发200
再次访问浏览器http://47.104.250.169/login.html ;显示503

根据 Nginx 日志自动封禁 IP

· 阅读需 4 分钟

根据nginx日志自动封禁 IP

遇到的问题问题:

攻击者会每秒 POST 请求 /a/b.php 数次,拉黑后过一段时间会切到其他 IP 继续攻击,如果开始攻击大概 100 行内就可以找到这种日志,需要检测这种信息,几分钟执行一次并去拉黑

Tips:如果是大规模 ddos 或 cc 攻击的话,这是不顶用的,还是需要上 高防IP 或者 CDN 或者 高防流量包 以及 添加防火墙进行流量清洗 等。

思路一: iptables

  • 编写脚本,按日期拆分access.log
  • 编写定时任务,每天0点拆分访问日志
  • 编写脚本,分析access.log访问日志,封禁当天访问次数超过200的ip
  • 编写定时任务,每10分钟执行一次封禁ip脚本

这样做的比较好的一点是,让小黑子连 403 也看不到,高效简单

日志拆分脚本

LOG_PATHPID 换成你自己的路径

# 每天0点执行日志按日期分隔脚本 0 0 * * * cd /www/Home/ && ./log_cut.sh
#!/bin/bash
#此脚本⽤于⾃动分割Nginx的⽇志,包括access.log
#每天00:00执⾏此脚本将前⼀天的access.log重命名为access-xxxx-xx-xx.log格式,并重新打开⽇志⽂件
#Nginx⽇志⽂件所在⽬录 todo 换成你自己的
LOG_PATH=/data/logs/nginx/

#获取昨天的⽇期
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)

#获取pid⽂件路径 todo 换成你自己的
PID=/var/run/nginx.pid

#分割⽇志
mv ${LOG_PATH}access.log ${LOG_PATH}access-${YESTERDAY}.log

#向Nginx主进程发送USR1信号,重新打开⽇志⽂件
kill -USR1 `cat ${PID}`

编写定时任务

crontab -e

# 每天0点执行日志按日期分隔脚本
0 0 * * * cd /www/Home/ && ./log_cut.sh

编写封禁ip脚本

# 每十分钟执行一次封禁ip脚本 */10 * * * * cd /www/Home/ && ./blackip.sh
#!/bin/bash
logdir=/data/logs/nginx/access.log #nginx访问日志文件路径
port=443
#循环遍历日志文件取出访问量大于100的ip(忽略自己本地ip)
for drop_ip in $(cat $logdir | grep -v '127.0.0.1' | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if ($1>100) print $2}'); do
# 避免重复添加
num=$(grep ${drop_ip} /tmp/nginx_deny.log | wc -l)
if [ $num -ge 1 ]; then
continue
fi

# shellcheck disable=SC2154
iptables -I INPUT -p tcp --dport ${port} -s ${drop_ip} -j DROP
echo ">>>>> $(date '+%Y-%m-%d %H%M%S') - 发现攻击源地址 -> ${drop_ip} " >>/tmp/nginx_deny.log #记录log
done

编写封禁ip定时任务

crontab -e 

# 每十分钟执行一次封禁ip脚本
*/10 * * * * cd /www/Home/ && ./blackip.sh

误封IP后 解封 IP

#清空屏蔽IP
iptables -t filter -D INPUT -s 1.2.3.4 -j DROP

#一键清空所有规则
iptables -F

思路二:nginx

配置nginx的黑名单,每次填加新的黑名单之后,但还要 重载/重启Nginx。 还有一点,会让小黑子看到 403 ,所以这不一定是最优解,大概思路如下:

定时查看 access.log 日志,将这些有问题的 IP 加入黑名单

编写 sh 脚本

#!/bin/bash
max=500 #我们设定的最大值,当访问量大于这个值得时候,封锁
confdir=/usr/local/data/nginx/conf/blockip.conf #nginx封锁配置文件路径
logdir=/usr/local/data/nginx/logs/access_huke88.log #nginx访问日志文件路径
#检测文件
test -e ${confdir} || touch ${confdir}
drop_ip=""
#循环遍历日志文件取出访问量大于500的ip
for drop_ip in $(cat $logdir | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if ($1>500) print $2}')
do
grep -q "${drop_Ip}" ${confdir} && eg=1 || eg=0;
if (( ${eg}==0 ));then
echo "deny ${drop_Ip};">>$confdir #把“deny IP;”语句写入封锁配置文件中
echo ">>>>> `date '+%Y-%m-%d %H%M%S'` - 发现攻击源地址 -> ${drop_Ip} " >> /usr/local/data/nginx/logs/nginx_deny.log #记录log
fi
done

systemctl reload nginx

定时执行

#!/bin/bash
sed -i 's/^/#&/g' /usr/local/nginx/conf/

blockip.conf #把nginx封锁配置文件中的内容注释掉

systemctl reload nginx #重置nginx服务,这样就做到了解锁IP