本文说一下程序初始化相关代码和nginx配置
1:ngx lua的执行阶段需要大家先了解下。参考这篇博客http://www.mrhaoting.com/?p=157
2:OpenStar的waf.conf配置文件
#lua_socket_log_errors off;
#lua_package_cpath "/opt/openresty/openstar/lib/?.so;;";
#lua_need_request_body on; #开启post
lua_code_cache on; # 关闭lua_cache 缓存 用于调试, 线上需要开启 设置为on
lua_package_path "/opt/openresty/openstar/lib/?.lua;/opt/openresty/lualib/?.lua";
# 这里需要根据自己安装的OR的路径,建议将OpenStar放到OR根目录。
lua_regex_cache_max_entries 102400;
# 1m 存储约1000+条IP数据
lua_shared_dict token_list 20m; # token 存放
lua_shared_dict count_dict 1m; # 用于计数数据的保存
lua_shared_dict config_dict 5m; # 保存config中部分配置
lua_shared_dict ip_dict 30m; # 用于记录黑、白名单ip
lua_shared_dict limit_ip_dict 50m; # 用于URL HOST IP 访问计数
more_set_headers 'Server: OpenStar';
# 暂时没有用nginx 自带的限速功能
#limit_req_zone $binary_remote_addr zone=allips:50m rate=15r/s;
#limit_conn_zone $binary_remote_addr zone=addr:50m;
init_by_lua_file /opt/openresty/openstar/init.lua;
# init 就是程序初始化阶段
#rewrite_by_lua_file /opt/openresty/openstar/rewrite.lua;
# rewrite 阶段暂时没有用上
access_by_lua_file /opt/openresty/openstar/access_all.lua;
# 主要的访问控制阶段
body_filter_by_lua_file /opt/openresty/openstar/body.lua;
# 返回内容替换阶段
3:nginx.conf配置
需要在nginx.conf的http节点下引用waf.conf即可。
user nobody nobody;
# CPU 的亲源等
worker_processes auto;
#worker_cpu_affinity 0001 0010 0100 1000;
worker_rlimit_nofile 100000;
#错误日志处理
#error_log logs/error.log crit;
#error_log logs/error.log debug;
#error_log logs/error.log notice;
error_log logs/error.log;
#error_log logs/error.log info;
events {
use epoll;
accept_mutex off; #关闭惊群
worker_connections 10240; #根据你的机器配置
multi_accept on;
}
http {
#引用waf配置
include waf.conf;
### log处理
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 off;
### 业务相关 ###
include mime.types;
default_type text/html;
charset utf-8;
#resolver 8.8.8.8;
error_page 404 400 /40x.html;
error_page 500 502 503 504 /50x.html;
#error_page 500 502 503 504 http://www.baidu.com;
### IO相关
# 建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存
open_file_cache max=65535 inactive=60s;
# 在inactive时间 1 次没有请求就删除
open_file_cache_min_uses 1;
# 这个是指多长时间检查一次缓存的有效信息
open_file_cache_valid 60s;
open_file_cache_errors on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
sendfile on;
# time相关
keepalive_timeout 30;
client_header_timeout 30;
client_body_timeout 30;
reset_timedout_connection on;
send_timeout 30;
# gzip
#include gzip.conf;
# 缓存相关
client_max_body_size 10m;
client_header_buffer_size 4k;
server_names_hash_bucket_size 128;
large_client_header_buffers 10 4k;
### 反向代理缓存处理
#proxy_cache_path /mnt/ngx_cache/ levels=1:2 keys_zone=my_cache:300m max_size=2g inactive=60m;
#proxy_buffer_size 128k;
#proxy_buffers 4 128k;
#proxy_busy_buffers_size 1024k;
#proxy_temp_file_write_size 1024k;
# http
server {
listen 80;
server_name localhost;
root html;
#lua执行的主目录
set $lua_path "/opt/openresty/openstar/";
#根目录
location / {
#limit_req zone=allips nodelay;
default_type text/html;
}
location ~ ^/api/([-_a-zA-Z0-9/]+) {
#limit_req zone=allips nodelay;
# 重写阶段
#rewrite_by_lua_file "${lua_path}api_rewrite.lua"
# 准入阶段完成参数验证
#access_by_lua_file "${lua_path}api_access.lua";
#内容生成阶段
content_by_lua_file "${lua_path}api/$1.lua";
#内容替换阶段
#body_filter_by_lua_file "${lua_path}api_body.lua";
#日志处理阶段
#log_by_lua_file "${lua_path}api/api_log.lua";
}
location ~* \.(gif|jpg|png|jpeg|bmp|css|js|flv|ico|swf|zip|txt)$ {
access_log off;
proxy_redirect off;
proxy_cache_valid 200 302 6h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 1m;
expires 30d;
}
}
# ssl
# server {
# listen 443;
# server_name localhost;
# root html;
# access_log off;
# #access_log logs/access_https.log main;
#
# ssl on;
# ssl_certificate /opt/openresty/nginx/ssl/server.crt;
# ssl_certificate_key /opt/openresty/nginx/ssl/server_nopwd.key;
#
# location / {
# limit_req zone=allips nodelay;
# default_type text/html;
# #content_by_lua_file "/opt/openresty/openstar/index/index.lua";
# }
#
# location ~* \.(gif|jpg|png|jpeg|bmp|css|js|flv|ico|swf|zip|txt){
# access_log off;
# proxy_redirect off;
# proxy_cache_valid 200 302 6h;
# proxy_cache_valid 301 1d;
# proxy_cache_valid any 1m;
# expires 30d;
# }
# }
include our.conf;
# 自己的业务相关配置
}
上面我配置的nginx一些可以参考下, 使用:
- 配置nginx.conf 在http节点,引用waf.conf。注:原ngx相关配置基本不用修改,该优化优化、该做CPU亲缘绑定继续、该动静分离还继续、该IO、TIME等优化继续不要停。
- 配置waf.conf 修改lua_package_path,使用正确的路径即可
- 设置目录权限 OpenStar目录建议放到OR下,方便操作,该目录ngx运行用户有读写执行权限即可。因为要写日志,暂时没有用ngx.log,后续可能会改动。
- lua文件修改 在init.lua中,修改conf_json参数,config.json文件绝对路径写好。
-
api使用 如果需要使用相关api,需要配置在某个servers下配置一个location,参照一下,配置比较简单,set $lua_path 根据实际情况配置即可
初始化阶段lua代码
在前面的我们执行流程图中,分层对请求进行处理,那么就需要一个基础的配置文件,然后在有规则列表配置文件进行分开。那么我就定义了主配置文件
{
// 注释 线上不要有
"redis_Mod" : {"state":"off","ip":"127.0.0.1","Port" : 6379,"Password":"yesorno@123"},
// redis_Mod 配置的是需要连接的redis相关配置, 这个主要是用于集群操作时使用,把配置和拦截计数放到redis
"realIpFrom_Mod" : "on",
// 表示是否开启从http头取用户真实ip
"ip_Mod" : "on",
// 表示是否开启ip 黑白名单
"host_method_Mod" : "on",
// 表示是否启用 host method 白名单 (用于host准入和method过滤)
"app_Mod" : "on",
// 表示是否启用 自定义规则 这里面的规则用法灵活
"referer_Mod" : "on",
// 表示是否开启referer 白名单
"url_Mod" : "on",
// 表示是否开启 url 的黑白名单
"header_Mod" : "on",
// 表示是否开启 header 黑名单
"agent_Mod" : "on",
// 表示是否开启useragent 黑名单
"cookie_Mod" : "on",
// 表示是否开启 cookie 黑名单
"args_Mod" : "on",
// 表示是否开启 get 参数过滤 黑名单
"post_Mod" : "on",
// 表示是否开启 post 参数过滤 黑名单
"network_Mod" : "on",
// 表示是否开启 网络层访问频率限速 频率黑名单
"replace_Mod" : "off",
// 表示是否开启 返回内容过滤
"debug_Mod" : true,
// 表示是否开启 debug 记录log
"baseDir" : "/opt/openresty/openstar/",
// baseDir 程序根目录
"logPath" : "/opt/openresty/openstar/logs/",
// logPath 配置log保存路径
"jsonPath" : "/opt/openresty/openstar/conf_json/",
// jsonPath 配置规则json文件路径
"htmlPath" : "/opt/openresty/openstar/index/",
// htmlPath 配置程序静态文件存放路径
"sayHtml" : "request error!"
// sayHtml 配置应用层deny 返回的内容
}
init阶段进行初始化(主配置文件,过滤规则配置文件)
直接在代码段里说啦。
local Config = {}
-- 引用json库
local cjson_safe = require "cjson.safe"
--- config.json 文件绝对路径(需要根据自己的情况进行配置)
local config_json = "/opt/openresty/openstar/config.json"
--- 读取文件(全部读取)
local function readfile(filepath)
local fd = io.open(filepath,"r")
if fd == nil then return end -- 文件读取错误返回
local str = fd:read("*a") --- 全部内容读取
fd:close()
return str
end
--- 载入JSON文件
local function loadjson(_path_name)
local x = readfile(_path_name)
local json = cjson_safe.decode(x) or {} --- json decode 失败返回一个空table
return json
end
--- 载入config.json全局基础配置
function loadConfig()
local _jsonConfig = loadjson(config_json)
Config.base = _jsonConfig
local _basedir = Config.base.jsonPath
Config.realIpFrom_Mod = loadjson(_basedir.."realIpFrom_Mod.json")
Config.ip_Mod = loadjson(_basedir.."ip_Mod.json")
Config.host_method_Mod = loadjson(_basedir.."host_method_Mod.json")
Config.app_Mod = loadjson(_basedir.."app_Mod.json")
Config.referer_Mod = loadjson(_basedir.."referer_Mod.json")
Config.url_Mod = loadjson(_basedir.."url_Mod.json")
Config.header_Mod = loadjson(_basedir.."header_Mod.json")
Config.useragent_Mod = loadjson(_basedir.."useragent_Mod.json")
Config.cookie_Mod = loadjson(_basedir.."cookie_Mod.json")
Config.args_Mod = loadjson(_basedir.."args_Mod.json")
Config.post_Mod = loadjson(_basedir.."post_Mod.json")
Config.network_Mod = loadjson(_basedir.."network_Mod.json")
Config.replace_Mod = loadjson(_basedir.."replace_Mod.json")
--- 将全局配置参数存放到共享内存(config_dict)中
local config_dict = ngx.shared.config_dict
for k,v in pairs(Config) do
if type(v) == "table" then
v = cjson_safe.encode(v)
end
config_dict:safe_set(k,v,0)
end
end
-- 读取所有配置信息(全局配置文件、规则配置文件)
loadConfig()
--- 初始化ip_mod列表
--- 将规则文件ip_Mod中的黑白名单ip读取到dict中
local function set_ip_mod()
local tb_ip_mod = Config.ip_Mod
local _dict = ngx.shared["ip_dict"]
for i,v in ipairs(tb_ip_mod) do
if v.action == "allow" then
_dict:safe_set(v.ip,"allow",0)
elseif v.action == "deny" then
_dict:safe_set(v.ip,"ip_mod deny",0)
else
end
end
end
if Config.base["ip_Mod"] == "on" then
set_ip_mod()
end
init阶段其实还有些其他代码,这里没有说明,用到的时候在说吧