我在 Nginx 中遇到了一个奇怪的行为,请求的主机名后面有一个点,而domain.com.
不是domain.com
单独的一个。我设置了一个简单的服务器配置来测试,如下所示:
server {
listen 80;
server_name example.com.;
root /var/www/example;
index server1.txt;
}
server {
listen 80;
server_name example.com;
root /var/www/example;
index server2.txt;
}
最初,我预计对 的请求example.com.
将被发送到第一个块,对 的请求example.com
将被发送到第二个块。对于Host
标头与任何块都不匹配的请求(例如)www.example.com
,我预计会再次发送到第一个块,因为它是隐式默认值。
然而,经过测试,我发现,请求example.com.
被发送到第二块。在尝试了各种替代名称、正则表达式等一段时间后,我决定将$host
变量写入自定义标头,以便查看它。结果发现 Nginx 实际上是放下值的尾随点$host
。据我所知,在 收到的请求example.com.
被认为与在 收到的请求相同example.com
,至少就服务器选择而言。这似乎是不可取的,因为尾随点可能会导致各种错误。。
更令人困惑的是,经过谷歌搜索后我发现Nginx 更新日志页面,在 0.1.29 更新日志中有:
错误修复:nginx 没有考虑“Host”标题行中的尾随点。
几年后,1.5.9 更新日志写道:
错误修复:解析器无法理解带有尾随点的域名。感谢张亦春。
虽然我不确定“解析器”是否是指 Nginx 在收到请求时正在运行的组件。(从阅读文档来看,听起来解析器可能不会执行任何操作,除非将请求转发到其他主机,然后必须解析其名称。)
这是怎么回事?Nginx 在评估服务器名称时是否应该删除尾随的点?如果是预期行为,是否也应该从参数中删除尾随的点server_name
以产生“冲突的服务器名称”错误?
我知道,没有尾随点的域名在技术上是“相对”域名,而不是“绝对”域名,尽管现在大多数人似乎都将它们视为与区域相关的域名,.
因此实际上没有区别。但如果需要,Nginx 至少应该能够做出这种区分吗?
最后,有没有example.com.
比添加更好的方法来捕获和重定向对 的请求if ($http_host = 'domain.com.')
?我一直在告诉这是低效的,因为它需要对Host
标题进行两次评估。
答案1
在 DNS 级别,example.com
和example.com.
是同一个名称。这不仅仅意味着它们应该被同等对待,还意味着它们都将在 DNS 数据包中编码为完全相同的八位字节序列。在使用 DNS 的协议(例如 HTTP)中尝试将它们视为不同肯定会引起混乱和问题。
如果某个软件使用来自 DNS 的名称,并将带尾随点和不带尾随点的相同名称视为不同,则该软件存在缺陷。
答案2
TLDR;
这看起来像是一个 Nginx 错误,可能是因为很少有人知道完全合格的域名以点结尾。
背景
我必须仔细阅读你的陈述“完全合格的域名以点结尾”。我发现这一有用的资源这很好地解释了这一点。还有一个 SF这里有问答。似乎只有极少数人(直到现在包括我自己)知道域名后面还可以有一个点。
笔记
请注意,“主机头”和“Nginx 服务器名称”完全不同。服务器名称定义 Nginx 服务器将回复的请求。“主机头”是客户端发送给服务器的 http 头的一部分。
例子
我尝试了您的示例服务器,将 example.com 映射到我的服务器,结果与您在 nginx 1.9.11 上的结果相同。我还尝试了仅定义服务器“example.com.”但没有定义“example.com”。当我卷曲该配置时,我收到了来自我的默认服务器的响应,而不是“example.com.”服务器。
文档
这Nginx server_name 文档没有提到结尾的点。文档允许在点后使用通配符 (example.com.*)。我想知道编写文档的人是否知道完全限定域名。
理论
不过,我不得不怀疑,如果你在 Nginx 中定义“example.com”和“example.com。”,它们有什么区别?“example.com”必须被假定为来自 DNS 根的完整 URL,因此它后面有一个假定的“。”。
结论
我认为从技术上来说,您可能是正确的,Nginx server_name 应该考虑尾随的点。出于上述原因,我不确定它是否应该将其与没有尾随点的 server_name 区别对待。
这似乎是由于疏忽而导致的 Nginx 错误。这也可能是故意的,基于常见做法,而不是请求函数。