Proxy Server | 正向代理与反向代理
看到这里的同学应该对「代理」并不陌生。无论是特别的上网技能还是 Nginx 映射本地端口,都离不开代理的特效。
这次,让我们再一次看看:代理,究竟是如何运作的。并重点介绍下可能更陌生一点的「反向代理」,我们可以用反向代理干什么。
What’s 「Proxy」 ?
无论正向代理还是反向代理,都是「代理」(废话?)
代理就像一个中转站,服务端与客户端之间的交流交给代理在中间代理。客户端想访问服务端,并不直接向服务端发出请求,而是向代理发出,然后让代理转交给服务端;同样的,服务端返回数据,并不是直接发回给客户端,而是发给代理,再让代理交还给客户端。所有客户端和服务端之间的流量都会由代理来转发。
好像把事情变麻烦了?不急,它自有用处。
Forward Proxy | 正向代理
正向代理工作原理
在正向代理时,代理服务器会先和客户端(Client)建立连接,然后客户端将某些特定请求或全部网络请求发给代理服务器,代理服务器再拿着请求跑去送给对应的服务端(Server)。同样的,服务端回应这个请求的时候也是先发给代理服务器(毕竟表面上这个请求是代理服务器发出的),然后代理服务器再把回应送回给客户端。
优势
从上面介绍的正向代理工作原理来看,代理服务器负责代替客户端发出和接收网络请求,所以表面上好像是代理客户端在发出请求(实际上貌似也是) ,这样给真实的客户端披上一层外套。
不难发现,正向代理可以:
- 突破访问限制(解锁),比如某些限制了地区使用的资源,我可以用一个当地的代理,让它代理我的流量,骗过服务端。
- 屏蔽广告,代理服务器可以判断返回的内容,如果是不受欢迎的广告或追踪代码,代理服务器就把它拦下来,不发给服务端。
- 匿名,可能有很多同学都在使用一个代理,服务端无从知道真实的请求是谁发出的,只知道是由代理转发的。从而保障了一定的匿名性。
Reverse Proxy | 反向代理
反向代理工作原理
那反向代理又是如何工作的呢?这次代理是替服务端(Server)工作了。
服务端只对外公开代理的地址,所有发送给服务端的请求都会先到代理那里,然后让代理再根据请求分发给相应的服务端;回应的时候也是类似。
优势
为什么需要这样的一步呢?其实许多服务器并不是十分顽强,收到过多的请求甚至可能宕机,更不用说要是被攻击了。而套上这一层反向代理,代理服务器可以将请求均衡地分配给服务器组,防止过多请求集中在一台或者几台服务器上,使其负载过大影响服务,这就叫「负载均衡」。同样地,遇到异常流量,代理可以直接拦截下来,而且代理还可以隐藏服务端的真实地址,这都起到了保护服务端的作用。
反向代理不仅可以保护服务器,甚至还可以加速访问!比如代理服务器可以将一些静态资源缓存下来,如果遇到请求,就不用向服务端发送,直接返回资源,更有利于让服务端将算力、带宽集中在加载重要的地方。
这里就不得不提到 CDN 了。CDN 的全称是内容分发网络 (Content Delivery Network 或 Content Distribution Network) ,可以将资源缓存在多台服务器上,访问的时候从最近的服务器中获取,提供高性能的传递且降低骨干网负载。而 CDN 大多也是基于 Nginx 或者 Nginx + SNI 反向代理实现的,所以你也可以将域名指向 CDN 隐藏真实地址。
实践出真知
端口映射
我在自己的 VPS 上 搭建 Jupyter Notebook 实现 Web 端编写运行 Python 代码。
我配置 Jupyter Notebook 是运行在 localhost:35767
上的。目前我已经将 jupyter.domain.com
解析到该 VPS 地址上了,而从公网访问 VPS 地址都是直接发送给 Nginx 代理上的。所以我们要合理配置 Nginx 使其能够让域名转发到对应服务的端口。
打开你的 Nginx 主配置文件(一般在 /etc/nginx/nginx.conf
,如果你也是使用宝塔的快速安装,那么会在 /www/server/nginx/conf/nginx.conf
)
首先我们定义 upstream 内容:
uptream jupyter {
server 127.0.0.1:35767;
}
这样就规定了名为 jupyter
的服务是在本机地址的 35767 端口上运行的,如果访问这个服务就定位过去。之后请求就可以以 http(s)://jupyter
代表 jupyter
的服务端地址,也就是 127.0.0.1:35767
。
然后我们监听 http/https 的请求,分别在 80/443 端口。
server {
listen 80;
listen 443 ssl;
server_name jupyter.domain.com; # 对应的域名
# https...ssl...
location / {
proxy_pass http://jupyter; # 转发请求
}
}
这样就实现了让 juypter.domain.com
的请求跳到 juypter
的服务地址,而之前我们已经配置好了该服务地址。
负载均衡
端口映射并不能真正体现 upstream 的强大,而负载均衡就不一样了。比如我想将 aria2c.domain.com
请求平均的分配到 6800 和 6999 这两个端口上。
首先定义 upstream :
upstream aria2c {
server 127.0.0.1:6800;
server 127.0.0.1:6999;
}
之后就只需要监听端口,判断域名是否匹配,然后转发到 http://aria2c
即可。
默认两个端口是同级的(权重为 1),你还可以为每个端口设定一个权重,或者根据 IP 分配,根据响应时间分配,等等。
后
看,正向代理拓展了客户端上网的姿势,反向代理使服务端更加强大。
但其实,代理能做到的远不止这些,目前已经有了许多玩法。无声无息中为大家提供便利。
限制代理能力的,或许只有人们的脑洞罢了。