玩下Nginx的GeoIp

Rejector · 2024-10-30 11:21:05 · 27 次点击

玩下Nginx的GeoIp



Nginx使用版本:1.27.2,构建环境:RockyLinux9



一些基础软件包



这里可能会包含其他模块的,懒得分出来了~

dnf一些配置就自行GPT吧,懒得分解了~



dnf --setopt=fastestmirror=True --setopt=deltarpm=True --setopt=max_parallel_downloads=10 --setopt=keepcache=True makecache
dnf -y update
dnf -y in epel-release
dnf -y groupinstall 'Development Tools'
dnf -y in nano wget psmisc cmake go automake gcc gcc-c++ kernel-devel git make tar autoconf \
zlib zlib-devel openssl openssl-devel bzip2 bzip2-devel pcre pcre-devel perl-IPC-Cmd libaio libaio-devel \
brotli-devel glibc-headers glibc-devel libbsd-devel perl-core libxcrypt-compat libtool binutils binutils-gold
dnf clean all

编译构建



直接原仓库拉最新的,个人喜好~

这里只会展示Geo需要的模块

-j$(nproc)会自动根据cpu获取执行线程数,快是会快设备都会短暂卡顿,所以建议上构建机去构建




  1. 拉取libmaxminddb


git clone --depth 1 --recurse-submodules https://github.com/maxmind/libmaxminddb.git libmaxminddb
cd libmaxminddb && ./bootstrap && ./configure
make -j$(nproc) && make install && make clean


  1. 拉取ngx_http_geoip2_module


git clone --depth 1 --recurse-submodules https://github.com/leev/ngx_http_geoip2_module.git ngx_http_geoip2_module


  1. nginxconfigure



configure加上geoip2的动态模块即可

nginx位置:objs/nginx

geoip2位置:objs/ngx_http_geoip2_module.so



--add-dynamic-module=ngx_http_geoip2_module 


  1. 检查nginx



检查无问题之后可直接复制到生产机器

记得加上运行权限chmod +x nginx



objs/nginx -V
nginx version: nginx/1.27.2
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC)
built with OpenSSL 3.1.7+quic 3 Sep 2024
TLS SNI support enabled
configure arguments: --prefix=/home/nginx --with-compat --with-threads --with-file-aio --with-http_v2_module --with-http_v3_module --with-http_ssl_module --with-http_sub_module --with-http_slice_module --with-http_realip_module --with-http_degradation_module --with-http_stub_status_module --with-pcre-jit --with-pcre=../pcre2 --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=../openssl --add-module=../ngx_zstd --add-module=../ngx_brotli --add-dynamic-module=../ngx_http_geoip2_module --with-ld-opt=-ljemalloc


  1. 获取mmdb文件



mmdb是Geo数据库文件,没有这个geoip2无法工作

这里准备了一份脚本可自动下载,至于文件覆盖和动态更新自行增加即可

GeoLite2来源maxmind.com,可自行注册生成LICENSE_KEY

GeoCN来源仓库



#!/bin/sh

# 检查是否提供了 LICENSE_KEY
if [ -z "$LICENSE_KEY" ]; then
echo "错误:未设置LICENSE_KEY。请将其导出为环境变量。"
exit 1
fi

# 设置 MaxMind 的下载地址
BASE_URL="https://download.maxmind.com/app/geoip_download"

echo "下载 GeoLite2-ASN.mmdb..."
curl -L -o "GeoLite2-ASN.mmdb.tar.gz" \
"${BASE_URL}?edition_id=GeoLite2-ASN&license_key=${LICENSE_KEY}&suffix=tar.gz"

if [ $? -eq 0 ]; then
tar -xvzf GeoLite2-ASN.mmdb.tar.gz --strip-components=1 && rm GeoLite2-ASN.mmdb.tar.gz
echo "GeoLite2-ASN.mmdb 已成功下载并提取。"
else
echo "GeoLite2-ASN.mmdb 下载失败。"
exit 1
fi

echo "下载 GeoLite2-City.mmdb..."
curl -L -o "GeoLite2-City.mmdb.tar.gz" \
"${BASE_URL}?edition_id=GeoLite2-City&license_key=${LICENSE_KEY}&suffix=tar.gz"

if [ $? -eq 0 ]; then
tar -xvzf GeoLite2-City.mmdb.tar.gz --strip-components=1 && rm GeoLite2-City.mmdb.tar.gz
echo "GeoLite2-City.mmdb 已成功下载并提取。"
else
echo "GeoLite2-City.mmdb 下载失败。"
exit 1
fi

echo "下载 GeoLite2-Country.mmdb..."
curl -L -o "GeoLite2-Country.mmdb.tar.gz" \
"${BASE_URL}?edition_id=GeoLite2-Country&license_key=${LICENSE_KEY}&suffix=tar.gz"

if [ $? -eq 0 ]; then
tar -xvzf GeoLite2-Country.mmdb.tar.gz --strip-components=1 && rm GeoLite2-Country.mmdb.tar.gz
echo "GeoLite2-Country.mmdb 已成功下载并提取。"
else
echo "GeoLite2-Country.mmdb 下载失败。"
exit 1
fi

echo "下载 GeoCN.mmdb..."
curl -L -o "GeoCN.mmdb" \
"http://github.com/ljxi/GeoCN/releases/download/Latest/GeoCN.mmdb"

if [ $? -eq 0 ]; then
echo "GeoCN.mmdb 已成功下载。"
else
echo "GeoCN.mmdb 下载失败。"
exit 1
fi

echo "所有Geo下载已完成。"
ls -lh

配置案例



这里分享下日志屏蔽海外内容,其他的可自行拓展




  1. 加载Geo模块



构建的时候是动态加载的,所以使用之前得加载so文件,在nginx.conf父配置增加即可

so路径自行修改即可



load_module ngx_http_geoip2_module.so;


  1. 加载Geo数据库



mmdb路径自行修改即可

括号内容的配置问gpt就行这里懒得分解了~



# 加载 GeoLite2 ASN 数据库
geoip2 GeoLite2-ASN.mmdb {
auto_reload 5m;
$geoip2_asn_number autonomous_system_number;
$geoip2_asn_organization autonomous_system_organization;
}
# 加载 GeoLite2 国家数据库
geoip2 GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_country_code country iso_code;
$geoip2_country_name country names en;
}
# 加载 GeoLite2 城市数据库
geoip2 GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_city_name city names en;
$geoip2_postal_code postal code;
$geoip2_latitude location latitude;
$geoip2_longitude location longitude;
$geoip2_region_name subdivisions 0 names en;
}
# 加载 GeoCN CN数据库
geoip2 GeoCN.mmdb {
auto_reload 5m;
$geoip2_cn_isp isp;
$geoip2_cn_city city;
$geoip2_cn_net_type net;
$geoip2_cn_province province;
$geoip2_cn_district district;
}


  1. 屏蔽所有非CN的IP



需要屏蔽的location /xxx的大括号第一行加上即可~

$geoip2_country_code是第2步定义的变量,需要对的上



# 检查国家代码,如果不是CN,则拒绝访问
if ($geoip2_country_code != "CN") {
return 403;
}


  1. 日志配置



这里转成json方便日志系统读取,不需要可让gpt转一下即可~

各种$geoip2_开头的是第2步定义的变量,需要对的上



# 将英文月份缩写映射为数字
map $month $month_num {
"Jan" "01";
"Feb" "02";
"Mar" "03";
"Apr" "04";
"May" "05";
"Jun" "06";
"Jul" "07";
"Aug" "08";
"Sep" "09";
"Oct" "10";
"Nov" "11";
"Dec" "12";
}

# 格式化时间为 yyyy-MM-dd HH:MM:SS
map $time_local $custom_time_local {
default "$time_local"; # 默认格式
"~(?<day>[0-9]{2})/(?<month>[A-Za-z]+)/(?<year>[0-9]{4}):(?<hour>[0-9]{2}):(?<minute>[0-9]{2}):(?<second>[0-9]{2})" "$year-$month_num-$day $hour:$minute:$second";
}

# JSON 日志格式,使用格式化后的时间
log_format main escape=json '{"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"time_local":"$custom_time_local",'
'"request_method":"$request_method",'
'"request":"$request",'
'"server_protocol":"$server_protocol",'
'"status":"$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"bytes_sent":"$bytes_sent",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_time":"$request_time",'
'"server_name":"$server_name",'
'"server_addr":"$server_addr",'
'"connection":"$connection",'
'"connection_requests":"$connection_requests",'
'"geoip2_country_code":"$geoip2_country_code",'
'"geoip2_country_name":"$geoip2_country_name",'
'"geoip2_city_name":"$geoip2_city_name",'
'"geoip2_region_name":"$geoip2_region_name",'
'"geoip2_postal_code":"$geoip2_postal_code",'
'"geoip2_latitude":"$geoip2_latitude",'
'"geoip2_longitude":"$geoip2_longitude",'
'"geoip2_asn_number":"$geoip2_asn_number",'
'"geoip2_asn_organization":"$geoip2_asn_organization",'
'"upstream_addr":"$upstream_addr",'
'"upstream_response_time":"$upstream_response_time",'
'"http_x_forwarded_for":"$http_x_forwarded_for"}';

# 日志位置配置
error_log logs/error.log;
access_log logs/access.log main;


  • 大致效果


{
"remote_addr": "112.57.65.69",
"remote_user": "",
"time_local": "2024-10-30 11:08:32",
"request_method": "GET",
"request": "GET / HTTP/1.1",
"server_protocol": "HTTP/1.1",
"status": "301",
"body_bytes_sent": "162",
"bytes_sent": "356",
"http_referer": "",
"http_user_agent": "DNSPod-Monitor/2.0",
"request_time": "0.000",
"server_name": "xxx.xxx.com",
"server_addr": "10.0.8.14",
"connection": "151379",
"connection_requests": "1",
"geoip2_country_code": "CN",
"geoip2_country_name": "China",
"geoip2_city_name": "",
"geoip2_region_name": "",
"geoip2_postal_code": "",
"geoip2_latitude": "34.77320",
"geoip2_longitude": "113.72200",
"geoip2_asn_number": "9808",
"geoip2_asn_organization": "China Mobile Communications Group Co., Ltd.",
"upstream_addr": "",
"upstream_response_time": "",
"http_x_forwarded_for": ""
}

最后



如果对各位佬有帮助,请帮忙点个赞~

如果需要完整的nginx配置,可查看本人仓库

如果内容有不对的地方欢迎提出,本人渴望进步~


举报· 27 次点击
登录 注册 站外分享
1 条回复  
handsome 限制会员 2024-10-30 11:25:38

感谢大佬教程

返回顶部