Loading... 此文章是Nginx的GeoIP2模块和MaxMind国家IP库相互结合,达到客户端IP访问的一个数据记录以及分析,同时还针对一些业务需求做出对Nginx中间件的控制,如:防盗链、防爬虫、限制访问速度、限制连接数等 该篇文章是从一个热爱搞技术的博主[StephenJose_Dai](https://www.daishenghui.club)文章中学习并实验后编写的,在此非常感谢这位博主! # 环境 | 名称+版本 | 官方下载链接 | 本地下载链接 | | :------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: | | CentOS7.9 | [http://isoredirect.centos.org/centos/7/isos/x86_64/](http://isoredirect.centos.org/centos/7/isos/x86_64/) | 无 | | Nginx1.22 | [https://nginx.org/download/nginx-1.22.1.tar.gz](https://nginx.org/download/nginx-1.22.1.tar.gz) | [https://resource.if010.com/geoip/nginx-1.22.1.tar.gz](https://resource.if010.com/geoip/nginx-1.22.1.tar.gz) | | GeoIP2模块v3.3 | [https://github.com/leev/ngx_http_geoip2_module/releases](https://github.com/leev/ngx_http_geoip2_module/releases) | [https://resource.if010.com/geoip/ngx_http_geoip2_module-3.3.tar.gz](https://resource.if010.com/geoip/ngx_http_geoip2_module-3.3.tar.gz) | | MaxMind国家IP库 | [https://www.maxmind.com/en/home](https://www.maxmind.com/en/home) | 无 | | libmaxminddb 1.7.1 | [https://github.com/maxmind/libmaxminddb/releases](https://github.com/maxmind/libmaxminddb/releases) | [https://resource.if010.com/geoip/libmaxminddb-1.7.1.tar.gz](https://resource.if010.com/geoip/libmaxminddb-1.7.1.tar.gz) | | geoipupdate 6.0.0 | [https://github.com/maxmind/geoipupdate/releases/download/v6.0.0/geoipupdate_6.0.0_linux_386.tar.gz](https://github.com/maxmind/geoipupdate/releases/download/v6.0.0/geoipupdate_6.0.0_linux_386.tar.gz) | [https://resource.if010.com/geoip/geoipupdate_6.0.0_linux_386.tar.gz](https://resource.if010.com/geoip/geoipupdate_6.0.0_linux_386.tar.gz) | > 注:libmaxminddb工具是用于解析MaxMind国家IP库文件的。 # 开搞 > 约定:所有安装包和准备材料都放在了`/data`目录下。 ## 编译安装libmaxminddb ```bash tar -zxvf libmaxminddb-1.7.1.tar.gz cd libmaxminddb-1.7.1 ./configure make && make check && make install ldconfig ``` 如果安装后,您收到一个`libmaxminddb.so.0`丢失的错误,您可能需要将前缀中的 lib 目录添加到您的库路径中。在使用默认前缀 ( `/usr/local`) 的大多数 Linux 发行版上,您可以通过运行以下命令来执行此操作: ```bash sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf" ldconfig ``` ## 解压GeoIP2 ```bash tar -zxvf ngx_http_geoip2_module-3.3.tar.gz mv ngx_http_geoip2_module-3.3 /usr/local/ ``` > 注意:因为这里使用的是Nginx1.22的版本,所以GeoIP2只能用3.3版本的,不然会报错! ## 编译安装Nginx前的一些依赖准备 我们这里编译安装Nginx需要用的有openssl、pcre、zlib、gcc,在此之前我们先解压编译包并放到指定目录,然后使用rpm安装gcc 这里的用到的依赖分享到了CSDN上,有需要的小伙伴可以自取[https://download.csdn.net/download/qq_32262243/88450296](https://download.csdn.net/download/qq_32262243/88450296) ```bash tar zxf pcre-8.42.tar.gz mv pcre-8.42 /usr/local/ tar zxf openssl-1.1.0h.tar.gz mv openssl-1.1.0h /usr/local/ tar zxf zlib-1.2.11.tar.gz mv zlib-1.2.11 /usr/local/ # rpm安装gcc rpm -ivh libstdc++-devel-4.8.5-44.el7.x86_64.rpm rpm -ivh gcc-c++-4.8.5-44.el7.x86_64.rpm ``` ## 编译安装Nginx ```bash tar -zxvf nginx-1.22.1.tar.gz cd /data/nginx-1.22.1 #配置编译 ./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_sub_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-stream --with-openssl=/usr/local/openssl-1.1.0h/ --with-pcre=/usr/local/pcre-8.42/ --with-zlib=/usr/local/zlib-1.2.11/ --add-module=/usr/local/ngx_http_geoip2_module-3.3 # 编译并安装 make && make install ``` ## 注册MaxMind帐号并下载国家IP数据库 ![注册页面](https://resource.if010.com/nginx_geoip_01.png) ![下载地址库入口](https://resource.if010.com/nginx_geoip_02.png) ![下载链接位置](https://resource.if010.com/nginx_geoip_03.png) ## 将下载的数据库解压并放到指定位置 这个位置并不一定说是要在哪里,只要到时候你Nginx调用的时候路径是对的就行 ```bash mkdir -p /usr/local/nginx/IPData/ tar -zxvf GeoLite2-Country_20231020.tar.gz cd GeoLite2-Country_20231020 mv GeoLite2-Country.mmdb /usr/local/nginx/IPData/ ``` ## 配置Nginx实现禁止境外IP访问、防盗链、防爬虫、限制访问速度、限制连接数 创建虚拟主机配置文件目录和缓存目录 ```bash mkdir -p /usr/local/nginx/conf/v_host/ mkdir -p /usr/local/nginx/cache ``` 编辑Nginx主配置文件`vim /usr/local/nginx/conf/nginx.conf` ```bash user nobody; # 配置Nginx线程数,这里设置为自动 worker_processes auto; error_log logs/error.log; pid logs/nginx.pid; events { # 定义每个线程可以处理1024个连接请求 worker_connections 1024; } http { log_format main '$remote_addr - [location: $geoip2_data_country_code $geoip2_country_name $geoip2_data_city_name $geoip2_data_province_name $geoip2_data_province_isocode $geoip2_continent_code] - $remote_user [$time_local] requesthost:"$http_host"; "$request" requesttime:"$request_time"; ' '$status $body_bytes_sent "$http_referer" - $request_body ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; # 关闭Nginx版本号显示 server_tokens off; proxy_buffering off; keepalive_timeout 300; keepalive_requests 200; client_max_body_size 20M; types_hash_max_size 2048; fastcgi_connect_timeout 300s; fastcgi_send_timeout 300s; fastcgi_read_timeout 300s; fastcgi_buffer_size 512k; fastcgi_buffers 10 512k; fastcgi_busy_buffers_size 1024k; fastcgi_temp_file_write_size 1024k; open_file_cache max=65535 inactive=60s; open_file_cache_valid 80s; server_names_hash_bucket_size 2048; client_header_buffer_size 128k; client_body_buffer_size 512k; large_client_header_buffers 4 128k; proxy_hide_header X-Powered-By; proxy_hide_header Server; proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; proxy_buffer_size 4k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; proxy_temp_path cache/mytemp_cache; proxy_cache_path cache/mytest_cache levels=1:2 keys_zone=mytest:20m inactive=24h max_size=1000m; proxy_intercept_errors on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_comp_level 4; gzip_types text/plain application/javascript image/png text/css text/xml text/vnd.wap.wml text/x-component application/x-javascript image/gif image/jpeg application/atom+xml application/rss+xml application/octet-stream application/x-rar-compressed application/json; gzip_http_version 1.1; gzip_vary on; gzip_disable "msie6"; gzip on; include mime.types; default_type application/octet-stream; # 配置国家IP库 geoip2 /usr/local/nginx/IPData/GeoLite2-Country.mmdb{ auto_reload 5m; $geoip2_metadate_country_build metadata build_epoch; $geoip2_data_country_code country iso_code; $geoip2_country_name country names en; } # 配置城市IP库 geoip2 /usr/local/nginx/IPData/GeoLite2-City.mmdb { auto_reload 5m; $geoip2_data_city_name city names en; $geoip2_data_province_name subdivisions 0 names en; $geoip2_data_province_isocode subdivisions 0 iso_code; $geoip2_continent_code continent code; } #配置规则,默认不允许所有IP访问,只允许中国IP访问 map $geoip2_data_country_code $allowed_country { default no; CN yes; } #设置白名单,在下列白名单中不限速 geo $is_whitelist { default 0; 172.17.0.0/16 1; } map $is_whitelist $limit_key { 1 ""; 0 $binary_remote_addr; } # 设置连接数 limit_conn_zone $binary_remote_addr zone=perip:10m; # 设置限制连接数,每秒150个连接数 limit_req_zone $binary_remote_addr zone=myRateLimit:10m rate=150r/s; # 设置限制连接数,每秒2000个连接数 limit_req_zone $binary_remote_addr zone=mywebRateLimit:10m rate=2000r/s; # 设置限制连接数,每秒200个连接数 limit_req_zone $binary_remote_addr zone=my26051RateLimit:10m rate=200r/s; # 引用v_host中的指定conf配置文件 include /usr/local/nginx/conf/v_host/*.conf; } ``` 创建编辑虚拟主机配置文件`vim /usr/local/nginx/conf/v_host/test.if010.com.conf` ```bash # HTTP配置 server { listen 80; charset utf-8; server_name test.if010.com; client_max_body_size 300m; access_log /usr/local/nginx/logs/test.if010.com_access.log main; error_log /usr/local/nginx/logs/test.if010.com_error.log debug; # 当访问http时,强制跳转到https error_page 497 https://test.if010.com$uri?$args; # 添加客户端的IP头 add_header client-country $geoip2_data_country_code; # 启用压缩,压缩等级为9级,压缩text/css text/plan text/xml application/javascript # application/x-javascript application/html application/xml image/png image/jpg # image/jpeg image/gif image/webp image/svg+xml 这些格式的文件 gzip on; gzip_comp_level 9; gzip_types text/css text/plan text/xml application/javascript application/x-javascript application/html application/xml image/png image/jpg image/jpeg image/gif image/webp image/svg+xml; # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回452状态码给客户端; if ($geoip2_data_country_code = no ) { return 452; } location /{ root /usr/local/nginx/html; index index.html; try_files $uri $uri/ /index.html?s=$uri&$args; # 限制连接数为nginx.conf配置的zone=myRateLimit的值(每秒150个请求数),允许突然爆发的连接数10个并且是马上执行没有延迟 limit_req zone=myRateLimit burst=10 nodelay; # 限制每个IP每秒连接数为nginx.conf配置的zone=perip的值(单个IP允许150个请求数) limit_conn perip 150; # 如果超过设定的每秒150个连接数这个阈值,则返回448状态码给客户端 limit_req_status 448; # 如果超过设定的每个IP每秒150个连接数这个阈值,则返回449状态码给客户端 limit_conn_status 449; # 限制客户端速度只能到150k limit_rate 150k; # 防盗链,如果请求的头不是test.if010.com就是无效的,则返回449状态码给客户端 valid_referers none blocked test.if010.comm; if ($invalid_referer) { return 449; } # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回452状态码给客户端 if ($geoip2_data_country_code = no ) { return 452; } # 防爬虫,如果UA是底下任意一个值,就判定为蜘蛛爬虫,则返回453给客户端 if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp|qihoobot|Scrubby|YodaoBot|yahoo-blogs/v3.9|Gigabot|yahoo-mmcrawler|Teoma|Robozilla|Bingbot|Slurp|Baiduspider|Googlebot|googlebot-mobile|googlebot-image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo!Slurp|Yahoo!Slurp China|YoudaoBot|Sosospider|MSNBot|ia_archiver|twiceler|psbot") { return 453; } } # 错误页配置,如果状态码是下列的值,就显示我配置的页面 error_page 400 401 402 403 404 500 502 503 504 /error.html; location = /error.html { root /usr/local/html; # 限制连接数为nginx.conf配置的zone=myRateLimit的值(每秒150个请求数),允许突然爆发的连接数10个并且是马上执行没有延迟 limit_req zone=myRateLimit burst=10 nodelay; # 限制每个IP每秒连接数为nginx.conf配置的zone=perip的值(单个IP允许150个请求数) limit_conn perip 150; # 如果超过设定的每秒150个连接数这个阈值,则返回448状态码给客户端 limit_req_status 448; # 如果超过设定的每个IP每秒150个连接数这个阈值,则返回449状态码给客户端 limit_conn_status 449; # 限制客户端速度只能到150k limit_rate 150k; # 防盗链,如果请求的头不是test.if010.com就是无效的,则返回449状态码给客户端 valid_referers none blocked test.if010.com; if ($invalid_referer) { return 449; } # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回452状态码给客户端 if ($geoip2_data_country_code = no ) { return 452; } # 防爬虫,如果UA是底下任意一个值,就判定为蜘蛛爬虫,则返回453给客户端 if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp|qihoobot|Scrubby|YodaoBot|yahoo-blogs/v3.9|Gigabot|yahoo-mmcrawler|Teoma|Robozilla|Bingbot|Slurp|Baiduspider|Googlebot|googlebot-mobile|googlebot-image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo!Slurp|Yahoo!Slurp China|YoudaoBot|Sosospider|MSNBot|ia_archiver|twiceler|psbot") { return 453; } } } # HTTPS配置 server { listen 443 ssl; charset utf-8; server_name test.if010.com; client_max_body_size 300m; ssl_certificate /usr/local/nginx/cert/test.if010.com.pem; ssl_certificate_key /usr/local/nginx/cert/test.if010.com.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; access_log /usr/local/nginx/logs/test.if010.com_access.log main; error_log /usr/local/nginx/logs/test.if010.com_error.log debug; # 添加客户端的IP头 add_header client-country $geoip2_data_country_code; # 启用压缩,压缩等级为9级,压缩text/css text/plan text/xml application/javascript # application/x-javascript application/html application/xml image/png image/jpg # image/jpeg image/gif image/webp image/svg+xml 这些格式的文件 gzip on; gzip_comp_level 9; gzip_types text/css text/plan text/xml application/javascript application/x-javascript application/html application/xml image/png image/jpg image/jpeg image/gif image/webp image/svg+xml; # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回452状态码给客户端; if ($geoip2_data_country_code = no ) { return 452; } location /{ root /usr/local/nginx/html; index index.html; try_files $uri $uri/ /index.html?s=$uri&$args; # 限制连接数为nginx.conf配置的zone=myRateLimit的值(每秒150个请求数),允许突然爆发的连接数10个并且是马上执行没有延迟 limit_req zone=myRateLimit burst=10 nodelay; # 限制每个IP每秒连接数为nginx.conf配置的zone=perip的值(单个IP允许150个请求数) limit_conn perip 150; # 如果超过设定的每秒150个连接数这个阈值,则返回448状态码给客户端 limit_req_status 448; # 如果超过设定的每个IP每秒150个连接数这个阈值,则返回449状态码给客户端 limit_conn_status 449; # 限制客户端速度只能到150k limit_rate 150k; # 防盗链,如果请求的头不是test.if010.com就是无效的,则返回449状态码给客户端 valid_referers none blocked test.if010.com; if ($invalid_referer) { return 449; } # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回451状态码给客户端 if ($geoip2_data_country_code = no ) { return 452; } # 防爬虫,如果UA是底下任意一个值,就判定为蜘蛛爬虫,则返回453给客户端 if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp|qihoobot|Scrubby|YodaoBot|yahoo-blogs/v3.9|Gigabot|yahoo-mmcrawler|Teoma|Robozilla|Bingbot|Slurp|Baiduspider|Googlebot|googlebot-mobile|googlebot-image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo!Slurp|Yahoo!Slurp China|YoudaoBot|Sosospider|MSNBot|ia_archiver|twiceler|psbot") { return 453; } } # 错误页配置,如果状态码是下列的值,就显示我配置的页面 error_page 400 401 402 403 404 500 502 503 504 /error.html; location = /error.html { root /usr/local/html; # 限制连接数为nginx.conf配置的zone=myRateLimit的值(每秒150个请求数),允许突然爆发的连接数10个并且是马上执行没有延迟 limit_req zone=myRateLimit burst=10 nodelay; # 限制每个IP每秒连接数为nginx.conf配置的zone=perip的值(单个IP允许150个请求数) limit_conn perip 150; # 如果超过设定的每秒150个连接数这个阈值,则返回448状态码给客户端 limit_req_status 448; # 如果超过设定的每个IP每秒150个连接数这个阈值,则返回449状态码给客户端 limit_conn_status 449; # 限制客户端速度只能到150k limit_rate 150k; # 防盗链,如果请求的头不是test.if010.com就是无效的,则返回449状态码给客户端 valid_referers none blocked test.if010.com; if ($invalid_referer) { return 449; } # 做判断,如果国家不是中国,就返回451状态码给客户端; if ($geoip2_data_country_code != CN ) { return 451; } # 做判断,如果匹配到默认不允许的规则,就返回452状态码给客户端 if ($geoip2_data_country_code = no ) { return 452; } # 防爬虫,如果UA是底下任意一个值,就判定为蜘蛛爬虫,则返回453给客户端 if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp|qihoobot|Scrubby|YodaoBot|yahoo-blogs/v3.9|Gigabot|yahoo-mmcrawler|Teoma|Robozilla|Bingbot|Slurp|Baiduspider|Googlebot|googlebot-mobile|googlebot-image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo!Slurp|Yahoo!Slurp China|YoudaoBot|Sosospider|MSNBot|ia_archiver|twiceler|psbot") { return 453; } } } ``` # 验证测试 ![Nginx访问日志结果](https://resource.if010.com/nginx_geoip_04.png) # 实现自动更新国家IP库 ## 获取geoipupdate官方工具 ```bash tar -zxvf geoipupdate_6.0.0_linux_386.tar.gz cd geoipupdate_6.0.0_linux_386/ mv geoipupdate /usr/local/nginx/IPData/ mv GeoIP.conf /usr/local/nginx/IPData/ ``` ## 创建LicenseKey ![申请License入口位置](https://resource.if010.com/nginx_geoip_05.png) ![查看LicenseKey](https://resource.if010.com/nginx_geoip_06.png) ## 配置GeoIP.conf ```bash vim /usr/local/nginx/IPData/GeoIP.conf # Please see https://dev.maxmind.com/geoip/updating-databases?lang=en for # instructions on setting up geoipupdate, including information on how to # download a pre-filled GeoIP.conf file. # Replace YOUR_ACCOUNT_ID_HERE and YOUR_LICENSE_KEY_HERE with an active account # ID and license key combination associated with your MaxMind account. These # are available from https://www.maxmind.com/en/my_license_key. AccountID xxxx #这里填写刚才记下的ID LicenseKey xxxx_xxxxxxxxxxxxxxx_xxx #这里填写刚才记下的key # Enter the edition IDs of the databases you would like to update. # Multiple edition IDs are separated by spaces. EditionIDs GeoLite2-Country GeoLite2-City # The remaining settings are OPTIONAL. # The directory to store the database files. Defaults to /usr/local/share/GeoIP DatabaseDirectory /usr/local/nginx/IPData/ #这里本来是注释掉的,取消注释修改成你数据库存放的位置 # The server to use. Defaults to "updates.maxmind.com". # Host updates.maxmind.com # The proxy host name or IP address. You may optionally specify a # port number, e.g., 127.0.0.1:8888. If no port number is specified, 1080 # will be used. # Proxy 127.0.0.1:8888 # The user name and password to use with your proxy server. # ProxyUserPassword username:password # Whether to preserve modification times of files downloaded from the server. # Defaults to "0". # PreserveFileTimes 0 # The lock file to use. This ensures only one geoipupdate process can run at a # time. # Note: Once created, this lockfile is not removed from the filesystem. # Defaults to ".geoipupdate.lock" under the DatabaseDirectory. LockFile /usr/local/nginx/IPData/.geoipupdate.lock #这里本来是注释掉的,取消注释修改成你数据库存放的位置 # The amount of time to retry for when errors during HTTP transactions are # encountered. It can be specified as a (possibly fractional) decimal number # followed by a unit suffix. Valid time units are "ns", "us" (or "µs"), "ms", # "s", "m", "h". # Defaults to "5m" (5 minutes). # RetryFor 5m # The number of parallel database downloads. # Defaults to "1". # Parallelism 1 ``` ## 启动geoipupdate 根据官方提供的参数来看,默认数据库会下到/usr/local/share下,所以我们要加个参数让它存放到/usr/local/nginx/IPData, -d跟–database-directory一样,指定数据库存放位置, -f跟–config-file一样,就是指定配置文件 ```bash ./geoipupdate -d /usr/local/nginx/IPData -f /usr/local/nginx/IPData/GeoIP.conf ``` 等一会它就更新完了,更新完后用ll命令看下时间,如果时间是当前时间,那就说明更新成功。 ## 创建定时任务 ```bash 创建一个shell脚本 mkdir -p /usr/local/script/logs/ cd /usr/local/nginx/IPData/ vim autoupdate.sh #!/bin/bash ######################################################################## # Function :自动更新IP数据库 # # Platform :Centso 6.x and 7.x (Base) # # Version :2.0 # # C_Date :2023-10-20 # # U_Date :2023-10-20 # # Author :Kim # # Contact :StephenJose_Dai # # Tips :Please don't delete it # # Used :确保/usr/local/nginx/IPData下有geoipupdate和GeoIP.conf文件 # # 再把脚本放入 /usr/local/script/下,然后运行即可 # # Log :用于自动更新国家IP数据库和城市IP数据库的程序 # ######################################################################## current_time=$(date "+%Y-%m-%d %H:%M:%S") /usr/local/nginx/IPData/geoipupdate -d /usr/local/nginx/IPData/ -f /usr/local/nginx/IPData/GeoIP.conf echo "[${current_time}] UpdateSuccessfully!" chmod +x autoupdate.sh crontab -e 00 02 * * * /usr/local/nginx/IPData/autoupdate.sh >> /usr/local/script/logs/geoipupdate.log 2>&1 重启crond服务 systemctl restart crond ``` 最后修改:2023 年 10 月 20 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 -