0x00 前言
我是学弟。
进入正题之前,感谢那些分享知识的前辈们,我在参考了他们的文章之后学习到了很多东西。
奉上详细链接:
Nginx反向代理、负载均衡、页面缓存、URL重写及读写分离详解
其中第一篇已经写的很详细了,有关正向代理,反向代理的介绍什么的;第二篇是nginx的官方文档,也是最最详细和标准的一个;第三篇是我参考的文件,第一遍当然看不懂,但是理解了每句话的内容之后也就明白了,下面的评论也挺搞笑的~。
0x01 简介
那我们就开始步入正题吧!
关于学习,无非就是,是什么,为什么,和怎样做。
是什么?
首先说明反向代理(reverse proxy)是什么,但是在这之前要先说明正向代理是什么,没错,真有正向代理(proxy)。
我们平时所说的代理就是正向代理,最常见的就是QQ代理,和VPN代理,以前的QQ主登陆界面的背面都会藏着一些设置选项,最醒目的就是代理,什么http代理啊,socks代理啊,https代理啊,我觉得这个功能是提供给那些在公司里面上不了QQ的人准备的,为什么上不了QQ?老板不让呗!所以就出现了“代理”这个工具,包括现在,也有很多网站提供免费的在线代理(我不是来打广告哒!),有匿名的,也有非匿名的,但是安全性,嘿嘿,真不好说。
代理的过程大概是这个样子的:
我上不了QQ,但是你可以上,所以我就把数据包发给你,你再帮我把数据包转给QQ服务器,当QQ服务器返回消息的时候,你再返回给我,这样你就充当了一个中间人的角色,也就是,代理。并不是多么难理解,就跟小时候传纸条差不多,中间传递的那个家伙就是我们的代理。当然,被老师抓到的也是他,不过,他也是有可能把你供出来的。所以在这里也提醒一下各位小黑阔们(海伦请无视),天网恢恢,疏而不漏,别以为挂了代理就找不到你了哦。
那么什么是反向代理?
有这样一种场景,你可以访问QQ的网站,但是我不行,我只能访问360的网站(先不要管为什么了)。但是我们之间的通信是畅通的,也就是说,我可以访问你的网站,那么,我该如何访问QQ呢?当然,我可以通过你这个跳板去上网,比如在你上面弄弄弄个VPN啊,ssh啊,但是如果你不让我这样做呢?你只开放了80端口给我,也就是说,我只能从你这里得到WWW的服务,这可如何是好?(不要问我为什么非要上QQ!)那么有一种办法就是你把QQ的内容抓取下来,放到80端口给我看,也就是说,我间接地通过你上了QQ。而你呢,就充当了反向代理的角色。注意,这里是间接上网,我表面上是访问的你,但是你再后端把QQ给抓过来了,所以,实质上我还是访问的QQ,这样说应该就会很好理解了。
0x02 为什么?
那么,为什么需要用反向代理呢?
1.服务器群的负载均衡
你有很多服务器对外提供服务,虽然说提供的服务都是一样的,但是每台服务器都有自己的IP啊,你不可能只让一台工作吧,那么怎样才能通过一个网址来调动所有的服务器都对外工作呢?这就需要反向代理了,设立一台主机对外开放,剩余的那些作为服务器群在后端负责处理数据,然后,当有请求发送到对外开放的主机上面时,这台主机就会通过算法去调动在后端的主机处理数据,然后把结果返回给客户,这样这台主机就仅仅起到了一个前台的作用,脏活累活什么的就交给了后面的那群主机们干了~前台作为调度员,是有责任处理好这些事务的,刚才说道通过算法进行处理,那么,究竟是什么算法呢?客官且听我慢慢说来。
[静态方法:仅根据算法本身实现调度:][a]
-
Round-robin(轮回调度)
我有十台肉鸡,啊不,是服务器,每台服务器的性能都差不多,所以我就采用了这个轮回查询算法,每当有新的业务进来了,前台的调度员就会每台服务器每台服务器的给分配任务,不会偏袒着谁,因为是按照次序来的,1号有任务就分给是2号,2号完了是3号,3号完了就让4号上,但是,如果4号要是挂了呢?这就需要我们设置一个fail_timeout,意思是如果服务器在这个时间里没能应答或者啥的,就把任务再分配给下一台肉鸡,啊不,主机。
-
Weighted round-robin(加权轮回调度)
还是那十台主机,但是有的是Digitalocean的,有的是阿里云的,有的用的是SSD,有的还tm用软盘,有的CPU用的是i7,有的用的是8086...性能不一样啊!要是按照上面的轮回算法,让一个超级电脑去等一台内存只有512M虚拟机,不能忍!所以,这时候就需要给我们的电脑加权了。好电脑就把权值分配的大一点,渣主机就把权值写小一点。这样前台在调度的时候就会按照他们的权值进行分配,主机A更快,那我就给他多分配点任务,主机B比较慢,那我分配任务的时候就少点。如果你还有兴趣了解,请谷歌“Weighted round-robin”。
-
Source ip Hashing(源地址散列调度)
通俗点讲就是按照你的IP地址给你hash一个主机,然后这台主机就为你服务了,这种算法的优点是什么的?很明显的一对一金牌服务嘛!记得有一次CTF,出题的妖怪在后台部署了好多好多服务器,上传shell每次都会到不同的主机上,那么,你猜他们用的是什么调度方法?没错,反正不是这种。那么如果巧了,同一时间好多任务都给了一台主机,而这台主机又没反应咋弄?调度员也不是傻X,当服务器没有正常反应的时候,他就会给下一台主机分配这个任务了,涉及到很多算法的问题吧,我想。
-
Destination ip Hashing(目标地址散列调度)
这种调度方法主要应用在缓存服务上面,如果好多主机访问的是同一台主机,那么前台调度员就会把这些主机看成同一类,把他们统统交给某一台服务器,怎么说呢,跟上面的哈希溯源正好相反着的,上面是一对一的服务,下面是一对多的服务。反正是缓存服务器嘛,性能肯定棒棒的,让他多做点事情也是没问题的。
动态方法:根据算法及后端RS当前的负载状况实现调度:
啊发现这些东西已经跑题了,所以各位看官有兴趣了解的话就不要听我在这里白活了,链接上面有哦~ 虽然那些文字看起来皱巴巴的 =。=
2. 海外代理
这就跟海外代购差不多的,我想买化妆品,但是国内没有啊,我就让代购去买,买完了给我就行了。放在服务器上呢,比如说,我想上谷歌,但是伟大的防火墙不让啊,所以我就交给海外的一台主机,让它帮我访问谷歌,然后我在向这台主机请求资源,这样就达到了访问谷歌的目的。https://google.kfd.me上面的站是我搭建的google。
“哎等会儿,你说的这个反向代理和VPN啥的有什么区别,还有我用的Shadowsocks,Goagent,不也都可以实现这种功能吗?”
哦。
那我就来扯一扯他们之间的区别。要是让我详细讲,估计一天也讲不完(其实是不会QAQ)。那我就简单粗略的给大家说一下有啥不同。首先说下VPN,VPN可以理解为一条虚拟的网线,我上不去谷歌,但是我远在日本的女朋友可以上啊,所以我就让女朋友答了一个VPN服务器,我呢,就通过VPN这条虚拟的网线连接上了女朋友的电脑,当然就可以上谷歌啦,不仅可以上谷歌,而且还可以……嘿嘿嘿。
那么,shadowsocks和goagent呢,他们都是代理软件,原理类似于上面讲到的正向代理,但是,代理的主机是127.0.0.1,也就是你自己的主机,如果在浏览器上设置了代理的话,那么你浏览器的流量都会先在本机走一圈,也就是通过那些shadowsocks啊goagent啊走一遍,而goagent呢,是连接了外网的家伙,我这里的外网,指的是out of China 的网,当然,在国内部署Goagent也不是不可以,只是你上不了谷歌而已,上上百度啊,QQ啊,360啊还都是可以的。Goagent会把流经它的数据转发到你部署的服务器上,在通过服务器进行资源请求。我之前也写过一篇关于goagent的,感兴趣的可以看一下。Shadowsocks的原理类似,不在赘述。
0x03 怎样做?
基本的配置Nginx我就不说了,网上一搜一大把,我在这里啰啰嗦嗦,大家也觉着没意思。如果说有什么需要注意的,那可能就是注意代理谷歌的时候不要被墙了你的域名。(我简直就是在作死……)
然后,我也不想做一个搬运工,把那些长篇大论以及图片复制粘贴过来,所以我就直接贴出配置文档以供大家参考,如果你把这份配置放在服务器上的话,你也会得到一个谷歌的反向代理以造福国人。顺便说下,kfd.me 这个域名是我的。
proxy_cache_path /var/www/cache/ levels=1:2 keys_zone=one:100m max_size=1g;
proxy_cache_key $host$request_uri;
upstream google{
server 74.125.200.103 max_fails=3 fail_timeout=10s;
server 74.125.200.105 max_fails=3 fail_timeout=10s;
server 74.125.200.99 max_fails=3 fail_timeout=10s;
server 74.125.200.147 max_fails=3 fail_timeout=10s;
server 74.125.200.104 max_fails=3 fail_timeout=10s;
}
server {
listen 80;
server_name google.kfd.me;
# rewrite ^/(.*) https://google.kfd.me$1 permanent;
#}
#server {
# listen 443;
# server_name google.kfd.me;
# ssl on;
# ssl_certificate /etc/ssl/private/google_kfd_me.crt;
# ssl_certificate_key /etc/ssl/private/kfd_me.key;
location / {
proxy_pass http://google;
proxy_cache one;
proxy_cache_valid 200 302 2h;
proxy_cache_valid 404 1h;
proxy_buffering off;
proxy_cookie_domain google.com google.kfd.me;
proxy_redirect https://www.google.com.sg/ /;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Accept-Encoding "";
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Language "zh-CN";
proxy_set_header Cookie "PREF=ID=047818f19f6de346:U=0f622f33dd8549d11:FF=25:LD=zh-CN:NW=1:TM=1325238577:LM=1332342444:GM=5:SG=1:S=rE01SyJh2w1IQ-Maw";
sub_filter www.google.com google.kfd.me;
sub_filter_once off;
}
}
下面就详细的解释一下每句话的作用,其实也就是口头翻译下官方文档(⊙﹏⊙b汗)
上面的两句是用来配置缓存目录的,首先定义了一个缓存目录,然后设置了目录的级别,也就是说,可以有几层目录_keys_zone_这个是设置空间名称的,可以随便定义,但是在下面引用的时候名字必须相同,而且要唯一。100m代表100分钟,缓存时间。最后的1g是代表缓存的总大小。 key代表的是通过什么方式来定义缓存,这里用的是主机名+url地址来确定的。这样每次有主机访问反代理的时候都会先查询一下这个缓存文件,如果有的话就不再请求新的资源。下面是缓存文件夹的一个tree。
这个upstream google,表示的是上游服务器们,google只是一个代号,你完全可以写成guge,只要你知道这是什么意思就行了,而且下面引用的时候不要引用错。下面引用的条目是 proxy_pass。在这个栏目里面我们要写的是服务器的ip,其实你写网址也行,毕竟解析的都是ip。然后这里要注意的是里面的调度算法,这里面可以说是大有学问,我在[上面][a]讲的只是一点点皮毛而已。“max_fails=3” -> 最多允许三次失败。三次失败过后默认服务器挂掉,并将请求转入下一个服务器。 fail_timeout=10s -> 失败的时间为10秒。由于俺代理的是谷歌,而且谷歌的服务器这么坚挺,绝壁不会down,所以这里写上去也就没什么太大的鸟用。仅作教学示范~
proxy_pass 这一条是最最重要的,别的可以什么都没有,但是这一条是作为反向代理最重要的,它后面跟的值就是你要代理的网址,我这里的google是引用了上面定义的那些server,如果不需要那些server,你也可以直接放一个网址在这里,比如,http://zh.wikipedia.org/wiki/ 然后他就会访问这个网址了,哦对了,这里还有一个比较重要的地方,如果你的代理是一个ip地址,但是直接访问这个ip地址又得不到东西,那么这时候就需要定义header里面的 Host 了,可以这样来一条_prxy_set_header Host "zh.wikipedia.org";_比如我要代理百度,然而百度并不让我直接上,所以我就可以这样写:
proxy_pass http://www.baidu.com;
proxy_set_header Host "www.baidu.com";
这样就可以蒙混过关~
proxy_cache这里就是在上面 keys_zone 定义的那个名字。至于为什么要在这里声明一下,是因为一台服务器上可能不仅有一个缓存池,这里的声明是为了更好的区分。
proxy_cache_valid 200 302 2h;这个说的是,当返回状态200和302的时候,缓存时间为两个小时。这里的返回状态是指我反代服务器给我的返回状态,一般可以设置的大一点,如果这个站经常被访问的话。想我这反代的谷歌,没几个人上,我也就写的这么小了。
proxy_cache_valid 404 1h;404缓存一个小时。
proxy_cookie_domain google.com google.kfd.me;替换cookie的domain,把google.com换成google.kfd.me。在这里你要有一个“域”的概念,cookie是不能随便用的,更不能串着用。(大牛们见笑了,我是说给小白听的,哎哎别打我脸啊,哎轻点轻点……)
proxy_redirect https://www.google.com.sg/ /;重定向 "https://www.google.com.sg" 到 "/",也就是说,当有请求google的资源的时候都会请求本地,这才是我们搭这个反代理的目的所在。
proxy_buffering off;关闭缓冲.(内存中的缓存,不是cache)无关紧要的东西。
proxy_set_header这个是用来定义header的,也就是我们发送给谷歌的header,在这里我定义了用户的真实ip,和一部分cookie,还有语言,以及User agent。
sub_filter www.google.com google.kfd.me;这个是最好玩的,但是只能玩一次。将返回结果中的www.google.com全部替换为google.kfd.me,这样当返回的网页中存在下一链接的时候,就会继续请求我们的 google.kfd.me 而不是跳到谷歌去。这里也可以好好地发挥一下,比如,偷点东西出来。当然,不在这里深究。P牛早已看穿了一切。
sub_filter_once off;是否只替换一次? 否。
当然,这个是全局代理谷歌,因为location是 / 嘛。你也可以在下面在加上一个location /hello { ... }
然后访问 google.kfd.me/hello 就可以重新定义到另一个地方了。花样location,看起来很简单,但,做的事情却有很多。最简单的,定义robots,然后说不定就会有好玩的事情发生了呢~
0x04 写在最后
我一直以为,不想当厨子的裁缝不是好司机,其实我错了,不相当司机的厨子才不是好裁缝。
事情并没有这样简单地结束,因为这东西是一把刀,然而你要用这把刀犯罪还是防身,分寸在你心中。
钓鱼网站就是这么简单,我写这篇文章的目的也不是教你怎样钓鱼,而是让你知道,下一个被钓鱼的就是你。
如果你要问我为什么这么做,那么我的回答就跟为什么要去爬珠峰一样,因为我能。
提高防范意识,切勿玩火自焚。