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; }
|