nginx 可以通过 listen 的 ip 和端口来匹配请求应该由哪个配置文件来处理,也可以通过 server_name 来匹配,抽空理了理这个匹配的规则和优先级,参考文档:
基于域名的虚拟主机
默认是先匹配 listen 的 ip 和端口,匹配到了再检查 server_name,如果没有匹配的 server_name,则由第一个来处理,除非添加 default_server
1 2 3 4 5 6 7 8 9 10 11 12 13
| server { listen 80; server_name example.net; default_type application/json; return 200 '{"server_name":"$server_name", "host": "$host", "server_addr":"$server_addr"}'; }
server { listen 80; server_name example.com; default_type application/json; return 200 '{"server_name":"$server_name", "host": "$host", "server_addr":"$server_addr"}'; }
|
测试一下:
1 2 3 4 5
| > curl 10.0.0.100 -H "host:example.com" {"server_name":"example.com", "host": "10.0.0.100", "server_addr":"10.0.0.100"}
> curl localhost {"server_name":"example.net", "host": "localhost", "server_addr":"127.0.0.1"}
|
在这个配置中,nginx 仅仅检查请求的“Host”头以决定该请求应由哪个虚拟主机来处理。如果 Host 头没有匹配任意一个虚拟主机,或者请求中根本没有包含 Host 头,那 nginx 会将请求分发到定义在此端口上的默认虚拟主机。在以上配置中,第一个被列出的虚拟主机即 nginx 的默认虚拟主机——这是 nginx 的默认行为。而且,可以显式地设置某个主机为默认虚拟主机,即在 “listen” 指令中设置 “default_server” 参数:
如果同样的 listen 配置了两个 default_server 则会报错 nginx: [emerg] a duplicate default server for 10.0.0.100:80 in /etc/nginx/conf.d/test.conf:9
基于域名和 IP 混合的虚拟主机
Nginx 首先选定由哪一个虚拟主机来处理请求。让我们从一个简单的配置(其中全部 2 个虚拟主机都在端口 *:80
上监听)开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| server { listen localhost:80; server_name example.org; default_type application/json; return 200 '{"server_name":"$server_name", "host": "$host", "server_addr":"$server_addr"}'; }
server { listen 10.0.0.100:80; server_name example.net; default_type application/json; return 200 '{"server_name":"$server_name", "host": "$host", "server_addr":"$server_addr"}'; }
server { listen 10.0.0.100:80; server_name example.com; default_type application/json; return 200 '{"server_name":"$server_name", "host": "$host", "server_addr":"$server_addr"}'; }
|
这个配置中,nginx 首先测试请求的 IP 地址和端口是否匹配某个 server 配置块中的 listen 指令配置。接着 nginx 继续测试请求的 Host 头是否匹配这个 server 块中的某个 server_name 的值。如果主机名没有找到,nginx 将把这个请求交给默认虚拟主机处理。
例如,一个从 10.0.0.100:80 端口收到的访问 a.example.com 的请求将被监听 10.0.0.100:80 端口的默认虚拟主机处理,本例中就是第二个服务器,因为这个端口上没有定义名为 a.example.com 的虚拟主机。
我们可以测试一下:
1 2 3 4 5 6 7 8 9 10 11
| > curl localhost {"server_name":"example.org", "host": "localhost", "server_addr":"127.0.0.1"}
> curl 10.0.0.100 {"server_name":"example.net", "host": "10.0.0.100", "server_addr":"10.0.0.100"}
> curl 10.0.0.100 -H "host:example.com" {"server_name":"example.com", "host": "example.com", "server_addr":"10.0.0.100"}
> curl 10.0.0.100 -H "host:a.example.com" {"server_name":"example.net", "host": "a.example.com", "server_addr":"10.0.0.100"}
|
server_name 为空
看一个例子,如果不允许请求中缺少“Host”头,可以定义如下主机,丢弃这些请求:
1 2 3 4 5
| server { listen 80; server_name ""; return 444; }
|