深入理解Nginx反向代理和负载均衡

深入理解Nginx反向代理和负载均衡

看过我之前文章的朋友应该了解我在搭建个性化Google镜像那篇博客中有提到过,Google镜像本身也是通过Nginx反向的代理来实现的,实现的个性化也是依赖的Nginx内置的一个模块ngx_http_sub_module。负载均衡也是我最近在为协会Google镜像配置的一项,我在这整个过程中也学到了很多。不得不说Nginx确实是一款非常优秀的Web服务器!

首先分享一些我在配置Nginx反向代理中遇到过的一些实际问题以及解决办法。

1.只有一个主机,要提供多个web服务,但又不想用域名加端口的方式访问

这个问题确实是我当时思索了很久,算是自己想出的解决办法吧,不过也确实能解决问题。我是直接在Nginx的主配置文件Nginx.cnf中添加的,我的思路是在本地做一次反向代理,来映射到服务对应的端口。

这里以我配置的为github配置的反向代理为例,因为平时经常逛github,但是国内有时候访问很慢,所以自己在香港的机子上做了个反代。

我是在第二个server中做的反代到github,但是监听的8040端口,也就是可以直接用ip:8040的方式直接访问到github。但是我分配了一个二级域名指向我的服务器,因为域名肯定是指向80端口。所以我在本地做一次反向代理,也就是第一个server中的配置,监听来自git.cdtu.site的请求。再反向代理到本地的8040端口,从而达到了目的。

我看了一些网上别人的解决办法,这里我直接引用他文章中的截图作对比。

Nginx多域名共享80端口配置

添加Ngin虚拟主机配置

在Nginx安装目录下建立vhosts文件夹,用来存放所有站点的配置文件。每个站点对应一个虚拟主机配置。

先修改Ngin主配置文件。

在主配置文件中他没有配置server相关的内容,而是放到单独的文件中。以上最关键配置:include /usr/local/nginx/vhosts/*.conf; 意思是在http模块里面加入你要引用的虚拟主机配置文件目录。

其实我发现和我的想法本质上是相同的,只是一个server单独一个配置文件罢了。

添加好虚拟主机配置后,将配置引入到主配置文件中“include /usr/local/nginx/vhosts/*.conf;”,然后启动Nginx即可。

2.在反向代理中的一些常见配置

  • nginx中proxy_set_header 的作用

nginx为了实现反向代理的需求而增加了一个ngx_http_proxy_module模块。其中proxy_set_header指令就是该模块需要读取的配置文件。在这里,所有设置的值的含义和http请求同中的含义完全相同,除了Host外还有X-Forward-For。

Host的含义是表明请求的主机名,因为nginx作为反向代理使用,而如果后端真是的服务器设置有类似防盗链或者根据http请求头中的host字段来进行路由或判断功能的话,如果反向代理层的nginx不重写请求头中的host字段,将会导致请求失败【默认反向代理服务器会向后端真实服务器发送请求,并且请求头中的host字段应为proxy_pass指令设置的服务器】。

同理,X_Forward_For字段表示该条http请求是有谁发起的?如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来在反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。因此,在配置用作反向代理的nginx中一般会增加两条配置,修改http的请求头。

就比如这样:


proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

这里的$http_host和$remote_addr都是nginx的导出变量,可以再配置文件中直接使用。如果Host请求头部没有出现在请求头中,则$http_host值为空,但是$host值为主域名。因此,一般而言,会用$host代替$http_host变量,从而避免http请求中丢失Host头部的情况下Host不被重写的失误。

X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。

X-Forwarded-For: client1, proxy1, proxy2
其中的值通过一个 逗号+空格 把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。
  • nginx来屏蔽指定的user_agent的访问以及根据user_agent做跳转

比如我们协会的Google镜像网站,我不希望被搜索引擎抓取到。我们可以禁止网络爬虫的user_agent,返回403。


if ($http_user_agent ~* (baiduspider|360spider|haosouspider|googlebot|soso|bing|sogou|yahoo|sohu-search|yodao|YoudaoBot|robozilla|msnbot|MJ12bot|NHN|Twiceler)) {
return 403;}
#还可禁止非GET|HEAD|POST方式的抓取
if ($request_method !~ ^(GET|HEAD|POST)$) {
  return 403;
}

添加这段即可屏蔽掉大部分主流爬虫。

3.Nginx中为多个server配置负载均衡

这是我配置过程中踩过的一些坑。首先Nginx确实很棒,因为前几天我多增加了一些服务器,想要给我们协会的Google镜像做一些性能拓展,当然我最先想到的肯定是负载均衡。我也考虑过阿里云提供的SLB负载均衡,不过是收费的,想想我的需求也没那么高,不如就用Nginx自带的负载均衡来实现。

这里用我为Google镜像配置负载均衡写的配置文件为例,upstream中有两个server一个是本机的反代,一个是我另外一台vps上搭建的Google镜像,直接指定ip和端口即可。我默认选用轮询的方式。

为什么说我踩了一些坑呢。因为之前我在看别人写的配置文件时,他upstream的名字是直接用的域名,就比如upstream  www.xxxxxx.com ,同理在proxy_pass配置时就要写成proxy_pass  http://www.xxxxxx.com ,我误以为他是要反代到这个域名的网站,而不是写的upstream的名字。我在这里纠结了好久,最终抱着试试的心态,把proxy_pass后面换成了 http:// 加上upstream的名字才成功了。

希望大家在这里配置的时候不要和我踩同样的坑。当然自己踩过的坑,印象会深刻很多。

zgao

如果有什么技术上的问题,可以加我的qq 1761321396 一起交流。

评论已关闭。