今天在配置Nginx多个虚拟主机的时候,发现一个问题,访问一个虚拟主机里的资源,结果却访问到了另外一个虚拟主机中的资源,赶紧去看看了官方文档,补补知识,在此记录一下Nginx是如何选定由哪个虚拟主机去处理请求的。
问题及现象
由于公司应用较多,所以单独选择了一个地方存放应用的Nginx配置文件,在Nginx主配置文件中引入这个路径的配置文件就可以了。
在配置某个应用程序(rsfw_origin.conf)需要临时支持下https的时候,要求关闭http,只允许https。于是复制该应用配置文件为一个名字(rsfw_https.conf),修改新配置文件里的一些与原有配置文件冲突的命名,比如upstream_server的名字等。并且关闭了http,只开启了https。两个配置文件内容大体如下:
rsfw_https.conf
rsfw_origin.conf
然后浏览器访问:https://rsfw.wisedu.com/test/sys/emaphome/portal/index.do
输入用户名密码登录认证,没有问题。
接着浏览器访问:http://rsfw.wisedu.com/test/sys/emaphome/portal/index.do
我原以为应该是访问不了,结果竟然还跳到了登录页面。两个虚拟主机,我访问其中一个虚拟主机下的资源,怎么会跳到另外一个虚拟主机下寻找资源呢?(两个虚拟主机下都有location /test)
查看nginx的error.log,发现是server: testdt.wisedu.com这台虚拟主机响应了请求(看下面的server:testdt.wisedu.com):
由此可见,Nginx对于使用哪个虚拟主机来处理用户请求应该有自己的一套规则,于是赶紧去官方文档找找资料。
原因及解决
官方文档:http://nginx.org/en/docs/http/request_processing.html
中文文档:https://tengine.taobao.org/nginx_docs/cn/docs/http/request_processing.html#how_to_prevent_undefined_server_names
总结一下,就是nginx会检测请求中的port是否匹配某个server配置块中listen指令,接着nginx继续测试请求的Host头是否匹配这个server块中的某个server_name的值。
如果主机名没有找到,nginx将把这个请求交给默认虚拟主机处理。第一个被列出的虚拟主机即nginx的默认虚拟主机——这是nginx的默认行为。而且,可以显式地设置某个主机为默认虚拟主机,即在”listen”指令中设置”default_server”参数:
在上面的例子中,由于rsfw_https.conf中的虚拟主机监听在了443端口,所以当我浏览器访问http://rsfw.wisedu.com/test/sys/emaphome/portal/index.do,不会被rsfw_https.conf中的虚拟主机rsfw.wisedu.com匹配到,于是交到了监听80端口的默认虚拟主机testdt.wisedu.com。
接着做个实验,重新写一个配置文件,同时手动指定默认虚拟主机。新建一个配置文件wisedu_fe.conf,在其中加上default_server配置,如下:
加了default_server,这台新的虚拟主机就成为了默认虚拟主机。重载Nginx配置文件。
浏览器输入http://rsfw.wisedu.com/test/sys/emaphome/portal/index.do
结果:浏览器显示404,而不在登录界面了。
error.log日志:
相应的server也变为了server: ressignal.wisedu.com