nginx學習筆記(8)虛擬主機名---轉載

通配符名字
正則表達式名字
其餘類型的名字
優化
兼容性

虛擬主機名使用server_name指令定義,用於決定由某臺虛擬主機來處理請求。具體請參考《nginx如何處理一個請求》。虛擬主機名可使用確切的名字,通配符,或者是正則表達式來定義:html

server {
    listen       80;
    server_name  example.org  www.example.org;
    ...
}

server {
    listen       80;
    server_name  *.example.org;
    ...
}

server {
    listen       80;
    server_name  mail.*;
    ...
}

server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;
    ...
}

nginx以名字查找虛擬主機時,若是名字能夠匹配多於一個主機名定義,好比同時匹配了通配符的名字和正則表達式的名字,那麼nginx按照下面的優先級別進行查找,並選中第一個匹配的虛擬主機:nginx

  1. 確切的名字;
  2. 最長的以星號起始的通配符名字:*.example.org
  3. 最長的以星號結束的通配符名字:mail.*
  4. 第一個匹配的正則表達式名字(按在配置文件中出現的順序)。

通配符名字

通配符名字只能夠在名字的起始處或結尾處包含一個星號,而且星號與其餘字符之間用點分隔。因此,「www.*.example.org」和「w*.example.org」都是非法的。不過,上面的兩個名字可使用正則表達式描述,即「~^www\..+\.example\.org$」和「~^w.*\.example\.org$」。星號能夠匹配名字的多個節(各節都是以點號分隔的)。「*.example.org」不只匹配www.example.org,也匹配www.sub.example.orgweb

有一種形如「.example.org」的特殊通配符,它能夠既匹配確切的名字「example.org」,又能夠匹配通常的通配符名字「*.example.org」。正則表達式

正則表達式名字

nginx使用的正則表達式兼容PCRE。爲了使用正則表達式,虛擬主機名必須以波浪線「~」起始:緩存

server_name  ~^www\d+\.example\.net$;

不然該名字會被認爲是個確切的名字,若是表達式含星號,則會被認爲是個通配符名字(並且極可能是一個非法的通配符名字)。不要忘記設置「^」和「$」錨點,語法上它們不是必須的,可是邏輯上是的。同時須要注意的是,域名中的點「.」須要用反斜線「\」轉義。含有「{」和「}」的正則表達式須要被引用,如:服務器

server_name  "~^(?<name>\w\d{1,3}+)\.example\.net$";

不然nginx就不能啓動,錯誤提示是:dom

directive "server_name" is not terminated by ";" in ...

命名的正則表達式捕獲組在後面能夠做爲變量使用:測試

server {
    server_name   ~^(www\.)?(?<domain>.+)$;

    location / {
        root   /sites/$domain;
    }
}

PCRE使用下面語法支持命名捕獲組:優化

?<name> 從PCRE-7.0開始支持,兼容Perl 5.10語法
?'name' 從PCRE-7.0開始支持,兼容Perl 5.10語法
?P<name> 從PCRE-4.0開始支持,兼容Python語法

若是nginx不能啓動,並顯示錯誤信息:ui

pcre_compile() failed: unrecognized character after (?< in ...

說明PCRE版本太舊,應該嘗試使用?P<name>。捕獲組也能夠以數字方式引用:

server {
    server_name   ~^(www\.)?(.+)$;

    location / {
        root   /sites/$2;
    }
}

不過,這種用法只限於簡單的狀況(好比上面的例子),由於數字引用很容易被覆蓋。

其餘類型的名字

有一些主機名會被特別對待。

若是須要用一個非默認的虛擬主機處理請求頭中不含「Host」字段的請求,須要指定一個空名字:

server {
    listen       80;
    server_name  example.org  www.example.org  "";
    ...
}

若是server塊中沒有定義server_name,nginx使用空名字做爲虛擬主機名。

nginx 0.8.48版本如下(含)在一樣的狀況下會使用機器名做爲虛擬主機名。

若是以「$hostname」(nginx 0.9.4及以上版本)定義虛擬主機名,機器名將被使用。

若是使用IP地址而不是主機名來請求服務器,那麼請求頭的「Host」字段包含的將是IP地址。能夠將IP地址做爲虛擬主機名來處理這種請求:

server {
    listen       80;
    server_name  nginx.org
                 www.nginx.org
                 ""
                 192.168.1.1
                 ;
    ...
}

在匹配全部的服務器的例子中,能夠見到一個奇怪的名字「_」:

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}

這沒什麼特別的,它只不過是成千上萬的與真實的名字絕無衝突的非法域名中的一個而已。固然,也可使用「--」和「!@#」等等。

nginx直到0.6.25版本還支持一個特殊的名字「*」,這個名字一直被錯誤地理解成是一個匹配全部的名字。但它歷來沒有像匹配全部的名字,或者通配符那樣工做過,而是用來支持一種功能,此功能如今已經改由server_name_in_redirect指令提供支持了。因此,如今這個特殊的名字「*」已通過時了,應該使用server_name_in_redirect指令取代它。須要注意的是,使用server_name指令沒法描述匹配全部的名字或者默認服務器。這是listen指令的屬性,而不是server_name指令的屬性。具體請參考《nginx如何處理一個請求》。能夠定義兩個服務器都監聽*:80和*:8080端口,而後指定一個做爲端口*:8080的默認服務器,另外一個做爲端口*:80的默認服務器:

server {
    listen       80;
    listen       8080  default_server;
    server_name  example.net;
    ...
}

server {
    listen       80  default_server;
    listen       8080;
    server_name  example.org;
    ...
}

優化

確切名字和通配符名字存儲在哈希表中。哈希表和監聽端口關聯。哈希表的尺寸在配置階段進行了優化,能夠以最小的CPU緩存命中失敗來找到名字。設置哈希表的細節參見這篇文檔

nginx首先搜索確切名字的哈希表,若是沒有找到,搜索以星號起始的通配符名字的哈希表,若是仍是沒有找到,繼續搜索以星號結束的通配符名字的哈希表。

由於名字是按照域名的節來搜索的,因此搜索通配符名字的哈希表比搜索確切名字的哈希錶慢。注意特殊的通配符名字「.example.org」存儲在通配符名字的哈希表中,而不在確切名字的哈希表中。

正則表達式是一個一個串行的測試,因此是最慢的,並且不可擴展。

鑑於以上緣由,請儘量使用確切的名字。舉個例子,若是使用example.orgwww.example.org來訪問服務器是最頻繁的,那麼將它們明確的定義出來就更爲有效:

server {
    listen       80;
    server_name  example.org  www.example.org  *.example.org;
    ...
}

下面這種方法相比更簡單,可是效率也更低:

server {
    listen       80;
    server_name  .example.org;
    ...
}

若是定義了大量名字,或者定義了很是長的名字,那可能須要在http配置塊中使用server_names_hash_max_sizeserver_names_hash_bucket_size指令進行調整。server_names_hash_bucket_size的默認值多是32,或者是64,或者是其餘值,取決於CPU的緩存行的長度。若是這個值是32,那麼定義「too.long.server.name.example.org」做爲虛擬主機名就會失敗,而nginx顯示下面錯誤信息:

could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

出現了這種狀況,那就須要將指令的值擴大一倍:

http {
    server_names_hash_bucket_size  64;
    ...

若是定義了大量名字,獲得了另一個錯誤:

could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

那麼應該先嚐試設置server_names_hash_max_size的值差很少等於名字列表的名字總量。若是還不能解決問題,或者服務器啓動很是緩慢,再嘗試提升server_names_hash_bucket_size的值。

若是隻爲一個監聽端口配置了惟一的主機,那麼nginx就徹底不會測試虛擬主機名了(也不會爲監聽端口創建哈希表)。不過,有一個例外,若是定義的虛擬主機名是一個含有捕獲組的正則表達式,這時nginx就不得不執行這個表達式以獲得捕獲組。

兼容性

  • 從0.9.4版本開始,支持特殊的虛擬主機名「$hostname」。
  • 從0.8.48版本開始,默認的虛擬主機名是空名字「」。
  • 從0.8.25版本開始,支持虛擬主機名中使用命名的正則表達式捕獲組。
  • 從0.7.40版本開始,支持虛擬主機名中使用正則表達式的捕獲組。
  • 從0.7.12版本開始,支持空名字「」。
  • 從0.6.25版本開始,通配符和正則表達式名字能夠做爲第一個虛擬主機名。
  • 從0.6.7版本開始,支持正則表達式的虛擬主機名。
  • 從0.6.0版本開始,支持形如example.*的通配符名字。
  • 從0.3.18版本開始,支持形如.example.org的特殊通配符名字。
  • 從0.1.13版本開始,支持形如*.example.org的通配符名字。

做者: Igor Sysoev編輯: Brian Mercer翻譯: cfsego
相關文章
相關標籤/搜索