理解Nginx的server匹配规则

栏目: 服务器 · Nginx · 发布时间: 5年前

内容简介:Nginx在逻辑上将提供不同内容的配置划分为块,这些块以层次结构的形式存在(http->server->location)。客户端发出请求时,Nginx收到之后,会有一个确定应该使用哪些配置块来处理请求的过程。本文主要介绍 server 块背后的处理过程。server块是Nginx配置的子集,它定义用于处理已定义类型请求的虚拟服务器(虚拟机)。管理员通常会配置多个server块,并根据请求的域名,端口和IP地址决定哪个块应该处理哪个连接。由于Nginx允许管理员定义多个server块作为单独的虚拟Web服务

Nginx的块配置

Nginx在逻辑上将提供不同内容的配置划分为块,这些块以层次结构的形式存在(http->server->location)。客户端发出请求时,Nginx收到之后,会有一个确定应该使用哪些配置块来处理请求的过程。本文主要介绍 server 块背后的处理过程。

server块是Nginx配置的子集,它定义用于处理已定义类型请求的虚拟服务器(虚拟机)。管理员通常会配置多个server块,并根据请求的域名,端口和IP地址决定哪个块应该处理哪个连接。

Nginx如何决定哪个server块来处理请求

由于Nginx允许管理员定义多个server块作为单独的虚拟Web服务器实例,因此需要一个算法来确定将使用哪些server块来匹配请求。

Nginx在此过程中关注的主要server块指令是 listen 指令和 server_name 指令。

解析“listen”指令以找到可能的匹配

首先,Nginx查看请求的IP地址和端口,并与每个服务器的 listen 指令相匹配,构建可能解析请求的服务器块列表。

listen 指令通常定义 server 块将响应的IP地址和端口。默认情况下,任何不包含 listen 指令的 server 块默认 listen 在 0.0.0.0:80 (或者 0.0.0.0:8080 如果Nginx由普通的非root用户运行),这样的配置块响应80端口上任何接口的请求,但是这个默认值在server选择过程中没有太大的权重。

listen 指令可以设置为:

  • IP地址/端口组合。
  • 只有IP地址,它将监听默认端口80。
  • 只有端口,它将监听该端口上的每个接口。
  • Unix套接字的路径。

最后的选项通常在不同的服务器之间传递请求时起到作用。

在尝试确定向哪个服务器块发送请求时,Nginx将首先尝试 listen 使用以下规则根据指令的特异性来决定:

  • Nginx用默认的缺省值来替换所有不完整的lesten指令(完整:IP+port的组合)的缺省值,因此每一个server块的 listen 指令都可以看作是IP地址和端口的组合。 这种转换的例子有:
    • 没有 listen 指令的块使用该值 0.0.0.0:80
    • 设置为 111.111.111.111 没有端口的IP地址的块变为 111.111.111.111:80
    • 设置为 8888 没有IP地址的端口的块变为 0.0.0.0:8888
  • 接下来Nginx会尝试去收集一个server块的列表,这个列表是基于具体的IP和端口最佳匹配。也就是说如果匹配的server块有具体的IP地址,它就不会匹配用0.0.0.0作为默认的IP地址的server块。无论什么情况,在Nginx选择server块的过程中,端口必须准确匹配。
  • 如果只有一个最具体的匹配,那么该server块将用于提供请求。如果有多个server 块具有相同层次的具体匹配,那么Nginx需继续评估 server_name 指令 。

需要特别注意的是,只有 listen 指令在同一层次上有多个匹配的 server 块时,Nginx才会继续评估 server_name 指令。举个例子,如果域名example.com被解析到IP为192.168.1.10,端口为80的主机上,当客户端请求example.com时,在本例中,第一个server模块总是会提供服务,尽管 server_name 指令在第二个server模块中。

1
2
3
4
server{
listen 192.168.1.10;
....
}
1
2
3
4
5
server{
listen 80;
server_name example.com;
....
}

多个server模块在具体的匹配中处于同一级别的情况下,Nginx下一步才会检查 server_name 指令。

解析server_name指令选择一个匹配

接下来,为了进一步评估具有相同特定 listen 指令的请求,Nginx会检查请求的“host”标头,此值包含客户端实际尝试访问的域或IP地址。

Nginx在候选的每一个server模块中,查看其 server_name 指令,尝试去找到最佳的匹配。Nginx通过下面的公式来进行评估:

  • Nginx首先找到 server_name 与请求的Host头信息精准匹配的server模块,如果找到了这个server模块,它将会被用于服务客户端的请求。若有多个特定的匹配项被找到,第一个会被用于提供服务。
  • 如果没有找到精准的匹配项,Nginx接下来将尝试去找 server_name 与前置通配符(在配置中名称的开头用*表示)匹配的server模块。只要找到一个,这个server模块将被用于为客户端提供服务。如果找到了多个匹配,最长匹配结果的server模块将会被用于提供服务。
  • 如果使用前置通配符没有找到匹配时,Nginx接下来将尝试去找 server_name 与后置通配符(在配置中名称的结尾用*表示)匹配的server模块。只要找到一个,这个server模块将被用于为客户端提供服务。如果找到了多个匹配,最长匹配结果的server模块将会被用于提供服务。
  • 如果使用后置通配符没有找到匹配时,Nginx接下来将会评估用正则表达式(在名称前用~表示)定义 server_name 的server模块。带有与Host头匹配的正则表达式的第一个 server_name 将被用于提供服务。
  • 如果没有找到用正则表达式定义 server_name 的相匹配的server模块时,Nginx接下来会使用默认IP和端口的server模块。

每一个IP地址/端口组合都有一个默认的server模块,当用上面的方法不能确定一个操作的过程时将使用默认的server模块。对于IP地址/端口的组合来说,这将是配置中的第一个模块或者是包含 default_server 选项作为 listen 指令的一部分的server模块(这将复写first-found算法)。每一个IP地址/端口组合只能有一个 default_server 声明。

实例

如果已定义的 server_name 与Host头的值精准匹配时,这个server模块将被选择来处理请求。

在这个例子中,如果请求的Host头的值被设置为 host1.example.com,第二个server模块将被选中:

1
2
3
4
5
server{
listen 80;
server_name *.example.com;
...
}
1
2
3
4
5
server{
listen 80;
server_name host1.example.com;
...
}

如果精准的匹配没有被找到时,Nginx将会检查是否有一个具有适合前置通配符的 server_name 。以通配符开始的最长的 server_name 的server模块将会被选择来完成响应。

在这个例子中,如果请求的Host头是 www.example.org,第二个server模块将被选中:

1
2
3
4
5
server{
listen 80;
server_name www.example.*;
...
}
1
2
3
4
5
server{
listen 80;
server_name *.example.org;
...
}
1
2
3
4
server{
listen 80;
server_name *.org;
}

server_name 以通配符开始的模块没有找到,Nginx将查看在表达式后面有通配符的匹配项是否存在。此时,以通配符结尾的最长的匹配项将被用于服务客户端的请求。

在这个例子中,如果请求的Host头被设置为 www.example.com,第三个模块将被选中:

1
2
3
4
5
server{
listen 80;
server_name host1.example.com;
...
}
1
2
3
4
server{
listen 80;
server_name example.com;
}
1
2
3
4
server{
listen 80;
server_name www.example.*;
}

如果通配符匹配项没有找到,Nginx将会去匹配用了正则表达式的 server_name 。第一个匹配上的server模块将会被选中来响应请求。

在这个例子中,如果请求的Host头设置为 www.example.com,那么第二个server模块将被选中来完成响应。

1
2
3
4
5
server{
listen 80;
server_name example.com;
...
}
1
2
3
4
5
server{
listen 80;
server_name ~^(www|host1).*\.example\.com$;
...
}
1
2
3
4
5
server{
listen 80;
server_name ~^(subdomain|set|www|host1).*\.example\.com$;
...
}

如果上述步骤都不能满足请求,则该请求将被传递到默认的server模块以获取匹配的IP地址和端口。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创京东

创京东

李志刚 / 中信出版社 / 2015-5-1 / CNY 49.80

1998年,刘强东创业,在中关村经销光磁产品。2004年,因为非典,京东偶然之下转向线上销售。2014年,京东市值已超400亿美元,跻身全球前十大互联网公司之列。 这是一个听起来很传奇的创业故事,但只有当事人了解创业维艰。 刚转向电商时,传统企业前景光明,而电商看起来前途未卜,京东如何能毅然转型并坚持到底?资金匮乏的时候,京东靠什么说服投资人?在强大的对手面前,京东靠什么反超并一路领先......一起来看看 《创京东》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具