虚拟服务器名(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的虚拟服务器域名配置的更多相关文章

  1. LNMP(linux+nginx+mysql+php)服务器环境配置【转载】

    本文转载自 园友David_Tang的博客,如有侵权请联系本人及时删除,原文地址: http://www.cnblogs.com/mchina/archive/2012/05/17/2507102.h ...

  2. Nginx反代服务器基础配置实践案例

    转载自:https://www.bilibili.com/read/cv16149433?spm_id_from=333.999.0.0 方式1: 轮询 RR(默认轮询)每个请求按时间顺序逐一分配到不 ...

  3. LNMP(linux+nginx+mysql+php)服务器环境配置

    一.简介 Nginx是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为 “engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理服 ...

  4. Nginx和Apache服务器上配置反向代理

    在实际项目过程中,由于网站要用到一个在线编辑器(个性化的在线编辑软件),需要跨域进行通信!由于跨域通信较多,所以当时就想到在网站服务器上代理编辑软件的请求! 这就是“反向代理”的实际需求! 一.Ngi ...

  5. 基于nginx的虚拟主机的配置

    安装pcre tar -xvf pcre-8.32.tar.gz cd pcre-8.32 ./configure make;make install 安装nginx 首先创建一个nginx用户,以n ...

  6. phpstudy 虚拟主机域名配置注意问题

    第一步:hosts文件中添加对应:127.0.0.1+空格+你的域名 第二部:在D:\phpStudy \Apache\conf\vhosts.conf中禁用470行 第三部:配置域名和引入程序地址

  7. nginx 同一 iP 多域名配置方法(多文件)

    一.Nginx 配置文件(nginx version: nginx/1.12.2) 路径:/usr/local/nginx/conf/nginx.conf 操作:在 http 模块增加(子配置文件的路 ...

  8. nginx静态资源服务器简单配置

    有时候我们可以把服务器的一些文件放在固定目录以便下载,比如image,css,js等.就可以使用nginx转发静态资源. 参考链接:https://blog.csdn.net/name_is_wl/a ...

  9. nginx同一iP多域名配置方法

    文章转自:http://blog.itblood.com/nginx-same-ip-multi-domain-configuration.html 下面的是我本机的配置: server { list ...

随机推荐

  1. mongodb 3.4 集群搭建:分片+副本集

    mongodb是最常用的nodql数据库,在数据库排名中已经上升到了前六.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群. 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置 ...

  2. [UWP]了解模板化控件(6):使用附加属性

    1. 基本需求 之前的ContentView2添加了PointerOver等效果,和TextBox等本来就有Header的控件放在一起反而变得鹤立鸡群. 为了解决这个问题,这次把ContentView ...

  3. C#:StreamReader读取.CSV文件(转换成DataTable)

    using System.Data; using System.IO; /// <summary> /// Stream读取.csv文件 /// </summary> /// ...

  4. SuperSocket 最基础入门

    ---恢复内容开始--- SuperSocket 是什么? 首先我们明确一下SuperSocket 本质是什么? 网络框架 !  ok , 那么我们直接上上官网,作者已经开源到Github,可以做两件 ...

  5. 理解new构造函数和apply以及call

    今天在看设计模式的时候,遇到一些挺低级的东西,搞不懂,顾查阅资料整理记录一番. 先了解一下new构造函数的过程: function func(){ console.log('do'); } var f ...

  6. Android测试:Building Local Unit Tests

    原文:https://developer.android.com/training/testing/unit-testing/local-unit-tests.html 如果你的单元测试没有依赖或者只 ...

  7. 初识QT

    前言:这是写给纯小白看的文章,大神可以自行绕道. QT的优势(摘自360百科): Qt支持下列操作系统: Microsoft Windows 95/98, Microsoft Windows NT, ...

  8. K:java中序列化的两种方式—Serializable或Externalizable

    在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...

  9. getComputedStyle与currentStyle获取样式(style/class)

    今天看jQuery源码CSS部分,里面用到了currentStyle和getComputedStyle来获取外部样式. 因为elem.style.width只能获取elem的style属性里的样式,无 ...

  10. 搭建subversion 服务器,并自动部署项目

    1 subversion目录文件说明: *dav目录:是提供apache与mod_dav_svn使用的目录,让他们存储内部数据*db目录:就是所有版本控制的数据存放文件*hooks目录:放置hook脚 ...