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 會影響內部重定向規則。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章