教程记录 · ARTICLE

Nginx 如何对特定国家访问限制

Nginx 如何限制国家或地区的访问,本次教程介绍了通过Nginx编译模块、Lua外挂的方式如何去限制不同国家的请求访问。

一、基于Nginx (非编译模块)方式限制

使用编译模块更简单,具体参考:https://nginx.org/en/docs/http/ngx_http_geoip_module.html

1. 安装 GeoIP2 模块

我使用的系统是红帽系,首先DNF或YUM安装

#RedHat 旧分支系列
yum install epel-release -y
yum install nginx-module-geoip2 -y
#RedHat部分新版发行版自带了(检查命令)
ldconfig -p | grep maxmind
#输出 libmaxminddb.so.0 (libc6,x86-64) => /lib64/libmaxminddb.so.0
#Ubuntu
apt install libnginx-mod-http-geoip2
#Nginx 自己编译加参数
--add-dynamic-module=ngx_http_geoip2_module

2. 下载 GeoIP 数据库

可以去官网注册后下载:https://www.maxmind.com/

其他镜像:

URL1

URL2

我们使用国别就可以了,因为需求是判断允许访问的国家。如果有特殊需求同样的写法。

3. Nginx 配置

配置如下,例子是只允许日本访问:

load_module modules/ngx_http_geoip2_module.so;

http {

	geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
		$geoip_country_code country iso_code;
	}


	map $geoip_country_code $allowed_country {
		default 0;
		JP 1;
	}

    #网站配置
	server {

		listen 80;

		if ($allowed_country = 0) {
			return 403;
		}

		....

	}

}

二、基于Nginx Lua方式限制

此方法依赖libmaxminddb.so,如果没有请自行安装:

#检查,如果是 so.0 是只有运行库,没有开发链接文件 需要额外安装开发包
[root@***** geoip]# ldconfig -p | grep maxmind
	libmaxminddb.so.0 (libc6,x86-64) => /lib64/libmaxminddb.so.0
#安装开发包
dnf install libmaxminddb-devel -y

1、检查当前Nginx是否包含Lua模块

# 检查命令(V大写)
nginx -V

如果发现模块包含“--add-module=/www/server/nginx/src/lua_nginx_module” 即可。

2. 克隆lua-resty-maxminddb (读取数据库lua包)

测试环境为了方便使用宝塔安装的nginx 1.31版本,工作路径其实是存在的。

#克隆项目包
cd /www/server/nginx
git clone https://github.com/anjia0532/lua-resty-maxminddb.git
#复制到工作路径
mkdir -p /www/server/nginx/lib/lua/resty/
cp lua-resty-maxminddb/lib/resty/maxminddb.lua /www/server/nginx/lib/lua/resty/
#检查
ls /www/server/nginx/lib/lua/resty/

3. nginx 配置&测试

#打开Nginx配置路径(宝塔环境可以跳过,因为已经有这个配置了,而且是同一个路径)
vi /www/server/nginx/conf/nginx.conf
#在http下增加,如果已经有了添加“;”后继续补上这个地址,nginx只允许设置一个
lua_package_path "/www/server/nginx/lua/?.lua;;";
#lua_package_path 多路径用“;”分割。

测试require

mkdir -p /www/server/nginx/lua
vi /www/server/nginx/lua/test.lua

#内容
local mmdb = require "resty.maxminddb"
ngx.say("ok")

#找一个server中添加
location /lua-test {
    default_type text/html;
    charset utf-8;

    content_by_lua_file /www/server/nginx/lua/test.lua;
}

#nginx 测试
nginx -t
#nginx reload 后访问
nginx -s reload

4. GeoIP数据导入

数据和第一章下载数据库一致,将数据库文件上传到服务器即可。

# 创建文件夹
mkdir -p /www/geoip

#下载到此目录,也可以自己上传
wget https://git.io/GeoLite2-Country.mmdb

#写一个新的lua脚本
vi /www/server/nginx/lua/geo.lua

geo.lua

ngx.header.content_type = "text/html; charset=utf-8"

local maxminddb = require "resty.maxminddb"

maxminddb.init("/www/geoip/GeoLite2-Country.mmdb")

local data = maxminddb.lookup(ngx.var.remote_addr)

if data then
    ngx.say("IP: ", ngx.var.remote_addr)
    ngx.say("<br>")
    ngx.say("Country: ", data.country.iso_code)
else
    ngx.say("unknown")
end

记得一定要重载nginx

nginx -s reload

访问测试:

5. 写一个只允许中国访问的脚本

local maxminddb = require "resty.maxminddb"

-- 初始化数据库
maxminddb.init("/www/geoip/GeoLite2-Country.mmdb")

-- 获取客户端IP
local ip = ngx.var.remote_addr

-- 查询国家
local res = maxminddb.lookup(ip)

if not res or not res.country then
    ngx.exit(403)
end

local country = res.country.iso_code

-- 只允许中国
if country ~= "CN" then
    ngx.status = 403
    ngx.say("您所在的国家禁止访问哦!")
    ngx.exit(403)
end
#允许中日美
local allow = {
    CN = true,
    JP = true,
    US = true
}

if not allow[country] then
    ngx.exit(403)
end

6. 生产优化

nginx支带了内存字典,可以把数据库放入内存里面,分配10M就够,国家数据库只有8M左右。和上面每个请求请求一次都要单独创建更高效。

# nginx配置
http {

    lua_shared_dict geoip 10m;

    init_by_lua_block {

        local maxminddb = require "resty.maxminddb"

        maxminddb.init(
            "/www/geoip/GeoLite2-Country.mmdb"
        )
    }

}

#lua脚本
local maxminddb = require "resty.maxminddb"

local res = maxminddb.lookup(
    ngx.var.remote_addr
)

如果要全局生效,就把脚本放到nginx全局配置文件,http下

http{
  .......
  access_by_lua_file /www/server/nginx/lua/country_allow.lua;
  .......
}

← 返回内容

COMMENTS

评论 0

提交后需审核通过才会显示 · 登录后使用账户昵称