• Nginx使用Lua


    文章来自
    Nginx安装lua支持
    openresty
    黑名单

    前提条件
    安装LuaJIT,查看【工具/LuaJIT】笔记

    Nginx-Lua支持

    • 下载解压ngx_devel_kit
    wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
    tar -xzvf v0.3.0.tar.gz
    
    • 下载解压lua-nginx-module
    wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz
    tar -xzvf v0.10.8.tar.gz
    
    • 配置,编译,安装
    # 前面的步骤查看【nginx】笔记
    
    #注意ngx_devel_kit和lua-nginx-module以实际解压路径为准
    ./configure 
    --add-module=/opt/soft/ngx_devel_kit-0.3.0 
    --add-module=/opt/soft/lua-nginx-module-0.10.8
    --prefix=/home/admin/server/nginx
    
    make
    make install
    

    配置文件

    • 把命令写在配置文件里
    location /hello {
       default_type 'text/plain';
       content_by_lua 'ngx.say("hello, lua")';
       charset utf-8;
    }
    
    • 把命令外部配置
    #lua文件方式
    #在server 中添加一个localtion
    location /lua {
        default_type 'text/html';
        lua_code_cache off; # 把缓存关了,这样修改lua文件就不用重启nginx了
        content_by_lua_file conf/lua/test.lua; #相对于nginx安装目录
        charset utf-8;
    }
    
    # conf/lua/test.lua
    ngx.say("hello world");
    
    • 服务启动后访问地址就行

    大佬封装好的工具包

    功能插件使用,需要提前安装在LuaJIT才行

    • 在server上添加配置
    # 这个?是固定写法
    # 自己写的或者大神写的lua文件
    lua_package_path "/usr/local/lualib/?.lua;;";
    # 官方的插件
    lua_package_cpath "/usr/local/lualib/?.so;;";
    
    service {
       ...
    }
    
    • 使用
    # 引入cjson,这个不需要文件路径,安装cjson查看【LuaJIT】笔记
    local cjson = require "cjson"
    
    # 引入大佬的工具包
    # 文件夹resty加里面的lua文件名
    local redis = require "resty.redis"
    local mysql = require "resty.mysql"
    ...
    

    获取访问nginx的请求数据

    • Get
    local method = ngx.var.request_method;
    local headers = ngx.req.get_headers();
    local uri_args = ngx.req.get_uri_args();
     
    if method == "GET" then
        ngx.say("id:", uri_args["id"]);
        ngx.say("gender:", uri_args["gender"]);
        ngx.say("user-agent:", headers["user-agent"]);
    end
    
    • Post
    local cjson = require "cjson";
    local method = ngx.var.request_method;
     
    if method == "POST" then
        ngx.req.read_body();
        local data = ngx.req.get_body_data();
        local reqObj = cjson.decode(data);
        ngx.say("username:", reqObj["username"]);
        ngx.say("password:", reqObj["password"]);
    end
    

    黑名单,需要配合redis使用

    • 设置黑名单缓存,不用每个请求都去获取一次
    http {
        # 缓存大小5m
        lua_shared_dict forbidden_list 5m;
        
        location /lua {
            # lua_code_cache off;
            access_by_lua_file conf/lua/forbidden_list.lua;
            default_type 'text/html';
            content_by_lua 'ngx.say("hello world")';
        }
    }
    
    • lua
    local redis = require("resty.redis")
    local ngx_log = ngx.log
    local ngx_ERR = ngx.ERR
    local ngx_INFO = ngx.INFO
    local ngx_exit = ngx.exit
    local ngx_var = ngx.var
    
    -- 黑名单缓存60秒
    local cache_idle = 60
    local forbidden_list = ngx.shared.forbidden_list
    
    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获取ip黑名单列表
    local function get_forbidden_list()
    	local red = redis:new()
    	red:set_timeout(1000)
    	local ip = "127.0.0.1"
    	local port = 6379
    	local password = "password"
    	local ok, err = red:connect(ip, port)
    	if not ok then
    		ngx_log(ngx_ERR, "connect to redis error : ", err)
    		close_redis(red)
    		return
    	end
    	
    	local res, err = red:auth(password)
        if not res then
            ngx_log(ngx_ERR, "failed to authenticate: ", err)
    		close_redis(red)
            return
        end
    	
    	local resp, err = red:smembers("forbidden_list")
    	if not resp then
    		ngx_log(ngx_ERR, "get redis connect error : ", err)
    		close_redis(red)
    		return
    	end
    	-- 得到的数据为空处理
    	if resp == ngx.null then
    		resp = nil
    	end
    	close_redis(red)
    	
    	return resp
    end
    
    -- 刷新黑名单
    local function reflush_forbidden_list()
    	local current_time = ngx.now()
    	local last_update_time = forbidden_list:get("last_update_time");
    	
    	if last_update_time == nil or last_update_time < (current_time - cache_idle) then
    		local new_forbidden_list = get_forbidden_list();
    		if not new_forbidden_list then
    			return
    		end
    		
    		forbidden_list:flush_all()
    		for i, forbidden_ip in ipairs(new_forbidden_list) do
    			forbidden_list:set(forbidden_ip, true);
    		end
    		forbidden_list:set("last_update_time", current_time);
    	end
    end
    
    
    reflush_forbidden_list()
    local ip = ngx_var.remote_addr
    if forbidden_list:get(ip) then
    	ngx_log(ngx_INFO, "forbidden ip refused access : ", ip)
    	return ngx_exit(ngx.HTTP_FORBIDDEN)
    end
    
    • 手动执行redis操作
    # 添加黑名单,然后访问
    SADD forbidden_list "127.0.0.1"
    
    # 移除黑名单,然后访问
    SREM forbidden_list "127.0.0.1"
    

    动态黑名单思路
    logstash+elasticsearch的组合,实现logstash实时读取nginx的访问日志access.log,elasticsearch储存并聚合访问日志中的访问记录,再由一个分析程序定时统计分析访问记录后判断出要加入黑名单的ip,然后将ip储存到redis中的ip黑名单列表

  • 相关阅读:
    互联网人25岁毕业 拿一万块钱月薪 (转)
    在windows平台编译openAL Android 库
    lua简单包装
    libevent 简单学习
    cocos2dx中使用tolua++使lua调用c++函数
    《OpenGL超级宝典》编程环境配置
    快速排序、归并排序、堆排序三种算法性能比较
    二叉树的三种遍历的递归与非递归算法
    boost之bind
    boost之内存管理
  • 原文地址:https://www.cnblogs.com/pengdt/p/13062526.html
Copyright © 2020-2023  润新知