nginx 的 server names

nginx 的 server names
===================

編譯自:
http://nginx.org/en/docs/http/server_names.htmlhtml


目錄:
    通配符主機名
    正則表達式主機名
    混雜主機名
    對主機名的優化
    兼容性
nginx

nginx 的 server names 由 server_name 指令定義,server name 是 nginx 用於選擇以哪一個 server 區塊處理訪問請求的依據參數。可參考 《nginx 是如何處理請求的》 的描述。git

server name 能夠用三種方式定義:
    定義準確的名字
    定義通配符名字
    定義正則表達式名字
正則表達式

例如:緩存

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

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

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

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

當 nginx 以請求的 server name 查找匹配的虛擬主機時,若是匹配的 server 區塊不止一個,nginx 按照以下的優先順序選擇 server 區塊:ui

    1. 準確的主機名
    2. 以 「*」 起始的最長的通配主機名
    3. 以 「*」 結尾的最長的通配主機名 
    4. 第一個匹配的正則表達式(按照配置文件中的順序)
    
因此,若是同時有一個通配主機名和正則表達式主機名與訪問請求的 server name 匹配,nginx 會選擇通配主機名的 server 區塊處理請求。


通配主機名
-----------

通配主機名只能在起始和末尾使用 「*」 字符,並且必須以 「.」 分隔。形如 「www.*.example.org」 或者 「w*.example.org」 的通配主機名是無效的。要達到這個匹配效果,只有使用正則表達式:

"www.*.example.org" ->     "~^www\..+\.example\.org$"
"w*.example.org"    ->     "~^w.*\.example\.org$"


「*」 號能夠匹配多個名字區域,「*.example.org」 不只能夠匹配 www.example.org,也可以匹配 www.sub.example.org。


正則表達式主機名
-----------------

nginx 使用的正則表達式與 Perl 語言的正則表達式(PCRE)兼容。使用正則表達式主機名,server name 必須以 「~」 字符爲起始字符。

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

若是不以 「~」 字符爲起始字符,該 server name 將被視爲 「準確的主機名」 或者當 server name 包含 「*」 時被視爲 「通配主機名」 (多數狀況是非法通配主機名,由於只有當 「*」 在 server name 的起始或結尾時才合法)。

不要忘記設置 「^」 和 「$」 錨定符對主機名進行界定,這不是 nginx 的配置語法要求,而是爲了使正則表達式能正確匹配。

同時也要注意,域名的分隔符 「.」 在正則表達式中應該以 「\」 引用。若是在正則表達式中使用了 「{」 和 「}」 字符,應該將整個正則表達式引用起來,由於花括弧在 nginx 配置中也有特殊意義,引用起來以免被 nginx 錯誤解析。例如:

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

若是不引用起來,nginx 會啓動失敗,並顯示以下錯誤信息:

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

正則表達式的 named capture (使用一個名字對匹配的字符串進行引用)可被視爲一個變量,在後面的配置中使用:
    
    server {
        server_name   ~^(www\.)?(?<domain>.+)$;

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

PCRE 庫支持 named capture,有以下幾種語法:

    ?<name>     Perl 5.10 compatible syntax, supported since PCRE-7.0
    ?'name'     Perl 5.10 compatible syntax, supported since PCRE-7.0
    ?P<name>    Python compatible syntax, supported since PCRE-4.0
    

    可參考:http://www.pcre.org/current/doc/html/pcre2pattern.html#SEC16  
   \d     any decimal digit
   \w     any "word" character

    
若是 nginx 啓動失敗,並顯示以下信息:

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

這表示 PCRE 庫太老舊,可嘗試使用 「?P<name>」 替代 「?<name>」。

named capture 也能以數字形式使用:
    
    server {
        server_name   ~^(www\.)?(.+)$;

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

不管如何,數字形式的使用應儘可能簡單,由於數字是隻是順序標識,而不是被匹配的字符串的標識,這致使數字引用很容易被覆蓋。


混雜主機名
-------------

有一些主機名是被特殊對待的。

對於未定義 「Host」 請求首部的請求,若是但願在某個 server 區塊中處理這樣的請求,應在 server_name 
指令的參數中添加 "" 空字符串參數:

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

    
《nginx 是如何處理訪問請求的》一文中曾經介紹過,若是 server 區塊中沒有定義 server_name 指令,便如同定義了 server_name ""。
    
    Note:
    在 0.8.48 版之前,遇到 server 區塊中沒有定義 server_name 指令的狀況,
    會將系統的主機名設置爲 server 區塊的 server name,而不是自動設置 "" 爲
    server name。

在 0.9.4 版本,若是設置:server_name $hostname,會將系統的主機名設置爲 server name。

若是某個訪問使用了 IP 地址 而不是 server name,「Host」 請求首部會包含 IP 地址。對於這樣的請求,
可以使用以下的配置:
    
    server {
        listen       80;
        server_name  example.org
                     www.example.org
                     ""
                     192.168.1.1
                     ;
        ...
    }


下面是一個 catch-all server 區塊的配置,使用了 「_」 做爲 server name:
    
    server {
        listen       80  default_server;
        server_name  _;
        return       444;
    }

這個 server name 並無什麼特殊之處,它僅是一個無效的域名而已,也可使用其餘相似的名字,如 「--」 and 「!@#」 。0.6.25 版之前的 nginx 曾經支持一個特殊的 server name: 「*」,這個特殊主機名被錯誤的解釋成一個catch-all 主機名。但它從未以一個 catch-all 或者 通配主機名工做,它的功能實際上與如今的 server_name_in_redirect 指令的功能相同。

特殊的 server name 「*」 如今已經被棄用,應使用 server_name_in_redirect 指令。

要注意的是,使用 server_name 指令沒法指定 defalt server 或是 catch-all name,這是 listen 指令的屬性,不是 server_name 指令的屬性。可參考《nginx 是如何處理訪問請求的》

咱們能夠定義兩個 server,它們都同時監聽於 *:80 端口 和 *:8080 端口,將其中一個設置爲 *:80 端口的默認 server,將另外一個設置爲 *:8080 端口的默認 server:

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

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

 

對主機名的優化
------------

準確的主機名、以 「*」 起始的通配主機名、以 「*」 結尾的通配主機名,這三種主機名被存放在三個 hash table 中。這三個 hash table 是與監聽端口綁定的。hash table 的大小在配置階段
被優化,優化的目的是努力下降這些名字在 CPU 緩存中命中失敗的概率。關於設置 hash table 的詳細討論請參考:http://nginx.org/en/docs/hash.html

在匹配主機名時,首先查找「準確主機名」的 hash table,若是沒有找到,會查找以 「*」 起始的「通配主機名」的hash table,若是沒有仍未找到,會查找以 「*」 結尾的「通配主機名」的 hash table。

對於「通配主機名」的 hash table 的檢索會更慢,由於是以主機名的域名部分去檢索的。

注意,對於特殊的通配主機名,形如 「.example.org」,這樣的主機名是存放在「通配主機名」的 hash table 中,而不是存放在「準確主機名」的 hash table 中。

若是前面都未找到,正則表達式會按寫在配置文件中的順序被測試,所以正則表達式是最慢的方法,而且沒有可擴展性。

由於以上這些緣由,在可能的狀況下最好使用 「準確的主機名」。例如,若是對於 example.org 和 www.example.org 的請求最爲頻繁,對他們進行顯式的定義會更有效率:

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

下面的定義方法不如上面的配置有效率:
    
    server {
        listen       80;
        server_name  .example.org;
        ...
    }

若是定義了大量的主機名,或者使用了很長的主機名,應在配置文件的 http context 中調整這個兩個參數:
    server_names_hash_max_size     
    server_names_hash_bucket_size

server_names_hash_bucket_size 指令的默認值可能爲 32 或 64 或 其餘數字,這是根據 CPU 緩存線大小而定的。若是默認值爲 32,並且定義了一個 server name 爲:「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 name 總數的值。若是這樣設置仍不能讓 nginx 正常啓動,或者 nginx 啓動的時間變得過長,再嘗試增長 server_names_hash_bucket_size 的值。

若是一個 server 是某個監聽端口惟一的 server,這時 nginx 根本不會去測試 server name,同時也不會爲該監聽端口構建 hash table。但其中又有一個例外,若是 server name 是正則表達式,並且正則表達式中包含了 captures,這時 nginx 不得不執行該正則表達式以獲取 captures。(正則表達式的 capture 是指被圓括號引用的表達式部分,它們所匹配的字符串,可經過名字或數字引用)


兼容性
-----------

從 0.9.4 開始支持特殊主機名 「$hostname」
從 0.8.48 開始,若是 server 區塊中未定義 server_name 指令,nginx 默認設定空字符串爲主機名,如同定義了 server_name ""

從 0.8.25 開始支持在「正則表達式主機名」中使用 named capture 特性
從 0.7.40 開始支持在「正則表達式主機名」中使用 capture 特性
從 0.7.12 開始支持 "" 空字符串主機名
從 0.6.25 開始,支持使用「正則表達式主機名」或者「通配主機名」做爲第一個主機名。
從 0.6.7 開始支持「正則表達式主機名」
從 0.6.0 開始支持形如 example.* 的「通配主機名」
從 0.3.18 開始支持形如 .example.org 的特殊「通配主機名」
從 0.1.13 開始支持形如 *.example.org 的「通配主機名」

written by Igor Sysoev edited by Brian Mercer

相關文章
相關標籤/搜索