Nginx 通過 Lua + Redis 實現動態封禁 IP


一 、安裝 Openrestry

# 1.下載源碼包 wget https://openresty.org/download/openresty-1.11.2.2.tar.gz tar -xzvf openresty-1.11.2.2.tar.gz cd openresty-1.11.2.2 # 2.查看 nginx 編譯選項: $ nginx -V nginx version: nginx/1.10.3 ... (省略) ... # 3. 編譯安裝 ./configure --prefix=/usr/local/openresty --with-luajit --without-http_redis2_module --with-http_stub_status_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-openssl=/usr/local/src/openssl-1.0.2m make make install

二 、 配置 openrestry

# 復制原來的 `nginx` 配置 #openresty-nginx 路徑是: /usr/local/openresty/nginx #將原來的nginx 配置都復制到 /usr/local/openresty/nginx/conf cp /usr/local/nginx/conf/*.conf /usr/local/openresty/nginx/conf/ ## vhost 目錄 ssl 目錄 cp -r /usr/local/nginx/conf/conf.d /usr/local/openresty/nginx/conf 還要根據服務器實際情況,修改 nginx.conf 等配置文件中替換路徑為新的路徑

三、 修改環境變量

  1. 先停止原來的nginx
  2. 添加環境變: 
    PATH=/usr/local/openresty/nginx/sbin:$PATH 
    export PATH
     
    改了之后原來的nginx 就沒用了,這里我本來就是替換的,所以就這樣設置了。
  3. 執行 :source /etc/profile
  4. 運行 openresty $ nginx

注意:openresty 在支持http2的時候 響應頭header server會修改成nginx

# 驗證版本 root@iZm5eabkgmsfy2phj5pr1xZ:~$ nginx -V nginx version: openresty/1.11.2.2 built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) built with OpenSSL 1.0.2m 2 Nov 2017 TLS SNI support enabled configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 —add-(省略)

 

這里寫圖片描述

這里寫圖片描述

四、 使用 lua-redis 實現封禁ip高頻訪問

1. 查看 access.log 高訪問前5條數據

awk '{print $1}' access.log | sort|uniq -c | sort -nr | head -n 5 8 180.169.120.218 1 40.77.167.22 1 207.46.13.192 ...

2. 修改 nginx 配置 ,nginx.conf 或者 虛擬主機host 中,添加對 lua 腳本的支持

# 以我自己服務器為例,我的www.leon0204.com 的配置文件在 $ cd /usr/local/openresty/nginx/conf/conf.d/ && vim leon0204.conf # 添加 openrestry 引入lua腳本要用的地址 lua_package_path "/usr/local/openresty/lualib/resty/redis.lua;";#告訴openresty庫地址 #lua_package_cpath "/usr/local/openresty/lualib/?.so;;"; error_log /usr/local/openresty/nginx/logs/openresty.debug.log debug; # 所有 xxx/hello 的請求會被分發給lua 腳本處理 location /hello { default_type text/html; access_by_lua_file "/usr/local/openresty/nginx/lua/access_by_redis.lua"; }

 

3. lua 的基於訪問頻率的reids 實現自動化可控封禁腳本

# Lua local function close_redis(red) if not red then return end --釋放連接(連接池實現) local pool_max_idle_time = 10000 --毫秒 local pool_size = 100 --連接池大小 local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) if not ok then ngx_log(ngx_ERR, "set redis keepalive error : ", err) end end -- 連接redis local redis = require('resty.redis') local red = redis.new() red:set_timeout(1000) local ip = "127.0.0.1" ---修改變量 local port = "6379" ---修改變量 local ok, err = red:connect(ip,port) if not ok then return close_redis(red) end red:auth('passwd') --resp = redis_init:set('funet', '888888') --resp = redis_init:get('funet') local clientIP = ngx.req.get_headers()["X-Real-IP"] if clientIP == nil then clientIP = ngx.req.get_headers()["x_forwarded_for"] end if clientIP == nil then clientIP = ngx.var.remote_addr end --ngx.say(clientIP) --if clientIP == "101.231.137.70" then -- ngx.exit(ngx.HTTP_FORBIDDEN) -- return close_redis(red) -- end local incrKey = "user:"..clientIP..":freq" local blockKey = "user:"..clientIP..":block" local is_block,err = red:get(blockKey) -- check if ip is blocked --ngx.say(tonumber(is_block)) if tonumber(is_block) == 1 then --ngx.say(3) ngx.exit(403) --ngx.exit(ngx.HTTP_FORBIDDEN) close_redis(red) end inc = red:incr(incrKey) ngx.say(inc) if inc < 2 then inc = red:expire(incrKey,1) end if inc > 2 then --每秒2次以上訪問即視為非法,會阻止1分鍾的訪問 red:set(blockKey,1) --設置block 為 True 為1 red:expire(blockKey,60) end close_redis(red) 

 

最終效果:

  1. 在一秒內訪問1,2次,nginx 返回 1,2
  2. 一秒訪問3次,直接返回 403 ,參數可控 ,封禁時間可控 
    這里寫圖片描述
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_28018283/article/details/79478838


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM