`

Nginx虚拟主机多server_name的顺序问题

阅读更多

今天在配置Nginx + PHP + MediaWiki中,发现一个问题:MediaWiki所在的Nginx虚拟主机绑定了多个域名,但是不管通过什么域名访问MediaWiki首页,都会被跳转到其中的一个域名上。Nginx配置文件中没有相关的rewrite跳转规则,那么就应该是MediaWiki的PHP程序做的跳转,但是,遍历了MediaWiki目录下的所有文件以及查询了MySQL数据库中的每个表,都没有发现记录有这个域名。后来,通过查看源代码发现MediaWiki是根据$_SERVER['SERVER_NAME']做的跳转,顺藤摸瓜,发现了下列问题:

  在一个Nginx虚拟主机中,可以绑定多个server_name,例如:
  点击在新窗口中浏览此图片

  而server_name的先后顺序的不同,对PHP程序中使用$_SERVER["SERVER_NAME"]或getenv('SERVER_NAME')获取服务器域名是有影响的:
  点击在新窗口中浏览此图片

  点击在新窗口中浏览此图片

  $_SERVER["SERVER_NAME"]或getenv('SERVER_NAME')获取的始终将是Nginx server_name配置中的第一个域名,这一点在程序开发中需要注意。这第一个域名就相当于Apache虚拟主机配置中的ServerName,后面的域名就相当于Apache的ServerAlias。

  PS:以下是网友Daze的留言,希望对本文读者有所帮助。

引用
在某些情况下(具体可参考 wiki.nginx.org),Nginx 内部重定向规则会被启动,例如,当 URL 指向一个目录并且在最后没有包含“/”时,Nginx 内部会自动的做一个 301 重定向,这时会有两种情况:
1、server_name_in_redirect on(默认),URL 重定向为: server_name 中的第一个域名 + 目录名 + /;
2、server_name_in_redirect off,URL 重定向为: 原 URL 中的域名 + 目录名 + /。

当你有多个域名要指向同一个虚拟主机,并且你自己写 301 重定向规则把它们合并到某一个域名时,情况就更复杂了:
首先,nginx 检查 URL,如果符合条件,就用该规则(你写的)做第一遍重定向,接着,检查新生成的 URL,如果符合内部自动重定向之条件,就用前面提到的规则再做一次重定向。

至于 PHP 的 $_SERVER["SERVER_NAME"],在 nginx 中默认是由 nginx 的变量 $server_name 提供,这时它和重定向没有关系,始终是 server_name 设置中的第一个域名,但这是可以被改变的,在你的 nginx 配置中找到 fastcgi_param 部分,修改
fastcgi_param  SERVER_NAME    $server_name;

fastcgi_param  SERVER_NAME    $host;
但现在就要注意了,此时的 $_SERVER["SERVER_NAME"] 会受你写的和 nginx 自己的重定向规则所影响而变化。

现在就清楚了,如果 MediaWiki 是通过 $_SERVER["SERVER_NAME"] 来自己处理 URL 的话,那么在 nginx + php 的默认环境下,它获得的将始终是 server_name 设置中的第一个域名,所以造成了“不管通过什么域名访问 MediaWiki 首页,都会被跳转到其中的一个域名上。”,这不是 nginx 的重定向造成的,虽然默认 server_name_in_redirect 是 on,但这个指令的影响范围仅仅只是 nginx 自己内部的重定向规则,所以,当你在 nginx + php 的环境中使用多域名虚拟主机,并且你的 php 库、框架、代码大量使用 $_SERVER["SERVER_NAME"] 时,你也许应该:
1、设置 fastcgi_param  SERVER_NAME    $host;
2、设置 server_name_in_redirect off; 让 nginx 在处理自己内部重定向时不默认使用  server_name 设置中的第一个域名;
3、不要使用 nginx 的 rewrite 规则来重定向、合并多个域名。
当然,后俩条是完全可选的,前提是你清楚你在做什么并且小心处理这时的  $_SERVER["SERVER_NAME"],也许更好的做法是保持 fastcgi_param  SERVER_NAME    $server_name; ,然后合理使用 $_SERVER["SERVER_NAME"] 和 $_SERVER["HTTP_HOST"]。

这个问题确实很微妙,也许我的理解还是不完全,好在还有 curl ,慢慢研究了。 :-)

P.S. nginx 0.7.x 之前的版本还有一个指令 optimize_server_names 会影响内部重定向规则。
分享到:
评论

相关推荐

    详解Nginx虚拟主机配置中server_name的具体写法

    在Nginx虚拟主机配置中,server_name是一个非常重要的参数,它用于定义虚拟主机对应的域名,从而使得浏览器可以通过不同的域名来访问到服务器上的不同网站或应用。 在server_name的配置中,可以设置一个或多个域名...

    一台nginx服务器多域名配置的方法

    Nginx中的server_name指令主要用于配置基于名称虚拟主机,server_name指令在接到请求后的匹配顺序分别为: 1、准确的server_name匹配,例如: server { listen 80; server_name ssdr.info www.ssdr.info; ... } 2...

    nginx常见问题整理和解决办法

    问题一:相同server_name多个虚拟主机优先级访问 server{ listen 80; server_name server1; location{...} } server{ listen 80; server_name server2; location{...} } 解决方法: 配置两个conf文件:server...

    使用Nginx实现灰度发布1

    2. **server模块**:这是Nginx监听的虚拟主机配置,用于处理特定域名的请求。`listen`指令指定监听的端口,`server_name`指定域名。 3. **access_log**:定义访问日志的存储位置和格式。 4. **set指令**:用于设置...

    nginx 配置指南

    # 配置虚拟主机 server { listen 80; # 监听端口 server_name example.com; # 服务器域名 location / { proxy_pass http://backend; # 将请求转发给后端服务器 proxy_set_header Host $host; # 传递原主机头...

    nginx学习笔记.docx

    它还可以包含多个 `server` 块,每个 `server` 块相当于一个虚拟主机,用于处理不同的域名或 IP 地址的请求。`server` 块可以进一步细分为: - **http 全局块**:配置 MIME 类型、日志格式等全局设置。 - **...

    适用于windows和linux下的的nginx.conf路由文件

    - `server_name`:设置虚拟主机的域名或IP。 - `root` / `document_root`:设置网站根目录。 - `index`:定义默认索引文件。 #### 2.5 location块 - `location`:根据请求的URI进行匹配,可以使用正则表达式。 - `...

    nginx详细配置

    - `server_name`: 设置虚拟主机的域名。 - `root`: 指定服务器根目录,用于查找静态文件。 - `index`: 指定默认首页文件。 - `error_page`: 定义错误页面。 - `proxy_pass`: 反向代理设置,将请求转发到其他服务器。...

    Nginx+Tomcat负载均衡配置教程

    - 打开浏览器,在地址栏输入`http://localhost/`,如果看到Nginx的欢迎页面,则说明已成功搭建虚拟主机。 #### 二、Nginx+Tomcat 集群配置 **1. 搭建Tomcat服务器** - **安装Tomcat**:按照官方文档安装Tomcat。 ...

    Nginx入门到精通搭建高可用集群负载均衡

    - `server` 块:定义虚拟主机,如 `listen 80` 和 `server_name localhost`。 - `location` 块:定义请求匹配规则,如 `/` 表示根目录,`proxy_pass` 实现反向代理。 **4. 反向代理与正向代理的区别** - **正向...

    使用Nginx轻松实现开源负载均衡

    - **创建虚拟主机**:在Nginx的配置文件中,为每个需要负载均衡的服务创建一个虚拟主机。 - **定义上游服务器**:在虚拟主机配置中,使用`upstream`块定义一组后端服务器,并指定负载均衡策略。 - **反向代理配置**...

    Nginx服务器详细资料

    - `nginx.conf`是主配置文件,包含多个server块,每个server块代表一个虚拟主机。 - server块内可以有location块,用于匹配特定的URL路径。 3. **配置示例**: - 设置监听端口: ```conf listen 80; ``` - ...

    ubuntu12.04安装Nginx+PHP5(PHP-FPM)+MySQL主机详解.pdf

    在这个文件中,你可以定义多个虚拟主机,但这里我们仅关注一个示例配置。确保`listen`指令指向正确的IP地址和端口(默认是80),并设置好网站根目录。`index`指令指定了默认的索引文件顺序。`server_name`可以设置为...

    nginx知识点.doc

    server 块通常用于配置虚拟主机,每个 server 块可以看作一个独立的 Web 服务器,可以有不同的监听端口、域名绑定和路由规则。 Nginx 的灵活性和强大的功能使其成为现代互联网架构中不可或缺的一部分,无论是用作...

    071201nginx配置 1

    总结来说,Nginx的配置涉及多个层面,包括服务器监听、虚拟主机、请求路由、错误处理等。正确理解和使用`listen`和`location`指令,可以实现高效、灵活的Web服务配置。同时,Nginx支持通过`killall -HUP nginx`命令...

    nginx-server-settings

    虚拟主机允许在单个Nginx实例上托管多个网站。通过`server_name`指令定义虚拟主机的域名,如`server_name example.com www.example.com;`。根据请求的Host头决定将请求路由到哪个`server`块。 5. **反向代理...

    ngnix的简单转发请求之server和location配置详解

    server指令定义了一个虚拟主机,即一个特定的网站或应用,其配置项中的listen指明了Nginx监听的端口,server_name则用于设置域名或者IP地址。location指令用于定义请求匹配的规则,决定请求如何转发,以及如何处理,...

Global site tag (gtag.js) - Google Analytics