通过 nginx 实现服务的地区限制
通过 nginx 限制服务的可访问地区,主要利用 GeoIP 数据库识别客户 IP 的归属地,进而对不通归属地的访问请求分流处理。
以限制中国地区访问为例。为了实现目标,我们需要以下“原料”:
- GeoLite2-Country 和 GeoLite2-City(可选)数据库
- GeoLite2-Country 数据库包含了全球范围内的IPv4和IPv6地址及其对应国家的地理位置信息,每个条目至少包含国家码(ISO 3166-1 alpha-2标准)。
- GeoLite2-City 数据库则更加详细,除了国家信息外,还提供了城市名称、行政区划、经纬度、时区、ISP信息等更细致的地理位置数据。
- libmaxminddb-devel 一个开发库及相关的头文件包,它提供了对 MaxMind GeoIP2 数据库格式的读取支持。这个库允许开发者编写程序来解析 MaxMind 提供的 GeoIP2 数据库,从而获取地理位置信息,包括但不限于国家、城市、经纬度、时区等与IP地址关联的数据。
- ngx_http_geoip2_module Nginx 的一个第三方模块,与 libmaxminddb 库配合使用,实现在 Nginx 服务器层面根据客户端 IP 地址获取其地理位置信息的功能。
服务处理流程:
客户端请求 -> 路由 -> nginx (ngx_http_geoip2_module 调用 libmaxminddb-devel 功能实现访问本地 Geo 数据库,得到用户 IP 所属的国家码等信息) -> 服务/拦截
一、GeoIP
1.1 安装 libmaxminddb-devel
yum install libmaxminddb-devel -y
1.2 下载 geoip2 模块
本文解压至:/usr/local/ngx_http_geoip2_module/
1.3 下载 GeoLite2 数据库
本文解压至:/usr/share/GeoIP/
二、nginx
2.1 下载 nginx 源码
上传到服务器上解压,进入源码根目录。将 auto 目录下的 configure cp 一份到源码根目录。
2.2 编译 nginx
注意 --conf-path
等路径配置。此处假设服务器已经通过 yum install nginx
之类的命令安装 nginx,相应的配置文件位一般默认位于 /etc/nginx/nginx.conf
。要确定原本的 nginx 的配置信息,请运行 nginx -V
。若你原本就是自己编译的 nginx,想必我就不用多说什么了。
[root@localhost nginx-release-1.20.1]# ./configure \
--prefix=/usr/share/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/lib/nginx/tmp/client_body \
--http-proxy-temp-path=/var/lib/nginx/tmp/proxy \
--http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi \
--http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi \
--http-scgi-temp-path=/var/lib/nginx/tmp/scgi \
--with-http_ssl_module \
--with-stream \
--with-http_stub_status_module \
--add-module=/usr/local/ngx_http_geoip2_module \
其中关键是:
--add-module=/usr/local/ngx_http_geoip2_module
而后编译,make 即可:
[root@localhost nginx-release-1.20.1]# make
2.3 替换 nginx
首先备份原程序:
cp /usr/sbin/nginx /usr/sbin/nginx-bkp
结束原进程:
pkill nginx
替换程序为新编译的程序(y回车确认):
cp objs/nginx /usr/sbin/
启动 nginx:
systemctl start nginx
2.4 配置 nginx
配置效果为,中国大陆地区访问,响应404。注意替换 GeoLite2 数据库的路径为你实际的路径。
这里 geoip2 我指定了 source 为 $http_x_real_ip country
,因为 geoip2 默认使用 $remote_ip
进行查询,而我的服务经过了(很多重)反向代理,默认的 remote_ip 只能记录到 127.0.0.1 或是到达我的首个服务器前的最上一级路由 IP。
更多示例用法请参考:https://github.com/leev/ngx_http_geoip2_module?tab=readme-ov-file#example-usage
http {
...
# GeoIP
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$http_x_real_ip country iso_code;
$geoip2_data_country_name source=$http_x_real_ip country names en;
}
map $geoip2_data_country_code $is_CN {
default no;
CN yes;
}
...
server {
...
if ($is_CN = yes) {
return 404;
}
...
}
...
}
三、更进一步
直接 404 有点不太友好了。
为 nginx 的 configure 加上以下参数使得 nginx 支持 sub_filter / subs_filter(可选)功能,以方便地使用静态页面展示用户所在地区和站点提示。
(Github Release - ngx_http_substitutions_filter_module-0.6.4)
--with-http_sub_module \
--add-module=/usr/local/ngx_http_substitutions_filter_module-0.6.4
在 geoip2 块中增加地区名映射:
$geoip2_data_country_name source=$http_x_real_ip country names en;
修改 server 块内容
server {
...
sub_filter '##COUNTRY##' '$geoip2_data_country_name';
if ($is_CN = yes) {
rewrite ^ /restricted.html break;
}
...
}
小猴寄 restricted.html 页面供参考:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>区域受限提示</title>
<style>
body {
background-color: #212529;
color: #fff;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding-top: 20vh;
}
.container {
text-align: center;
padding: 40px;
max-width: 600px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 10px;
background-color: #343a40;
}
h1 {
font-size: 2em;
margin-bottom: 20px;
}
p {
font-size: 1.2em;
line-height: 1.6;
}
@media (max-width: 767px) {
.container {
padding: 20px;
}
h1 {
font-size: 1.5em;
}
p {
font-size: 1em;
}
}
</style>
</head>
<body>
<div class="container">
<h1>区域受限提示</h1>
<p>受法律法规限制,本站内容暂不对您所在地区(##COUNTRY##)开放。</p>
<p>由此带来的不便,敬请谅解!</p>
<p style="text-align: right;">——小猴寄</p>
</div>
</body>
</html>
重载配置
nginx -s reload
四、效果
- 感谢你赐予我前进的力量