浅析nginx配置server_name为多个时的坑
一、问题背景
我们一个服务器设置了2个域名,分别对应2个项目。监听 80 端口写了2个 server_name。比如这样server_name配置改为:
# 只列出了我们关心的配置,省略了其他无关部分
server {
server_name www.abc.com test.dce.com;
}
见这篇文章有类似问题:https://blog.csdn.net/u011296355/article/details/106740860
二、问题定位
根据业务上报错时打的日志,定位到请求公共处理的部分里有这么一个判断:
if ($_SERVER['SERVER_NAME'] != parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) {
$this->redirectError();
}
判断请求referer里解析出的域名如果和nginx里的$server_name变量里的域名如果不一样,就跳到错误页面,也是前面说的问题。
那么问题来了,看referer中的域名为什么和 $_SERVER['SERVER_NAME'] 不一致呢?我请求用的链接形式如 http://test.daemoncoder.com/xxx 这种形式,但是最终在PHP这一层取到 $_SERVER['SERVER_NAME'] 的值为 www.daemoncoder.com,而 HTTP_REFERER 里的域名为:test.daemoncoder.com。
可以看到 SERVER_NAME 的取值和我们的预期不一致,nginx是怎么把这个变量传过来的,需要从 nginx 的 fastcgi_params 配置文件中找一下 SERVER_NAME 的定义:
fastcgi_param SERVER_NAME $server_name;
可以看到 nginx 里的 $server_name 变量就是我们PHP里取的$_SERVER['SERVER_NAME'] 的来源。
三、问题的原因
通过上面的定位,我们基本可以看到问题的根本原因了:
当nginx配置里一个server节点下,server_name配置多个域名时,$server_name变量的值都是配置的第一个。
再回顾下我的 nginx 配置,所以就知道 $server_name 始终是 www.abc.com 的原因了。
四、解决方式
1、第一种方式就是把配置文件按域名拆分到各自单独的server节点下,也就是
# 省略其他无关部分
server {
server_name www.abc.com;
}
server {
server_name test.dce.com;
}
这样用不同的域名访问会落到各自对应的配置中,解析到的 $server_name 也都是各自的值。
2、第二种方式是修改 nginx SERVER_NAME 使用 $host 变量, 也就是把
fastcgi_param SERVER_NAME $server_name;
// 修改为:
fastcgi_param SERVER_NAME $host;
3、$host 变量的解析都是当前请求的host,不会受 server_name 是否配置多个域名的影响。