openresty限频

Openresty安装并限频

内核调参
安装Openresty
加载lua脚本实现限频
nginx配置文件
vhosts 示例
测试

内核调参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
openresty版本:openresty-1.19.9.1
机器规格: 8c16g 
内核参数修改并生效: cat /etc/sysctl.conf && sysctl -p 
sysctl.conf
fs.file-max = 1577138
vm.swappiness = 0
kernel.sysrq = 1
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.tcp_max_tw_buckets = 50000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 10240
net.ipv4.tcp_synack_retries = 2
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.netfilter.nf_conntrack_max = 524288
net.nf_conntrack_max = 524288
net.core.netdev_max_backlog = 50000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65000

安装Openresty

源码编译,nginx二进制文件;
#下载openrestry,对应apt安装的版本
wget –no-check-certificate https://openresty.org/download/openresty-1.19.9.1.tar.gz

#下载nginx_upstream_check_module模块
wget –no-check-certificate https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz

tar -xf openresty-1.19.9.1.tar.gz
tar -xf v0.3.0.tar.gz
cp -r nginx_upstream_check_module-0.3.0/ openresty-1.19.9.1/bundle/

#更新源
apt-get update
#安装编译需要依赖
sudo apt install make gcc libpcre3 libpcre3-dev openssl libssl-dev zlib1g-dev libgeoip-dev

编译

cd openresty-1.19.9.1/

sudo ./configure –prefix=/usr/local/openresty –with-cc-opt=’-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl111/include’ –with-ld-opt=’-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl111/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl111/lib’ –add-module=./bundle/nginx_upstream_check_module-0.3.0/ –with-pcre-jit –with-stream –with-stream_ssl_module –with-stream_ssl_preread_module –with-http_v2_module –without-mail_pop3_module –without-mail_imap_module –without-mail_smtp_module –with-http_stub_status_module –with-http_realip_module –with-http_addition_module –with-http_auth_request_module –with-http_secure_link_module –with-http_random_index_module –with-http_gzip_static_module –with-http_sub_module –with-http_dav_module –with-http_flv_module –with-http_mp4_module –with-http_gunzip_module –with-threads –with-stream –with-http_ssl_module –with-http_geoip_module

sudo make
sudo make install

mkdir -p /usr/local/nginx/conf-openresty.d
mkdir -p /usr/local/nginx/vhosts
cp /usr/local/openresty/nginx/conf/mime.types /usr/local/nginx/mime.types

指定nginx配置文件

/usr/local/openresty/nginx/sbin/nginx -c /usr/local/nginx/nginx.conf #(依照机器具体nginx配置)
加载lua脚本实现限频
lua脚本和lua限频率配置压缩包 https://www.jxhs.me/data/2024-06-23/openresty-lua.tar.gz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
配置文件目录:/usr/local/openresty/nginx/config
application.json
rules/frequency_limit.json
rules/filter.json
tar -zxvf openresty-lua.tar.gz -C /usr/local/openresty/nginx/
cd /usr/local/openresty/nginx/config/rules/
vim frequency_limit.json
[
{
"enable": true,
"matchers": {
"URL": {
"operator": "≈",
"value": "api-test.test.com/info"
}
},
"count": "6", # 6次访问次数
"time": "1", # 1s
"limit_items": ["ip"]
}
]

nginx配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
nginx主配置文件
user ubuntu;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;

error_log /app/logs/nginx/error.log warn;

events {
worker_connections 50240;
use epoll;
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '{'
'"time_local": "$time_local",'
'"remote_addr": "$remote_addr",'
'"http_x_forwarded_for": "$http_x_forwarded_for",'
'"http_x_amzn_trace_id": "$http_x_amzn_trace_id",'
'"host": "$host",'
'"server_port": "$server_port",'
'"status": "$status",'
'"request_time": "$request_time",'
'"upstream_connect_time": "$upstream_connect_time",'
'"upstream_header_time": "$upstream_header_time",'
'"request": "$request",'
'"request_id": "$request_id",'
'"upstream_addr": "$upstream_addr",'
'"upstream_response_time": "$upstream_response_time",'
'"upstream_status": "$upstream_status",'
'"request_length": "$request_length",'
'"body_bytes_sent": "$body_bytes_sent",'
'"remote_user": "$remote_user",'
'"http_referer": "$http_referer",'
'"http_user_agent": "$http_user_agent"'
'}';

sendfile on;
send_timeout 30;

keepalive_timeout 75s;
keepalive_requests 20000;
gzip on;
gzip_min_length 1000;
gzip_buffers 4 8k;
gzip_comp_level 2;
gzip_http_version 1.1;
gzip_types text/css text/xml text/plain text/vnd.wap.wml application/x-javascript application/rss+xml application/xhtml+xml application/javascript application/json;

proxy_buffer_size 128k;
proxy_buffers 32 128k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_read_timeout 15s;
proxy_connect_timeout 3s;
# proxy_ignore_client_abort on;
client_max_body_size 120m;
client_body_buffer_size 120M;

server_tokens off;

geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoLiteCity.dat;


map $http_x_forwarded_for $RealIpFromForwarded {
"" $remote_addr;
~^.*?,?(?P<ipAddr>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$ $ipAddr;
}

map $http_x_connecting_ip $clientRealIp {
"" $RealIpFromForwarded;
~^.*?,?(?P<ipAddr>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$ $ipAddr;
}

server {
listen 80;
server_name localhost;

location / {
return 404;
}

location /health {
add_header Content-Type text/plain;
return 200 'ngx up!';
}        
location /nginx_status {
stub_status on;
allow 127.0.0.1; #only allow requests from localhost
deny all; #deny all other hosts
}    
}

include conf-openresty.d/*.conf;
include vhosts/*.conf;
}

nginx配置加载lua脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# vim /usr/local/nginx/conf-openresty.d/in_http_block.conf

lua_package_path '/usr/local/openresty/nginx/lua/?.lua;;/usr/local/openresty/nginx/lua/module/?.lua;;/usr/local/openresty/nginx/lua/library/?.lua;;';
lua_package_cpath '/usr/local/openresty/nginx/lua/?.so;;';
lua_code_cache on;

lua_shared_dict frequency_limit 10m;
lua_shared_dict config 5m;
lua_shared_dict summary 20m;
lua_shared_dict status 10m;

init_by_lua_file /usr/local/openresty/nginx/lua/on_init.lua;
access_by_lua_file /usr/local/openresty/nginx/lua/on_access.lua;
rewrite_by_lua_file /usr/local/openresty/nginx/lua/on_rewrite.lua;
log_by_lua_file /usr/local/openresty/nginx/lua/on_log.lua;

vhosts 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vim /usr/local/nginx/vhosts/api-test.test.com.conf
server {
listen 80;
server_name api-test.test.com;

access_log /app/logs/nginx/api-test.test.com.access.log json;
error_log /app/logs/nginx/api-test.test.com.error.log error;

location / {
proxy_pass http://xx.xx.xx.xx:port;
}
location /info {
echo "123 $remote_addr";
}
}

测试

1.启动openresty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nginx.service 
cat /lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/openresty/nginx/logs/nginx.pid
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -c /usr/local/nginx/nginx.conf -t
ExecStart=/usr/local/openresty/nginx/sbin/nginx -c /usr/local/nginx/nginx.conf
ExecReload=/usr/local/openresty/nginx/sbin/nginx -s reload
ExecStop=/usr/local/openresty/nginx/sbin/nginx -s stop
PrivateTmp=true
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

在另外一台服务器配置hosts做测试,模拟20个请求访问 http://api-test.test.com/info,在1s内超过6个的其他请求会返回 frequency limit 的网页信息并返回429的状态码
~$ sudo /usr/local/openresty/nginx/sbin/nginx -c /usr/local/nginx/nginx.conf # 启动 openresty

在另外一台主机上测试,模拟20个请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
~$ for i in {1..20};do curl http://api-test.test.com/info;done
123 172.31.15.178
123 172.31.15.178
123 172.31.15.178
123 172.31.15.178
123 172.31.15.178
123 172.31.15.178
<!DOCTYPE html>
<html>
<body>
<h1>frequency limit</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<h1>frequency limit</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<h1>frequency limit</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<h1>frequency limit</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<h1>frequency limit</h1>
</body>
</html>
...

查看nginx日志,看到返回429 status code,符合预期


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!