Nginx配合GeoIP模块来处理不同国家的访问

Nginx的http_geoip_module模块可以满足针对国内外/国内城市地域作HTTP访问规则区别的需求。这里使用Nginx 的 GeoIP 拓展(ngx_http_geoip_module),在标准版的 Nginx 中需要重新把它拓展编译进去。 首先先检查一下Nginx是否有GeoIP模块:
1
nginx -V
倘若输出界面没有包含 --with-http_geoip_module,首先安装 nginx-module-geoip,在Nginx相关路径下运行:
1
2
3
4
5
6
7
8
wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
tar -zxvf GeoIP.tar.gz
cd GeoIP-1.4.8
./configure
make
make install
echo '/usr/local/lib' > /etc/ld.so.conf.d/geoip.conf #刚才安装的库自动安装到 /usr/local/lib 下,所以这个目录需要加到动态链接配置里面以便运行相关程序的时候能自动绑定到这个 GeoIP 库.
ldconfig
或者:
1
2
3
4
5
6
7
8
sudo apt-get install nginx-module-geoip
# DAT 版数据库官方已不再提供下载,下面的链接来自私有云备份
# 详见:https://dev.maxmind.com/geoip/legacy/downloadable/
wget https://cdn.kixss.com/GeoIP/GeoIPv6.dat.gz
gzip -d -k GeoIPv6.dat.gz

# GeoIPv6.dat 覆盖了 IPv4 和 IPv6 的数据,如果仅需 IPv4,使用下面这个文件
wget https://cdn.kixss.com/GeoIP/GeoIP.dat
注意:如果nginx不是yum安装的而是源码编译安装的需要从新安装编译一次nginx加上此模块,然后就不用手动加入此模块了。yum 安装好后找到安装的模块文件 ,如果nginx是用yun安装的一般是安装到 /etc/nginx/modules/目录下 。

手动加入模块,在nginx.conf配置文件的头部载入模块和http是同一个级别的。

1
2
load_module "modules/ngx_http_geoip_module.so";
load_module "modules/ngx_stream_geoip_module.so";

添加未编译安装模块:
cd 到Nginx 源码目录,LNMP的环境目录在/root的LNMP安装包下/nginx/src,需要解压缩并且重新编译。
使用参数从新配置,注意这里参数是直接复制 nginx -V 显示出来的,把configure arguments: 后面的参数复制出来,后面加上--with-http_geoip_module即可。

1
./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-openssl=/root/lnmp1.5-full/src/openssl-1.0.2o --with-http_geoip_module

等上面执行完了,然后再编译:

1
make

替换Nginx二进制文件。(建议备份下当前Nginx文件,避免出现问题了无法恢复)

1
2
3
4
#先停止nginx 再替换二进制文件,提示overwrite 的话记得输入y后回车。
service nginx stop
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.backup
cp ./objs/nginx /usr/local/nginx/sbin/nginx

替换成功后,重启Nginx。然后查看一下GeoIP模块加载情况。如果后面包含了--with-http_geoip_module 就成功了。

1
2
service nginx restart
nginx -V

检查一下/usr/local/share/GeoIP/目录是否包含GeoIP.dat,打开Nginx配置文件,添加变量,在http{} 区域任意位置(include字段之前)添加如下变量:

1
2
3
4
geoip_country /usr/local/share/GeoIP/GeoIP.dat;
fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
fastcgi_param GEOIP_COUNTRY_CODE3 $geoip_country_code3;
fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;

编辑Nginx 网站配置文件,在server {} 区域内添加代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
load_module "modules/ngx_http_geoip_module.so";
load_module "modules/ngx_stream_geoip_module.so";
...
http{
geoip_country /etc/nginx/geoip/GeoIP.dat; #加载国家IP
geoip_city /etc/nginx/geoip/GeoLiteCity.dat; #加载城市IP
.......
server
{
......
location / {
#判断如果不是中国的就返回403;
if ($geoip_country_code != CN) {
return 403;
}
}
#返回国家城市信息
location /myip {
default_type text/plain;
return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
}

}
}

或者根据不同的国家的访问导向不同的页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# vi /etc/nginx/nginx.conf

http {
...
geoip_country /home/vpsee/GeoIP.dat;
fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
fastcgi_param GEOIP_COUNTRY_CODE3 $geoip_country_code3;
fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;
...
}

server {
...
location / {
root /home/vpsee/www;
if ($geoip_country_code = CN) {
root /home/vpsee/cn;
}
...
}
...
}

最后,附上一份Nginx配置文件的详细注解(关于Nginx内rewrite规则及正则表达式的应用,可点击这里查看详情):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#load_module modules/ngx_stream_module.so;   #动态加载模块,必须写道开头
user nginx nginx;

#4核心启用
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000

#8核心启用
#worker_processes 8;
#worker_cpu_affinity 00000001 00000010 00000100 0000100000010000 00100000 01000000 10000000;

#这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,
#但是nginx分配请求并不是那么均匀,所以最好与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#error_log logs/error.log;
#error_log logs/error.log notice;
error_log logs/error.log info;

pid logs/nginx.pid;

events {
use epoll;
worker_connections 65535;
multi_accept on;
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
#开启高效传输模式
sendfile on;
tcp_nopush on;
#开启高效传输模式end
#连接超时时间
keepalive_timeout 60; #客户端连接保持会话超时时间,超过这个时间,服务器断开这个链接
tcp_nodelay on; #也是防止网络阻塞,不过要包涵在keepalived参数才有效
client_header_buffer_size 4k; #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过 1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。
open_file_cache max=102400 inactive=20s; #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件 #数一致,inactive 是指经过多长时间文件没被请求后删除缓存。
open_file_cache_valid 30s; #这个是指多长时间检查一次缓存的有效信息。
open_file_cache_min_uses 1; #open_file_cache指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文
#件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。
client_header_timeout 15; #设置请求头的超时时间。我们也可以把这个设置低些,如果超过这个时间没有发送任何数据,nginx将返回request time out的错误
client_body_timeout 15; #设置请求体的超时时间。我们也可以把这个设置低些,超过这个时间没有发送任何数据,和上面一样的错误提示
reset_timedout_connection on; #告诉nginx关闭不响应的客户端连接。这将会释放那个客户端所占有的内存空间。 time out的错误
send_timeout 15; #响应客户端超时时间,这个超时时间仅限于两个活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx关闭连接
server_tokens off; #并不会让nginx执行的速度更快,但它可以关闭在错误页面中的nginx版本数字,这样对于安全性是有好处的。
client_max_body_size 10m; 上传文件大小限制
#连接超时时间 end
#fastcgi调优
fastcgi_buffering on; #默认on,是否缓存fastcgi响应
fastcgi_connect_timeout 600s; #指定连接到后端FastCGI的超时时间。
fastcgi_send_timeout 600s; #向FastCGI传送请求的超时时间。
fastcgi_read_timeout 600s; #指定接收FastCGI应答的超时时间。
fastcgi_buffer_size 64k; #指定读取FastCGI应答第一部分需要用多大的缓冲区,默认的缓冲区大小为fastcgi_buffers指令中的每块大小,可以将这个值设置更小。
fastcgi_buffers 4 64k; #指定本地需要用多少和多大的缓冲区来缓冲FastCGI的应答请求,如果一个php脚本所产生的页面大小为256KB,那么会分配4个64KB的缓冲区来缓存,
#如果页面大小大于256KB,那么大于256KB的部分会缓存到fastcgi_temp_path指定的路径中,但是这并不是好方法,因为内存中的数据处理速度要快于磁盘。
#一般这个值应该为站点中php脚本所产生的页面大小的中间值,如果站点大部分脚本所产生的页面大小为256KB,那么可以把这个值设置为“8 32K”、“4 64k”等。
fastcgi_busy_buffers_size 128k; #建议设置为fastcgi_buffers的两倍,繁忙时候的buffer
fastcgi_temp_file_write_size 128k; #在写入fastcgi_temp_path时将用多大的数据块,默认值是fastcgi_buffers的两倍,该数值设置小时若负载上来时可能报502BadGateway
fastcgi_temp_path fastcgi_temp 1 2; #缓存临时目录
fastcgi_intercept_errors on; #这个指令指定是否传递4xx和5xx错误信息到客户端,或者允许nginx使用error_page处理错误信息。
fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=fastcgi_cache_zone:128m inactive=1d max_size=10g;

#fastcgi_cache缓存目录,可以设置目录层级,比如1:2会生成16*256个子目录,cache_fastcgi是这个缓存空间的名字,cache是用多少内存(这样热门的内容nginx直接放内存,提高访问速度),
#inactive表示默认失效时间,如果缓存数据在失效时间内没有被访问,将被删除,max_size表示最多用多少硬盘空间。
#fastcgi调优end
#gzip调优

gzip on; #开启压缩功能
gzip_min_length 2k; #设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取,默认值是0,不管页面多大都进行压缩,建议设置成大于1K,如果小与1K可能会越压越大。
gzip_buffers 4 32k; #压缩缓冲区大小,表示申请4个单位为32K的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
gzip_http_version 1.1; #压缩版本,用于设置识别HTTP协议版本,默认是1.1,目前大部分浏览器已经支持GZIP解压,使用默认即可
gzip_comp_level 6; ; #压缩比例,用来指定GZIP压缩比,1压缩比最小,处理速度最快,9压缩比最大,传输速度快,但是处理慢,也比较消耗CPU资源。
gzip_typestext/plain text/css text/javascriptapplication/json application/javascript application/x-javascriptapplication/xml; #用来指定压缩的类型,‘text/html’类型总是会被压缩。
gzip_disable "MSIE[1-6]"; #ie浏览器1-6禁用gzip
gzip_vary on; #varyheader支持,改选项可以让前端的缓存服务器缓存经过GZIP压缩的页面,例如用Squid缓存经过nginx压缩的数据
gzip_proxied any;
#gzip调优end
#geoip
geoip_country /usr/local/nginx/geoip/GeoIP.data;
geoip_city /usr/local/nginx/geoip/GeoLiteCity.dat;

#一般是在日志里面使用
log_format ip_log '$geoip_city_country_name $geoip_region_name $geoip_city';

#geoip end


}