看到这里的同学应该对「代理」并不陌生。无论是特别的上网技能还是 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 内容:

1
2
3
uptream jupyter {
server 127.0.0.1:35767;
}

这样就规定了名为 jupyter 的服务是在本机地址的 35767 端口上运行的,如果访问这个服务就定位过去。之后请求就可以以 http(s)://jupyter 代表 jupyter 的服务端地址,也就是 127.0.0.1:35767

然后我们监听 http/https 的请求,分别在 80/443 端口。

1
2
3
4
5
6
7
8
9
10
11
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 :

1
2
3
4
upstream aria2c {
server 127.0.0.1:6800;
server 127.0.0.1:6999;
}

之后就只需要监听端口,判断域名是否匹配,然后转发到 http://aria2c 即可。

默认两个端口是同级的(权重为 1),你还可以为每个端口设定一个权重,或者根据 IP 分配,根据响应时间分配,等等。

看,正向代理拓展了客户端上网的姿势,反向代理使服务端更加强大。

但其实,代理能做到的远不止这些,目前已经有了许多玩法。无声无息中为大家提供便利。

限制代理能力的,或许只有人们的脑洞罢了。


(Ended, thanks for reading…)


 Comments