openresty 协议分流

最后由 Tabing010102 更新于 2022年11月24日

需求:

openresty根据HTTP协议类型/版本/IP Country分流至不同后端(处理TLS,需部署证书,IPCountry信息使用GeoIP2)

为了使用GeoIP Country信息,我们需要GeoIP2库(libmaxminddb),GitHub地址:点我跳转

下载最新release,解压编译安装:

wget "https://github.com/maxmind/libmaxminddb/releases/download/1.7.1/libmaxminddb-1.7.1.tar.gz"
tar zxvf libmaxminddb-1.7.1.tar.gz
cd libmaxminddb-1.7.1
./configure
make && make install
# 最后刷新动态链接库缓存,否则可能会出现找不到libmaxminddb.so
ldconfig

由于libmaxminddb默认安装在/usr/local/lib中,CentOS 7默认并不会在此文件夹搜索,因此需要将/usr/local/lib添加至搜索路径,再执行ldconfig

echo "/usr/local/lib" >> /etc/ld.so.conf.d/local.conf

接下来下载MaxMind的GeoIP2数据库文件(mmdb格式),对于只识别国家的情况,下载GeoLite2 Country即可,然后将其解压至/var/lib/GeoIP中(或者其他任何地方,需对代码进行相应更改)

接下来安装openresty和opm,openresty官方提供了大部分Linux发行版的包(官方package安装指引),安装openrestyopenresty-opm

接下来使用opm安装geoip的LuaJIT(链接):opm get leafo/geoip

openretsy默认安装在/usr/local/openresty中,为了使用GeoIP2库,需要在openresty安装目录下的lualib文件夹下创建geoip_helper.lua(摘自opm页面说明,使加载好的GeoIP2数据库常加载,而不是每接收一个请求重新加载一遍GeoIP2数据库;也可使用其他名字,须在配置中进行相应修改):

local geoip = require "geoip.mmdb"

return {
  country_db = assert(geoip.load_database("/var/lib/GeoIP/GeoLite2-Country.mmdb")),
  -- load more databases if necessary:
  -- asnum_db = ...
  -- etc.
}

接下来在nginx/conf文件夹中创建配置文件stream.conf,其中50001为对IP为US的客户端的服务器端口,50002为http2服务,50003为http服务,50099为其他类型协议的服务端口:

stream {
    resolver 1.1.1.1;
    lua_add_variable $ProxyPort;

    server {
        listen 443 ssl reuseport;
        listen [::]:443 ssl reuseport;

        # ssl cert config
        ssl_certificate "path/to/fullchain.cer";
        ssl_certificate_key "path/to/private.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 10m;
        # ssl protocol config
        ssl_protocols TLSv1.3;
        ssl_prefer_server_ciphers off;

        # proxy_buffer_size 256k;
        
        # preread size
        preread_buffer_size 58;

        preread_by_lua_block {
            local sock, err = ngx.req.socket()
            -- if sock then
            --     ngx.log(ngx.NOTICE, "got the request socket")
            -- else
            --     ngx.log(ngx.NOTICE, "failed to get the request socket: ", err)
            -- end

            local data, err = sock:peek(16)
            -- local data2, err = sock:peek(58)

            -- get country iso code
            local result = require("geoip_helper").country_db:lookup_value(ngx.var.remote_addr, "country", "iso_code")
            -- ngx.log(ngx.NOTICE, "result = " .. result)

            if result and string.match(result, "US") then
                -- for US IP
                -- ngx.log(ngx.NOTICE, "US -> 50001")
                ngx.var.ProxyPort = "50001"
            elseif string.match(data, "HTTP/2.0") then
                -- for http2
                -- ngx.log(ngx.NOTICE, "HTTP/2.0 -> 50002")
                ngx.var.ProxyPort = "50002"
            elseif string.match(data, "HTTP") then
                -- for http
                -- ngx.log(ngx.NOTICE, "HTTP -> 50003")
                ngx.var.ProxyPort = "50003"
            -- elseif string.byte(data2:sub(57), 1, 2) == 13 then
            --     -- for tj
            --     -- ngx.log(ngx.NOTICE, "tj -> 50004")
            --     ngx.var.ProxyPort = "50004"
            else
                -- for other protocol
                -- ngx.log(ngx.NOTICE, "other -> 50099")
                ngx.var.ProxyPort = "50099"
            end
        }

        proxy_pass 127.0.0.1:$ProxyPort;

        access_log off;
    }
}

最后需要将nginx/conf中的主配置文件加入include stream.conf;,重新启动openresty使配置生效

Visits: 45

发布者:Tabing010102

???

留下评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据