OpenResty(Lua)+Redis實現動態封禁IP

文章目錄

    • 架構設計
    • 環境準備
    • 源碼編輯安裝OpenResty
      • 下載
      • 安裝準備依賴
      • 編譯
      • 安裝
      • 配置環境變量(可選)
      • OpenResty 服務管理命令
    • 安裝Redis
    • 配置Lua腳本
    • 測試
      • 準備測試工具
      • 測試封禁邏輯
    • 刪除版本信息
    • 清除編譯安裝的OpenResty

架構設計

通過 Nginx + Redis 的方案,確實可以將流量擋在 Nginx 和 Redis 層,從而利用nginx和redis適合高并發的特點,保護后端了服務。如果需要更高的性能和可靠性,推薦使用防火墻/WAF相關手段,將流量擋在網絡層面。

  • 動態封禁邏輯:通過Lua腳本實時分析Nginx訪問日志,將高頻請求的IP寫入Redis黑名單。
  • 自動解封機制:Redis中設置IP的TTL過期時間,到期自動釋放。
  • 性能優化:使用共享內存緩存黑名單,減少Redis查詢壓力。

環境準備

關閉防火墻和selinux,進行時間同步。

  • 操作系統:兩臺CentOS 7.9(本文章使用)或其他操作系統
  • 軟件依賴:OpenResty(集成Nginx+Lua)、Redis 5.0+
  • 網絡權限:確保Redis端口(默認6379)可訪問

主機OpenResty:

[root@localhost ~]# hostnamectl set-hostname openresty
[root@localhost ~]# bash
[root@openresty ~]# ip a | grep 192.168inet 192.168.226.133/24 brd 192.168.226.255 scope global noprefixroute ens33
[root@openresty ~]# hostnamectlStatic hostname: openrestyPretty hostname: openrestyIcon name: computer-vmChassis: vmMachine ID: 7ec089d0625e4b258d18677311cbeb31Boot ID: 550ce2f4975f431aaf449951924e6821Virtualization: vmwareOperating System: CentOS Linux 7 (Core)CPE OS Name: cpe:/o:centos:centos:7Kernel: Linux 3.10.0-1160.el7.x86_64Architecture: x86-64
[root@openresty ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

主機Redis:

[root@localhost ~]# hostnamectl set-hostname redis
[root@localhost ~]# bash
bash
[root@redis ~]# ip a | grep 192.168inet 192.168.226.134/24 brd 192.168.226.255 scope global noprefixroute ens33[root@redis ~]# hostnamectlStatic hostname: redisIcon name: computer-vmChassis: vmMachine ID: 7ec089d0625e4b258d18677311cbeb31Boot ID: 3bc6025f09f84885a928787b996fdf28Virtualization: vmwareOperating System: CentOS Linux 7 (Core)CPE OS Name: cpe:/o:centos:centos:7Kernel: Linux 3.10.0-1160.el7.x86_64Architecture: x86-64
[root@redis ~]# cat /etc/os-release 
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

源碼編輯安裝OpenResty

下載

在192.168.226.133上操作

  1. 官網下載:https://openresty.org/cn/download.html

    上傳壓縮包至openresty主機中

  2. 使用wget下載:

[root@openresty ~]# wget https://openresty.org/download/openresty-1.25.3.2.tar.gz
--2025-03-14 23:06:24--  https://openresty.org/download/openresty-1.25.3.2.tar.gz
Resolving openresty.org (openresty.org)... 47.91.165.147
Connecting to openresty.org (openresty.org)|47.91.165.147|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5837745 (5.6M) [application/x-gzip]
Saving to: ‘openresty-1.25.3.2.tar.gz’100%[==============================================================================================================================================================================================>] 5,837,745   4.46MB/s   in 1.2s   2025-03-14 23:06:26 (4.46 MB/s) - ‘openresty-1.25.3.2.tar.gz’ saved [5837745/5837745]# 解壓
[root@openresty ~]# tar -zxvf openresty-1.25.3.2.tar.gz

安裝準備依賴

[root@openresty ~]# mkdir -p ./package# 下載依賴包并緩存到當前目錄下的package目錄里,這個命令方便離線緩存后拿到內網主機安裝
# 將 package 目錄拷貝到目標機器后,通過以下命令批量安裝:rpm -ivh ./package/*.rpm --nodeps --force
# --downloadonly 會下載主包及其所有依賴的 RPM 文件,但需注意:
# 如果依賴包已安裝,yum 默認不會重復下載。若需強制下載,需在未安裝的環境中操作 
# 使用 --setopt=keepcache=1 可強制緩存,但需在 /etc/yum.conf 中設置 keepcache=1 
# 不同Linux發行版依賴包名可能不同(如Ubuntu用apt安裝libpcre3-dev等)
[root@openresty ~]# yum install -y --downloadonly --downloaddir=./package readline-devel pcre pcre-devel openssl openssl-devel gcc curl GeoIP-devel perl

編譯

[root@openresty ~]# cd openresty-1.25.3.2
[root@openresty openresty-1.25.3.2]# ll
total 104
drwxrwxr-x 46 1000 1000  4096 Jul 17  2024 bundle
-rwxrwxr-x  1 1000 1000 51486 Jul 17  2024 configure
-rw-rw-r--  1 1000 1000 22924 Jul 17  2024 COPYRIGHT
drwxrwxr-x  2 1000 1000  4096 Jul 17  2024 patches
-rw-rw-r--  1 1000 1000  4689 Jul 17  2024 README.markdown
-rw-rw-r--  1 1000 1000  8974 Jul 17  2024 README-windows.txt
drwxrwxr-x  2 1000 1000    52 Jul 17  2024 util# 自行確認依賴包都已安裝
# 運行配置腳本以準備編譯過程;使用./configure --help查看所有可用參數
# 若需自定義安裝路徑,添加--prefix=/your/path(默認路徑為/usr/local/openresty)
[root@openresty openresty-1.25.3.2]#./configure \--with-luajit \--with-http_ssl_module \--with-http_gzip_static_module \--with-http_realip_module \--with-http_stub_status_module注釋:--with-luajit:啟用LuaJIT支持(高性能Lua引擎)。--with-http_ssl_module:啟用HTTPS支持。--with-http_gzip_static_module:啟用靜態文件壓縮。--with-http_realip_module:獲取客戶端真實IP。--with-http_stub_status_module:啟用Nginx狀態監控

安裝

[root@openresty openresty-1.25.3.2]# make -j$(nproc)   # 并行編譯,加速構建
[root@openresty openresty-1.25.3.2]# make install      # 安裝到系統目錄

配置環境變量(可選)

為方便啟動,可將OpenResty的Nginx路徑加入PATH修改~/.bashrc/etc/profile

[root@openresty openresty-1.25.3.2]# export PATH=/usr/local/openresty/nginx/sbin:$PATH
[root@openresty openresty-1.25.3.2]# source ~/.bashrc

配置路徑解析

配置項路徑作用說明
Nginx 根目錄/usr/local/openresty/nginx所有組件和文件的安裝根目錄
Nginx 可執行文件/usr/local/openresty/nginx/sbin/nginx啟動、停止服務的核心二進制文件
動態模塊目錄/usr/local/openresty/nginx/modules存放通過 load_module 加載的動態模塊(如第三方擴展)
主配置文件/usr/local/openresty/nginx/conf/nginx.conf全局配置入口,建議分拆配置到 conf.d/ 目錄
PID 文件/usr/local/openresty/nginx/logs/nginx.pid記錄 Nginx 主進程的進程 ID(用于 nginx -s reload 等操作)
錯誤日志/usr/local/openresty/nginx/logs/error.log服務運行時的錯誤日志(故障排查優先查看此文件)
訪問日志/usr/local/openresty/nginx/logs/access.log所有 HTTP 請求的訪問日志(需定期清理或輪轉)
臨時文件目錄client_body_temp, proxy_temp, fastcgi_temp處理請求時生成的臨時文件(需確保磁盤空間充足和寫入權限)

OpenResty 服務管理命令

# 安全啟動配置-創建專用用戶
[root@openresty openresty-1.25.3.2]# cd
[root@openresty ~]# useradd -M -s /sbin/nologin nginx                # 創建無登錄權限的用戶
[root@openresty ~]# chown -R nginx:nginx /usr/local/openresty/nginx/  # 修改目錄權限
命令參數/選項說明
/usr/local/openresty/nginx/sbin/nginx-p /custom/path指定 OpenResty 項目根目錄(默認 /usr/local/openresty
-c nginx.conf指定配置文件路徑(默認 /usr/local/openresty/nginx/conf/nginx.conf
-s stop強制停止服務
-s quit優雅停止服務(等待請求處理完成)
-s reload重載配置文件(不中斷服務)
-t檢查配置文件語法是否正確
-V顯示 OpenResty 版本及編譯時啟用的模塊(如 LuaJIT、SSL 等)

編輯 nginx.conf

修改下屬配置,一般就在第2行,修改完成后保存退出

[root@openresty ~]# vim /usr/local/openresty/nginx/conf/nginx.conf
user nginx;

啟動

# 直接啟動
[root@openresty ~]# /usr/local/openresty/nginx/sbin/nginx
# 檢查進程是否運行
[root@openresty ~]# ps aux | grep nginx
root      25779  0.0  0.0  55312  1708 ?        Ss   00:52   0:00 nginx: master process /usr/local/openresty/nginx/sbin/nginx
nginx     25780  0.0  0.1  55736  2472 ?        S    00:52   0:00 nginx: worker process[root@openresty ~]# ss -tnlp | grep 80
LISTEN     0      128          *:80                       *:*                   users:(("nginx",pid=25780,fd=6),("nginx",pid=25779,fd=6))瀏覽器訪問:http://192.168.226.133/
然后可以看到Welcome to OpenResty!的頁面。

安裝Redis

在192.168.226.134主機安裝

redis這里直接使用yum安裝了

# centos7.9的默認倉庫epel只有一個3.2x版本的Redis
# Remi 倉庫是一個常用的第三方倉庫,提供了較新的軟件版本。
[root@redis ~]# yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm# 查看 Remi 倉庫中的 Redis 版本
[root@redis ~]# yum --enablerepo=remi list redis --showduplicates
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile* base: mirrors.aliyun.com* extras: mirrors.aliyun.com* remi: mirrors.tuna.tsinghua.edu.cn* remi-safe: mirrors.tuna.tsinghua.edu.cn* updates: mirrors.aliyun.com
remi                                                                                                                                                                       | 3.0 kB  00:00:00     
remi-safe                                                                                                                                                                  | 3.0 kB  00:00:00     
(1/2): remi-safe/primary_db                                                                                                                                                | 2.6 MB  00:00:01     
(2/2): remi/primary_db                                                                                                                                                     | 3.7 MB  00:00:02     
Available Packages
redis.x86_64                                                                                3.2.12-2.el7                                                                                      epel
redis.x86_64                                                                                5.0.13-1.el7.remi                                                                                 remi
redis.x86_64                                                                                5.0.14-1.el7.remi                                                                                 remi
redis.x86_64                                                                                6.0.19-1.el7.remi                                                                                 remi
redis.x86_64                                                                                6.0.20-1.el7.remi                                                                                 remi
redis.x86_64                                                                                6.2.13-1.el7.remi                                                                                 remi
redis.x86_64                                                                                6.2.14-1.el7.remi                                                                                 remi
redis.x86_64                                                                                7.0.14-1.el7.remi                                                                                 remi
redis.x86_64                                                                                7.0.15-1.el7.remi                                                                                 remi
redis.x86_64                                                                                7.2.4-1.el7.remi                                                                                  remi
redis.x86_64                                                                                7.2.5-1.el7.remi                                                                                  remi# 選擇一個版本下載安裝
[root@redis ~]# yum -y --enablerepo=remi install redis-5.0.14-1.el7.remi
[root@redis ~]# systemctl enable --now redis[root@redis ~]# redis-cli -v
redis-cli 5.0.14# 配置連接Redis的用戶名和密碼
# 編輯 Redis 配置文件(通常位于 /etc/redis.conf
# 找到 requirepass 字樣附近插入配置并設置密碼
[root@redis ~]# vim /etc/redis.conf
requirepass "GFrc3d+76Fr*Ctpt"# 重啟Redis
[root@redis ~]# systemctl restart redis
# 使用密碼連接測試
[root@redis ~]# redis-cli -h 127.0.0.1 -p 6379 -a "GFrc3d+76Fr*Ctpt"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> # 配置指定IP可以連接Redis 
# 編輯配置文件找到bind關鍵字,增加指定IP的配置
[root@redis ~]# vim /etc/redis.conf
bind 127.0.0.1 192.168.226.133 192.168.226.134# 重啟Redis,然后自行連接測試即可
[root@redis ~]# systemctl restart redis

配置Lua腳本

在192.168.226.133上操作

[root@openresty ~]# cd /usr/local/openresty/nginx/conf# 更新nginx.conf配置
[root@openresty conf]# cat nginx.conf
user  nginx;
worker_processes  auto;# 錯誤日志設置
error_log  logs/error.log  warn;
pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;# 真實IP解析設置real_ip_header     X-Forwarded-For;real_ip_recursive  on;# 定義日志格式log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  logs/access.log  main;# Lua配置lua_package_path "/usr/local/openresty/lualib/?.lua;;";lua_shared_dict ip_counters 10m;  # 用于擴展速率限制server {listen       80;server_name  localhost;# 在訪問階段執行IP檢查access_by_lua_file conf/lua/ip_block.lua;location / {root   html;index  index.html index.htm;}# 封禁IP管理接口(生產環境需要添加鑒權!)location /manage/blacklist {allow 127.0.0.1;  # 只允許本地訪問deny all;# 參數示例:# /manage/blacklist?action=add&ip=1.2.3.4# /manage/blacklist?action=del&ip=1.2.3.4content_by_lua_block {local redis = require "resty.redis"local red = redis:new()red:set_timeout(1000)local ip = ngx.var.arg_iplocal action = ngx.var.arg_actionif not (ip and action) thenngx.say('{"code":400,"msg":"缺少參數"}')returnend-- 連接Redislocal ok, err = red:connect("192.168.226.134", 6379)if not ok thenngx.say('{"code":500,"msg":"Redis連接失敗"}')returnend-- 認證local auth_ok, auth_err = red:auth("GFrc3d+76Fr*Ctpt")if not auth_ok thenngx.say('{"code":500,"msg":"Redis認證失敗"}')returnendred:select(15)-- 執行操作local resif action == "add" thenres, err = red:sadd("blacklist", ip)elseif action == "del" thenres, err = red:srem("blacklist", ip)elsengx.say('{"code":400,"msg":"無效操作"}')returnendif err thenngx.say('{"code":500,"msg":"操作失敗: '..err..'"}')elsengx.say('{"code":200,"msg":"操作成功","affected":'..res..'}')endred:close()}}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}

創建Lua腳本(日志記錄允許通過的不允許的配置,選擇一個lua腳本配置即可。)

[root@openresty conf]# mkdir lua
[root@openresty conf]# cd lua/
[root@openresty lua]# cat ip_block.lua
local redis = require "resty.redis"
local cjson = require "cjson.safe"-- 配置區域 ===========================================
local SECURITY_CONFIG = {redis = {host = "192.168.226.134",   -- Redis 服務器地址port = 6379,                -- Redis 端口password = "GFrc3d+76Fr*Ctpt", -- Redis 認證密碼database = 15,              -- 使用的數據庫編號timeout = 1000              -- 連接超時時間(毫秒)},rate_limit = {window = 5,                 -- 統計時間窗口(秒)threshold = 10,             -- 請求閾值(次數/窗口)ban_duration = 60           -- 封禁時長(秒)},log = {path = "/usr/local/openresty/nginx/logs/lua_combined.log" -- 日志文件路徑}
}
-- 結束配置區域 =======================================-- 獲取客戶端 IP
local function get_client_ip()local headers = ngx.req.get_headers()return headers["X-Real-IP"] or (headers["X-Forwarded-For"] and headers["X-Forwarded-For"]:match("([^,]+)")) orngx.var.remote_addr
end-- 記錄日志
local function log_event(event_type, client_ip, reason)local log_entry = {timestamp = ngx.localtime(),event = event_type,client_ip = client_ip,reason = reason,request = {method = ngx.req.get_method(),uri = ngx.var.request_uri,args = ngx.req.get_uri_args()}}local json_str, err = cjson.encode(log_entry)if not json_str thenngx.log(ngx.ERR, "JSON 編碼失敗: ", err)returnend-- 異步寫入日志local ok, err = ngx.timer.at(0, function(premature, path, entry)if premature then return endlocal file = io.open(path, "a")if file thenfile:write(entry, "\n")file:close()elsengx.log(ngx.ERR, "無法打開日志文件: ", path)endend, SECURITY_CONFIG.log.path, json_str)if not ok thenngx.log(ngx.ERR, "無法創建日志定時器: ", err)end
end-- 主邏輯
local client_ip = get_client_ip()
local red = redis:new()
red:set_timeout(SECURITY_CONFIG.redis.timeout)-- 連接 Redis
local ok, err = red:connect(SECURITY_CONFIG.redis.host, SECURITY_CONFIG.redis.port)
if not ok thenngx.log(ngx.ERR, "Redis 連接失敗: ", err)return ngx.exit(500)
end-- 認證
local auth_ok, auth_err = red:auth(SECURITY_CONFIG.redis.password)
if not auth_ok thenngx.log(ngx.ERR, "Redis 認證失敗: ", auth_err)return ngx.exit(500)
end-- 選擇數據庫
red:select(SECURITY_CONFIG.redis.database)-- 檢查白名單
local is_whitelisted, err = red:sismember("whitelist", client_ip)
if is_whitelisted == 1 thenlog_event("WHITELIST_BYPASS", client_ip, "IP 在白名單中")red:set_keepalive(10000, 100)  -- 釋放連接到連接池return  -- 白名單直接放行
end-- 檢查黑名單
local is_blacklisted, err = red:sismember("blacklist", client_ip)
if is_blacklisted == 1 thenlog_event("BLACKLIST_BLOCK", client_ip, "IP 在黑名單中")red:set_keepalive(10000, 100)  -- 釋放連接到連接池return ngx.exit(403)  -- 返回 403 禁止訪問
end-- 檢查請求頻率
local counter_key = "rate_limit:" .. client_ip
local request_count, err = red:incr(counter_key)
if not request_count thenngx.log(ngx.ERR, "Redis 計數器增加失敗: ", err)return ngx.exit(500)
end-- 如果是第一次訪問,設置過期時間
if request_count == 1 thenred:expire(counter_key, SECURITY_CONFIG.rate_limit.window)
end-- 觸發封禁條件
if request_count > SECURITY_CONFIG.rate_limit.threshold thenlocal ok, err = red:sadd("blacklist", client_ip)if not ok thenngx.log(ngx.ERR, "添加黑名單失敗: ", err)return ngx.exit(500)endred:expire("blacklist", SECURITY_CONFIG.rate_limit.ban_duration)log_event("RATE_LIMIT_BLOCK", client_ip, "請求頻率超限")red:set_keepalive(10000, 100)  -- 釋放連接到連接池return ngx.exit(429)  -- 返回 429 請求過多
end-- 正常請求
log_event("ALLOWED_REQUEST", client_ip, "請求通過")
red:set_keepalive(10000, 100)  -- 釋放連接到連接池

日志僅記錄不允許的配置

local redis = require "resty.redis"
local cjson = require "cjson.safe"-- 配置區域 ===========================================
local SECURITY_CONFIG = {redis = {host = "192.168.226.134",   -- Redis 服務器地址port = 6379,                -- Redis 端口password = "GFrc3d+76Fr*Ctpt", -- Redis 認證密碼database = 15,              -- 使用的數據庫編號timeout = 1000              -- 連接超時時間(毫秒)},rate_limit = {window = 5,                 -- 統計時間窗口(秒)threshold = 10,             -- 請求閾值(次數/窗口)ban_duration = 60           -- 封禁時長(秒)},log = {path = "/usr/local/openresty/nginx/logs/lua_combined.log" -- 日志文件路徑}
}
-- 結束配置區域 =======================================-- 獲取客戶端 IP
local function get_client_ip()local headers = ngx.req.get_headers()return headers["X-Real-IP"] or (headers["X-Forwarded-For"] and headers["X-Forwarded-For"]:match("([^,]+)")) orngx.var.remote_addr
end-- 記錄日志
local function log_event(event_type, client_ip, reason)local log_entry = {timestamp = ngx.localtime(),event = event_type,client_ip = client_ip,reason = reason,request = {method = ngx.req.get_method(),uri = ngx.var.request_uri,args = ngx.req.get_uri_args()}}local json_str, err = cjson.encode(log_entry)if not json_str thenngx.log(ngx.ERR, "JSON 編碼失敗: ", err)returnend-- 異步寫入日志local ok, err = ngx.timer.at(0, function(premature, path, entry)if premature then return endlocal file = io.open(path, "a")if file thenfile:write(entry, "\n")file:close()elsengx.log(ngx.ERR, "無法打開日志文件: ", path)endend, SECURITY_CONFIG.log.path, json_str)if not ok thenngx.log(ngx.ERR, "無法創建日志定時器: ", err)end
end-- 主邏輯
local client_ip = get_client_ip()
local red = redis:new()
red:set_timeout(SECURITY_CONFIG.redis.timeout)-- 連接 Redis
local ok, err = red:connect(SECURITY_CONFIG.redis.host, SECURITY_CONFIG.redis.port)
if not ok thenngx.log(ngx.ERR, "Redis 連接失敗: ", err)return ngx.exit(500)
end-- 認證
local auth_ok, auth_err = red:auth(SECURITY_CONFIG.redis.password)
if not auth_ok thenngx.log(ngx.ERR, "Redis 認證失敗: ", auth_err)return ngx.exit(500)
end-- 選擇數據庫
red:select(SECURITY_CONFIG.redis.database)-- 檢查白名單
local is_whitelisted, err = red:sismember("whitelist", client_ip)
if is_whitelisted == 1 thenred:set_keepalive(10000, 100)  -- 釋放連接到連接池return  -- 白名單直接放行
end-- 檢查黑名單
local is_blacklisted, err = red:sismember("blacklist", client_ip)
if is_blacklisted == 1 thenlog_event("BLACKLIST_BLOCK", client_ip, "IP 在黑名單中")red:set_keepalive(10000, 100)  -- 釋放連接到連接池return ngx.exit(403)  -- 返回 403 禁止訪問
end-- 檢查請求頻率
local counter_key = "rate_limit:" .. client_ip
local request_count, err = red:incr(counter_key)
if not request_count thenngx.log(ngx.ERR, "Redis 計數器增加失敗: ", err)return ngx.exit(500)
end-- 如果是第一次訪問,設置過期時間
if request_count == 1 thenred:expire(counter_key, SECURITY_CONFIG.rate_limit.window)
end-- 觸發封禁條件
if request_count > SECURITY_CONFIG.rate_limit.threshold thenlocal ok, err = red:sadd("blacklist", client_ip)if not ok thenngx.log(ngx.ERR, "添加黑名單失敗: ", err)return ngx.exit(500)endred:expire("blacklist", SECURITY_CONFIG.rate_limit.ban_duration)log_event("RATE_LIMIT_BLOCK", client_ip, "請求頻率超限")red:set_keepalive(10000, 100)  -- 釋放連接到連接池return ngx.exit(429)  -- 返回 429 請求過多
end-- 正常請求,不記錄日志
red:set_keepalive(10000, 100)  -- 釋放連接到連接池

熱加載配置

[root@openresty lua]# nginx -t
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
[root@openresty lua]# nginx -s reload
# 修改目錄權限
[root@openresty lua]# chown -R nginx:nginx /usr/local/openresty/nginx/
[root@openresty lua]# chmod -R 755 /usr/local/openresty/nginx/html

附白名單操作:

如果需要加白處理,需要手動在Redis中插入

SADD whitelist 192.168.226.134

測試

準備測試工具

  • 使用工具模擬高頻率請求。推薦使用以下工具:

    • ab (Apache Benchmark):適用于簡單的壓力測試。
    • wrk:高性能的 HTTP 壓力測試工具。
    • curl:手動測試單次請求。
    # 安裝 ab
    yum install httpd-tools -y# 安裝 wrk (第三方 RPM 包安裝)
    yum install -y https://github.com/scutse/wrk-rpm/releases/download/4.1.0/wrk-4.1.0-1.el7.centos.x86_64.rpm
    

一般yum 官方倉庫中未提供 wrk 的預編譯包。

下附wrk安裝方法:

# 安裝依賴
yum install -y git make gcc openssl-devel
# 克隆源碼并編譯
git clone https://github.com/wg/wrk.git
cd wrk
make
# 安裝到系統路徑
cp wrk /usr/local/bin
# 驗證安裝,輸出版本信息即表示成功
wrk --version

測試封禁邏輯

使用 ab 進行壓力測試

運行以下命令,模擬高頻率請求:

[root@openresty ~]# curl http://localhost/[root@openresty ~]# ab -n 100 -c 10 http://192.168.226.133/參數說明:- `-n 100`:總請求數為 100。- `-c 10`:并發請求數為 10[root@openresty ~]# curl http://localhost/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty</center>
</body>
</html>

觀察 Nginx 日志和 Lua 日志,檢查是否觸發封禁邏輯:

如果封禁邏輯生效,你會看到類似以下的日志:

[root@openresty ~]# tail -f /usr/local/openresty/nginx/logs/lua_combined.log  # 我使用的lua配置僅記錄黑名單的訪問,因此就看到了拒絕的日志
{"timestamp":"2025-03-15 20:02:24","event":"RATE_LIMIT_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.1","reason":"請求頻率超限"}
{"timestamp":"2025-03-15 20:02:24","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.1","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:02:24","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.1","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:02:24","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.1","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:02:25","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.1","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:03:05","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:03:05","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:03:05","event":"RATE_LIMIT_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"請求頻率超限"}
{"timestamp":"2025-03-15 20:03:05","event":"RATE_LIMIT_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"請求頻率超限"}
{"timestamp":"2025-03-15 20:03:05","event":"RATE_LIMIT_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"請求頻率超限"}
{"timestamp":"2025-03-15 20:03:05","event":"RATE_LIMIT_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"請求頻率超限"}
{"timestamp":"2025-03-15 20:03:05","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:03:05","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"IP 在黑名單中"}
{"timestamp":"2025-03-15 20:03:05","event":"BLACKLIST_BLOCK","request":{"args":{},"method":"GET","uri":"\/"},"client_ip":"192.168.226.134","reason":"IP 在黑名單中"}

刪除版本信息

1.通過nginx.conf配置

關閉全局版本信息顯示

當訪問瀏覽器這個服務的一個不存在的頁面時,可以看到

404 Not Found
openresty/1.25.3.2

或使用

[root@openresty ~]# curl -I http:192.168.226.133
HTTP/1.1 200 OK
Server: openresty/1.25.3.2
Date: Fri, 14 Mar 2025 17:29:43 GMT
Content-Type: text/html
Content-Length: 116103
Last-Modified: Fri, 14 Mar 2025 15:48:58 GMT
Connection: keep-alive
ETag: "67d44fea-1c587"
Accept-Ranges: bytes

要關閉版本信息這個功能,需要修改nginx配置

vim /usr/local/openresty/nginx/conf/nginx.conf

在http模塊里配置是全局生效,在特定的server塊里配置是特定server塊里的生效,這里我設置全局生效。

[root@openresty ~]#  vim /usr/local/openresty/nginx/conf/nginx.conf
http {...server_tokens off;  # 隱藏 Nginx 版本信息...
}

熱加載配置

[root@openresty ~]# nginx -s reload

重新訪問一個404頁面驗證

404 Not Found
openresty

然后使用curl

[root@openresty ~]# curl -I http://192.168.226.133
HTTP/1.1 200 OK
Server: openresty
Date: Fri, 14 Mar 2025 17:32:04 GMT
Content-Type: text/html
Content-Length: 116103
Last-Modified: Fri, 14 Mar 2025 15:48:58 GMT
Connection: keep-alive
ETag: "67d44fea-1c587"
Accept-Ranges: bytes

通過配置server_tokens off;參數只能隱藏1.25.3.2d而不能隱藏openresty`信息。

2.修改編譯選項

通過配置server_tokens off;但是發現還會有openresty字樣

下述為徹底刪除版本信息方式:

[root@openresty ~]# ll
total 5712
-rw-------. 1 root  root     1259 Feb  7 08:04 anaconda-ks.cfg
drwxrwxr-x  6 nginx nginx     159 Mar 14 23:48 openresty-1.25.3.2
-rw-r--r--  1 root  root  5837745 Jul 17  2024 openresty-1.25.3.2.tar.gz
drwxr-xr-x  2 root  root     4096 Mar 14 23:27 package
[root@openresty ~]# cd openresty-1.25.3.2
[root@openresty openresty-1.25.3.2]# ll
total 116
drwxrwxr-x 47 nginx nginx  4096 Mar 14 23:47 build
drwxrwxr-x 46 nginx nginx  4096 Jul 17  2024 bundle
-rwxrwxr-x  1 nginx nginx 51486 Jul 17  2024 configure
-rw-rw-r--  1 nginx nginx 22924 Jul 17  2024 COPYRIGHT
-rw-r--r--  1 root  root   6005 Mar 14 23:48 Makefile
drwxrwxr-x  2 nginx nginx  4096 Jul 17  2024 patches
-rw-rw-r--  1 nginx nginx  4689 Jul 17  2024 README.markdown
-rw-rw-r--  1 nginx nginx  8974 Jul 17  2024 README-windows.txt
drwxrwxr-x  2 nginx nginx    52 Jul 17  2024 util# 修改源碼中的版本信息:
[root@openresty openresty-1.25.3.2]# cd bundle/nginx-1.25.3/src/core/
[root@openresty core]# cat  nginx.h/** Copyright (C) Igor Sysoev* Copyright (C) Nginx, Inc.*/#ifndef _NGINX_H_INCLUDED_
#define _NGINX_H_INCLUDED_#define nginx_version      1025003
#define NGINX_VERSION      "1.25.3"
#define NGINX_VER          "openresty/" NGINX_VERSION ".2"#ifdef NGX_BUILD
#define NGINX_VER_BUILD    NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD    NGINX_VER
#endif#define NGINX_VAR          "NGINX"
#define NGX_OLDPID_EXT     ".oldbin"#endif /* _NGINX_H_INCLUDED_ */

然后自定義修改為:

[root@openresty core]# cat nginx.h/** Copyright (C) Igor Sysoev* Copyright (C) Nginx, Inc.*/#ifndef _NGINX_H_INCLUDED_
#define _NGINX_H_INCLUDED_#define nginx_version      1025003
#define NGINX_VERSION      "I'm a walk-on"
#define NGINX_VER          "Hello! " NGINX_VERSION "_______110"#ifdef NGX_BUILD
#define NGINX_VER_BUILD    NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD    NGINX_VER
#endif#define NGINX_VAR          "NGINX"
#define NGX_OLDPID_EXT     ".oldbin"#endif /* _NGINX_H_INCLUDED_ */

再次編譯并安裝

[root@openresty core]# cd 
[root@openresty ~]# ll
total 5712
-rw-------. 1 root  root     1259 Feb  7 08:04 anaconda-ks.cfg
drwxrwxr-x  6 nginx nginx     159 Mar 14 23:48 openresty-1.25.3.2
-rw-r--r--  1 root  root  5837745 Jul 17  2024 openresty-1.25.3.2.tar.gz
drwxr-xr-x  2 root  root     4096 Mar 14 23:27 package
[root@openresty ~]# cd openresty-1.25.3.2
[root@openresty openresty-1.25.3.2]# ll
total 116
drwxrwxr-x 47 nginx nginx  4096 Mar 14 23:47 build
drwxrwxr-x 46 nginx nginx  4096 Jul 17  2024 bundle
-rwxrwxr-x  1 nginx nginx 51486 Jul 17  2024 configure
-rw-rw-r--  1 nginx nginx 22924 Jul 17  2024 COPYRIGHT
-rw-r--r--  1 root  root   6005 Mar 14 23:48 Makefile
drwxrwxr-x  2 nginx nginx  4096 Jul 17  2024 patches
-rw-rw-r--  1 nginx nginx  4689 Jul 17  2024 README.markdown
-rw-rw-r--  1 nginx nginx  8974 Jul 17  2024 README-windows.txt
drwxrwxr-x  2 nginx nginx    52 Jul 17  2024 util# 編譯
[root@openresty openresty-1.25.3.2]#./configure \--with-luajit \--with-http_ssl_module \--with-http_gzip_static_module \--with-http_realip_module \--with-http_stub_status_module# 安裝
[root@openresty openresty-1.25.3.2]# make -j$(nproc)   # 并行編譯,加速構建
[root@openresty openresty-1.25.3.2]# make install      # 安裝到系統目錄
# 進行平滑升級
# 查看舊進程ID
[root@openresty openresty-1.25.3.2]# ps aux | grep nginx
root      33968  0.0  0.0  55312  1704 ?        Ss   01:37   0:00 nginx: master process nginx
nginx     33969  0.0  0.1  55736  2712 ?        S    01:37   0:00 nginx: worker process
root      51298  0.0  0.0 112812   980 pts/0    S+   01:43   0:00 grep --color=auto nginx
# 驗證配置文件無錯誤
[root@openresty openresty-1.25.3.2]# /usr/local/openresty/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
# 熱加載平滑升級
[root@openresty openresty-1.25.3.2]# /usr/local/openresty/nginx/sbin/nginx -s reload
# 查看新進程
[root@openresty openresty-1.25.3.2]# ps aux | grep nginx
root      33968  0.0  0.1  55448  3628 ?        Ss   01:37   0:00 nginx: master process nginx
nginx     51300  0.0  0.1  55884  2656 ?        S    01:43   0:00 nginx: worker process# 此步驟利用平滑升級的思路,重新編譯安裝了服務,去除了版本信息。

清除編譯安裝的OpenResty

# 停止 OpenResty 服務
[root@openresty ~]# /usr/local/openresty/nginx/sbin/nginx -s stop
# 刪除 OpenResty 安裝目錄
[root@openresty ~]# rm -rf /usr/local/openresty
# 刪除 OpenResty 的符號鏈接
[root@openresty ~]# rm -f /usr/local/bin/openresty# 清理環境變量,刪除之前定義的變量export PATH=/usr/local/openresty/nginx/sbin:$PATH
vi ~/.bash_profileexport PATH
# 刪除后保存退出# 清理編譯源碼目錄
[root@openresty ~]# rm -rf ./openresty-1.25.3.2
# 檢查是否清理干凈
[root@openresty ~]# which openresty
[root@openresty ~]# which nginx

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898916.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898916.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898916.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Turtle基本操作(前進、后退、旋轉)

1. Turtle基本移動概念 在Turtle繪圖中,“海龜”(Turtle)相當于一支筆,它在屏幕上移動時,會在經過的路徑上留下軌跡。我們可以通過一系列簡單的指令控制它的前進、后退和旋轉,從而繪制各種形狀和圖案。 2. 前進與后退 2.1 前進(forward() 或 fd()) Turtle的 forward…

C++類與對象的第一個簡單的實戰練習-3.24筆記

在嗶哩嗶哩學習的這個老師的C面向對象高級語言程序設計教程&#xff08;118集全&#xff09;講的真的很不錯 實戰一&#xff1a; 情況一&#xff1a;將所有代碼寫到一個文件main.cpp中 #include<iostream> //不知道包含strcpy的頭文件名稱是什么,問ai可知 #include<…

Jetson Orin NX使用 Ollama 本地部署 deepseek

本文記錄在 jetson orin nx 上使用 ollama 部署 deepseek 的過程 有用的網站及工具 NVIDIA Jetson AI LabOllama官網Jtop 工具 > 用以查看jetson GPU/CPU/Memory 等占用情況的工具&#xff0c;安裝過程如下&#xff1a; sudo apt-get install python3-pip sudo -H pip3 in…

目標檢測20年(三)

對這篇論文感興趣的小伙伴可以訂閱筆者《目標檢測》專欄&#xff0c;關注筆者對該文獻的閱讀和理解。 前兩篇解讀鏈接&#xff1a; 目標檢測20年&#xff08;一&#xff09;-CSDN博客 目標檢測20年&#xff08;二&#xff09;-CSDN博客 目錄 四、 檢測器的加速發展 4.1 特…

智能手持終端PDA在設備巡檢管理中的應用

在工業制造、能源電力、軌道交通等領域&#xff0c;設備巡檢是保障生產安全與連續性的核心環節。傳統巡檢模式存在效率低、易出錯、數據滯后等痛點。上海岳冉智能設備巡檢手持終端PDA&#xff0c;以智能化、數字化、高可靠為核心設計理念&#xff0c;集RFID、條碼掃描、AI圖像識…

AI知識補全(二):提示工程(Prompting)是什么?

名人說&#xff1a;人生如逆旅&#xff0c;我亦是行人。 ——蘇軾《臨江仙送錢穆父》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;AI知識補全&#xff08;一&#xff09;&#xff1a;tokens是什么…

C++友元:跨墻訪問的三種姿勢

目錄 友元 友元之普通函數形式 友元之成員函數形式 友元類 友元的特點 友元 什么叫友元&#xff1f; 一般來說&#xff0c;類的私有成員只能在類的內部訪問&#xff0c;類之外是不能訪問它們的。但如果將其他類/函數設置為類的友元&#xff0c;那么友元類/函數就可以在前…

位運算[找出唯一成對的數]

題目來源&#xff1a;藍橋云課 不用輔助儲存空間 import java.util.Random;public class T_01 {public class Util {public static void swap(int[] arr, int i, int j) {int temp arr[i];arr[i] arr[j];arr[j] temp;}public static void print(int[] arr) {for (int i 0; …

簡記_FPGA 硬件最小系統設計

一、FPGA板級設計的五要素 1.1、電源電路 核心電壓&#xff1a;一般為固定值 IO電壓&#xff1a;FPGA的IO分為多個bank&#xff0c;同一個bank的不同IO引腳電壓相同&#xff0c;不同bank的電壓可以不同 輔助電壓&#xff1a;除了核心電壓和IO電壓&#xff0c;FPGA工作所需的…

7.2 控件和組件

版權聲明&#xff1a;本文為博主原創文章&#xff0c;轉載請在顯著位置標明本文出處以及作者網名&#xff0c;未經作者允許不得用于商業目的 C#工具箱位于編輯窗口的左側&#xff0c;它默認內置了大量的控件和組件。控件一般派生于System.Windows.Forms.Control類&#xff0c;顯…

Spring Boot中接口數據字段為?Long?類型時,前端number精度丟失問題解決方案

Spring Boot中接口數據字段為 Long 類型時&#xff0c;前端number精度丟失問題解決方案 在Spring Boot中&#xff0c;當接口數據字段為 Long 類型時&#xff0c;返回頁面的JSON中該字段通常會被序列化為數字類型。 例如&#xff0c;一個Java對象中有一個 Long 類型的屬性 id …

OpenCV第2課 OpenCV的組成結構與圖片/視頻的加載及展示

1.OpenCV 的組成結構 2.OpenCV 的具體模塊 3. 圖像的讀取 4. 視頻的讀取 1.OpenCV 的組成結構 OpenCV 是由很多模塊組成的,這些模塊可以分成很多層: 最底層是基于硬件加速層(HAL)的各種硬件優化。再上一層是opencv_contrib 模塊所包含的OpenCV 由其他開發人員所貢獻的代…

安裝配置Tesseract-OCR

1,下載對應的可執行文件 在Tesseract OCR下載地址Index of /tesseract下載合適的版本安裝包,如下: 點擊安裝包進行安裝: 語言選擇英文: 如果需要識別中文,則可以在安裝過程中勾選下載中文語言包和腳本(也可以按需選擇繁體):

關于墻面涂鴉的視覺檢測與噴涂修復裝置研究(大綱)

公共場所墻面涂鴉視覺檢測與精準噴涂修復裝置研究 融合視覺識別與自動化噴涂的墻面維護解決方案 第一章 緒論 1.1 研究背景與意義 城市形象與秩序維護&#xff1a; 涂鴉對公共環境的影響&#xff08;破壞美觀、傳遞不良信息&#xff09;清除涂鴉的重要性&#xff08;恢復原貌…

圖論 | 98. 所有可達路徑

98. 所有可達路徑 題目鏈接&#xff1a; 98. 所有可達路徑 思路 先創建鄰接矩陣&#xff0c;再深搜寫代碼是需要注意的是acm格式&#xff0c;輸入的格式要轉化為int&#xff0c;輸出要轉化為str&#xff0c;用map&#xff08;&#xff09;實現。 dfs def dfs(grid,node,n,…

MCP+Hologres+LLM 搭建數據分析 Agent

LLM大模型在數據分析領域的挑戰 在數據分析領域&#xff0c;大模型&#xff08;LLM&#xff09;具備強大語言理解能力&#xff0c;NL2SQL等各類智能化工具也極大提升了數據分析人員的分析效率&#xff0c;但仍舊面臨不少挑戰&#xff1a; 傳統 LLM 缺乏實時數據接入能力&…

Categorical分布(分類分布):深度學習中的離散建模利器

Categorical分布&#xff1a;深度學習中的離散建模利器 引言 對于深度學習研究者來說&#xff0c;概率分布是模型設計和優化的基石。在許多生成模型中&#xff0c;如變分自編碼器&#xff08;VAE&#xff09;及其變種VQ-VAE&#xff08;Vector Quantized Variational Autoenc…

Langchain 提示詞(Prompt)

基本用法 1. 基本概念 提示詞模板 是一個字符串模板&#xff0c;其中包含一些占位符&#xff08;通常是 {variable} 形式的&#xff09;&#xff0c;這些占位符可以在運行時被實際值替換。LangChain 提供了多種類型的提示詞模板&#xff0c;以適應不同的使用場景。 2. 主要類…

centos7.9鏡像源及Python引入ssl問題處理

一、鏡像源修改 1. 備份原有的鏡像源配置文件 在修改之前,先備份現有的 CentOS-Base.repo 文件: sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2. 編輯鏡像源配置文件 使用文本編輯器(如 nano 或 vi)打開 /etc/yum.repos.d/Ce…

Java高頻面試之集合-17

hello啊&#xff0c;各位觀眾姥爺們&#xff01;&#xff01;&#xff01;本baby今天來報道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面試官&#xff1a;JDK 8 對 HashMap 主要做了哪些優化呢&#xff1f;為什么要這么做&#xff1f; JDK 8 對 HashMap 的主要優化及原因 JDK…