1. 程式人生 > >Nginx的虛擬服務器域名配置

Nginx的虛擬服務器域名配置

頭部 這一 配置 example article log perl 引號 點號

虛擬服務器名(server name)是通過指令server_name來指定的。在《 Nginx是如何處理Request的?》一節中,我們講到nginx分兩步來匹配過來的Request請求: 1.選擇server 2.選擇location 在第1步中,其實也分兩步: 1).匹配port 2).匹配server_name 這一節就來聊聊nginx是如何具體匹配server_name的。

server_name指令 server_name的形式有三種: 1.精確域名形式(exact names) 2.通配符(*)形式 3.正則表達式形式 如下: 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$; ... } 通配符形式,其實又分為前向通配符
後向通配符(分別如第二,第三個例子),通配符不能位於字符串的中間位置。 當然,完全存在這麽一種情況,一個host同時匹配上面三種的一種或者多種形式,比如host 為www.example.com可以同時匹配; server_name *.example.com *.com www.example.com www.example.* www.* ~^(.+)\.example\.com$ server_name 有6個指令參數,www.example.com都是匹配的,那麽最後選擇哪一個呢?有一定的順序:
  1. 精確域名匹配,www.example.com
  2. 以通配符*開始的,最長的那個域名
    ,*.example.com
  3. 以通配符*結束的,最長的那個域名,www.example.*
  4. 最後是正則表達式形式的,按照在配置文件中出現的順序,依次嘗試進行匹配,選取第一個被匹配到的域名,~^(.+)\.example\.com$
精確域名形式非常簡單,接下來分別對server_name的通配符和正則表達式兩種形式做個介紹。 通配符 通配符*在server name中的使用非常嚴格:只能位於域名的頭部或者尾部,不能出現在中間;並且必須以"."分隔開: *.example.com www.example.* 以下都是不合法的形式: www.*.example.org w*.example.org 當然,如果要達到後兩者所體現的目的,可以使用正則表達式,例如,上面不合法的兩個域名可以寫成這樣: ~^www\..+\.example\.org$ ~^w.*\.example\.org$ 另外一種特殊的形式可以同時匹配example.org和*.example.org,這就是 .example.org
正則表達式 nginx的正則表達式語法使用的是Perl語言(PCRE)的正則語法。基本形式為 server_name ~^www\d+\.example\.net$; 這則表達式需要註意的幾點
  • 必須以~開始,沒有~符號的要麽被視作完全匹配或者通配符匹配
  • ~和正則表達式主體之間沒有空格
  • 正則表達式主體通常以^開始以$結束(雖說語法上不一定要求如此,但是從邏輯意義上強烈要求這麽做)。
  • 正則表達式中,點號"."必須轉義,寫作"\.";正則表達式可以不用引號包住,但是,如果其中包含"{"和"}"則必須用雙引號包裹
例如: server_name "~^(?<name>\w\d{1,3}+)\.example\.net$"; 如果不加引號,nginx便無法正確加載配置文件,並報一個錯誤: directive "server_name" is not terminated by ";" in ... 正則表達式使用命名捕獲組,例如: server { server_name ~^(?<myname>.+)\.example\.cn$; root /var/www/hb/$myname; } PCRE語法支持下面幾種捕獲語法: ?<name> ?‘name‘ ?P<name> 前面兩者是最新的語法,第三種是老的寫法。如果nginx報下面錯誤: pcre_compile() failed: unrecognized character after (?< in ... 說明,你應該將?<name>或者?‘name‘改為較古老的?P<name>寫法了。 同樣,使用普通捕獲組也是可以的: server { server_name ~^(.+)\.example\.cn$; root /var/www/hb/$1; } 當然,普通捕獲組要慎用,因為很容易被後面的正則所覆蓋。 其他形式 除了兩面提到的幾種形式,sername_name的指令參數還有可能是其他的幾種形式。 如果請求Request沒有Host的頭部,那麽如果想要匹配,可以用空字符串: server { listen 80; server_name example.org www.example.org ""; ... } 另外,如果在server上下文中,沒有定義 server_name,那麽nginx使用空字符串作為虛擬機名稱。 如果使用IP而不是域名來發起請求,那麽Host請求頭就是一個IP,此時server_name也可以寫成一個IP: server { listen 80; server_name example.org www.example.org "" 192.168.1.1 ; ... } "_"可以用來匹配所有的域名 server { listen 80 default_server; server_name _; return 444; } 其他的字符,"-"和"!@#"也是可以的。註意,匹配所有域名的不能是"*"最佳實踐 我們知道nginx是一個款高性能的web服務器,其設計充滿了許多優化的技巧。在使用的時候也不例外,如果我們能對nginx的設計原理有一些了解,我們在配置時就能很好的利用這些設計,從而使得nginx的效率達到最大化。 前面提到,server_name的指令參數匹配有一定的匹配順序,即最先匹配精確域名形式,然後匹配以通配符*開始的域名,其次匹配以通配符*結束的域名,最後是匹配正則形式。如果前面匹配到了,就會終止繼續匹配。 從原理上說,這是因為,nginx會為每個監聽的port分別維護精確域名,前向通配符和後項通配符的Hash表。Hash表能在nginx啟動的配置階段得到創建和優化。精確域名的Hash表首先被搜尋,如果找不到,前向通配Hash表會被接著被搜尋,如果也沒有找到,那麽後向通配Hash表會被搜尋。搜尋通配Hash表要比精確域名Hash表要慢,因為其是按照域名的部分來做搜尋的(比如,*.example.com,會搜尋example和com部分)。 值得註意的是:".example.org"被存在通配Hash表裏面,並沒有存在精確Hash表裏面,因此匹配它是較慢的。 如果以上兩種方式都還沒有匹配上,那麽最後輪到正則形式的指令上場了。正則形式的域名是按照先後順序一個一個的去匹配的,沒有存入任何Hash表,匹配到正確的就結束,因此,這是最慢的形式,沒有任何“技巧”可言。 因此,最好的配置方式就是,盡可能使用精確域名,其次是通配符形式的,最後是正則形式。即便是正則形式域名,也要根據實際需要將用的最多的域名盡量前置。這樣方可使得nginx的性能達到最大化。 例如: server { listen 80; server_name example.org www.example.org *.example.org; ... } 這種方式要優於: server { listen 80; server_name .example.org; ... } 長域名,多域名的情況 在某些情況下,域名會非常的長,nginx不會允許其無限長,默認最大為32。在http上下文中,你可以通過server_names_hash_bucket_size指令來設置,可選參數有32,64(2的N次方)等 例如,如果域名被定義為:"too.long.server.name.example.org",超過32字符,那麽會報錯: could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32 解決方式: http { server_names_hash_bucket_size 64; ... 在另一些情況下,server_name配置的域名又很多,nginx同樣可能報錯:
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的值(例如將2^N調整到2^(N+1)) http { server_names_hash_max_size:600 server_names_hash_bucket_size 32; ...
如果一個域名是某個監聽端口下的唯一域名,那麽nginx就不會建立Hash匹配表,也不會有上面介紹的那些匹配流程,然而,如果這個唯一的域名是一個捕獲組正則表達式,那麽nginx還是去嘗試去解析正則表達式以提取這個字段。

Nginx的虛擬服務器域名配置