一、问题描述
某次本平台和外部平台接口调用,同样Nginx location配置,测试环境调用正常,生产环境调用返回失败;
相关链接:Nginx官方文档、server_name、How nginx processes a request
二、排查处理
1)经排查最后发现为server_name 配置为localhost,而请求的head中携带的Host变量为其它,导致从主机外的请求无法正常转发到目标接口,而走默认的/,解析为外部地址,导致超时调用失败。Nginx日志报错如下:upstream timed out (110: Connection timed out) while connecting to upstream
2)修改server_name为同网站域名一直后,请求成功。
3)原因:
1、被调用接口方有Host字段验证;
2、Nginx本身机制安全限制,server_name是nginx配置文件中比较重要的参数之一,用于指定虚拟主机的域名或IP地址,指定由哪个server服务器块处理给定的请求。当一个请求头里的Host字段中的值和server_name匹配时,nginx将会使用该虚拟主机配置处理该请求。否则,Nginx会将请求交给默认server来处理,先看请求的端口有没有配置default_server指令,配置后由该server下location进行处理;如果所有的server都没有配置default_server指令,就会交给第一个开启了此端口的server处理。官方:如果服务器块中没有定义server_name,则nginx使用空名称作为服务器名称,在0.8.48以后会使用所在机器的主机名作为server_name;现场只有一个端口虚拟主机,不存在路由路由错误的问题,本次问题出现在对端应该限制了server_name 验证,比如配置了444。
三、Nginx server_name规则
server_name可以接受多个参数,但不要在server_name中使用逗号隔开的多个域名,一个nginx配置文件中可以有多个server_name相同的虚拟主机,nginx会尝试将这些参数与请求的Host头进行匹配。
1)使用server_name指定服务器的IP地址,按IP来匹配或路由:
server {
listen 80;
server_name 192.168.1.100;
location / {
root /var/www/html;
}
}
2)使用域名匹配:
server {
listen 80;
server_name www.example.com;
location / {
root /var/www/html;
}
}
3)使用正则表达式进行匹配二级域名,使用多个子域名情况下
server {
listen 80;
server_name ~^(www\.)?example\.com$; #匹配www.example.com或example.com两种域名
server_name *.example.com; #通配符方式
location / {
root /var/www/html;
}
}
4)禁止所有已解析未授权域名及IP访问
server {listen 80 default_server;listen 443 ssl default_server;#server_name _; #这里指任意server_name 10.54.12.129;ssl_certificate #ssl证书pem路径;ssl_certificate_key #ssl证书keym路径;return 444;
}
listen 80 default_server: 指定该 server 配置段为 80 端口的默认主机,即对于未绑定的域名指向你的服务器时,匹配不到你配置的虚拟主机域名后,会默认使用这个虚拟主机。
listen 443 ss default_server: 指定该 server 配置段为 443 端口的默认主机,即对于未绑定的域名指向你的服务器时,匹配不到你配置的虚拟主机域名后,会默认使用这个虚拟主机。
server_name : 此处的可以换成任意其他无效字符或无效的域名,表示该 server 配置不会被正常访问到。
return 444:设置默认ip的80、443端口下的所有为绑定域名访问后,直接关闭连接。444状态码是一种非标准状态代码,用于指示 Nginx 关闭连接而不向客户端发送响应,最常用于拒绝恶意或格式错误的请求。客户端看不到此状态代码,它仅出现在 nginx 日志文件中。
5)将所有未授权域名及IP访问跳转到指定网页
server {listen 80 default_server;server_name _;rewrite ^(.*) http://www.bjpt.cn permanent;
}