0x01 前言
其实我本意并不是想区分国内外访客,只是我想使用又拍云的CDN服务分发静态文件。因此我购买了腾讯云的服务器并且完成备案,不用白不用,所以我区分了国内外访客。
因为购买了腾讯云的服务器,所以我干脆将cn域名指向该服务器,然后通过并不是很高明的技术手段区分访客,这样可以减轻香港服务器的负载,也可以尝试新技术。
其实我香港的服务器完全可以承载所有访问请求,每天的访客在200至300个IP左右,几乎是没人看的节奏,但这不是重点。
0x02 逻辑
首先是架构图:
当国内外的用户在浏览器中输入我博客的地址并会车,他们的操作系统会查询DNS以获取域名的DNS记录。
我域名的DNS托管在dnspod,而dnspod有一个免费区分国内外访客的功能,然后分别返还设定的DNS记录。而我也利用这个功能,给不同地域的用户返还cn1和hk1两台服务器的IP。
这里会有个问题,我希望国内的访客都使用enginx\.cn域名,国外访客都使用enginx\.net,但DNS只能返还DNS记录而不能跳转。
所以我还分别在两台服务器上使用nginx作301跳转,将通过其他域名进入我网站的访客都重定向到enginx\.cn或enginx\.net这两个域名。
完成跳转后服务器会返还网站源码给用户,浏览器解析源码的同时会从CDN服务器中下载静态文件。这样可以大大减少源站带宽的压力。
而cn1服务器则是hk1服务器的镜像站,通过nginx的反向代理功能实现相关服务。
0x03 dnspod
以下是分别使用国内网络与国外网络dig我域名的结果:
#国内用户 dig ngx.hk ; <<>> DiG 9.8.3-P1 <<>> ngx.hk ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26772 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;ngx.hk. IN A ;; ANSWER SECTION: ngx.hk. 600 IN CNAME cn1.c4.hk. cn1.c4.hk. 600 IN A 118.89.52.242 ;; Query time: 107 msec ;; SERVER: 10.1.2.1#53(10.1.2.1) ;; WHEN: Tue Sep 12 15:27:41 2017 ;; MSG SIZE rcvd: 67 #国外用户 dig ngx.hk ; <<>> DiG 9.9.4-RedHat-9.9.4-50.el7_3.1 <<>> ngx.hk ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55912 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;ngx.hk. IN A ;; ANSWER SECTION: ngx.hk. 1277 IN CNAME hk1.c4.hk. hk1.c4.hk. 169 IN A 103.15.217.210 ;; Query time: 28 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Tue Sep 12 15:28:07 CST 2017 ;; MSG SIZE rcvd: 78
从上面结果可以看出,从DNS层面就区分了用户,将不同地域的用户指向了不同的服务器。以下是dnspod的配置:
enginx\.cn域名的DNS记录与.net的相类似。
0x04 301
将用户导向相应的服务器后,DNS的工作就完成了。以下都是我的域名:
ngx.hk enginx.cn enginx.org enginx.uk proj.org.cn
当国内用户通过非.cn域名访问时,cn1服务器将通过301重定向至enginx\.cn;当国外用户通过非.net域名访问时,hk1服务器将通过301重定向至enginx\.net。
而301重定向我是通过nginx实现的,因为只需要实现301重定向功能,所以配置信息较为简单。以下是enginx\.org域名跳转到enginx\.net的配置信息:
server { listen 80; server_name enginx.org www.enginx.org; return 301 https://ngx.hk$request_uri; } server { listen 443 ssl; server_name enginx.org www.enginx.org; ssl on; ssl_certificate /usr/local/nginx/ssl/enginx.org.crt; ssl_certificate_key /usr/local/nginx/ssl/enginx.org.key; ssl_buffer_size 16k; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA; ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache builtin:20480 shared:SSL:10m; ssl_session_timeout 3h; ssl_stapling on; ssl_session_tickets on; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=31536000; preload; includeSubDomains" always; add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; max-age=2592000; includeSubDomains'; return 301 https://ngx.hk$request_uri; }
其他域名也类似,在这需要顾及http协议的访客。我的网站使用顶级域名作为主域名,而没有添加www,所以也需要顾及使用www的访客。
至此,所有工作均已完成。
0x05 其他
因为CDN可以设置IP+host的方式回源,所以我使用的又拍云CDN不受此规则影响:
nginx后面是apache、php-fpm与mariadb,nginx前面还有一个waf。这些内容我以后再写文章详细说明。
0x06 结语
我最近在寻找好一点的DNS服务商,我想使用CAA这个功能。但近几天了解的几家服务商都不支持根据地域区分返还DNS记录。
如果不行,那只好使用nginx通过geoip数据库区分了。