分享

【Nginx05】Nginx学习:HTTP核心模块(二)Server

 硬核项目经理 2023-07-03 发布于湖南

Nginx学习:HTTP核心模块(二)Server

第一个重要的子模块就是这个 Server 相关的模块。Server 代表服务的意思,其实就是这个 Nginx 的 HTTP 服务端所能提供的服务。或者更直白点说,就是虚拟主机的配置。通过 Server ,我们可以在同一台服务器上,配置监听不同端口号的 HTTP 应用,配置不同域名解析的 HTTP 服务,并且还可以灵活组合进行各种不同的域名和端口号的配置。这就是 Server 模块的作用。

Server

默认安装完成 Nginx 之后,都会提供一个默认的配置文件,在其中就会有一个 server 。

server {
  listen       80;
  server_name  localhost;

  location / {
    root   html;
    index  index.html index.htm;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
   root   html;
 }
}

整个 server{} 模块就是表示设置一个虚拟主机的配置。它只能写在 http 模块下面,但是可以有多个。比如我们可以再添加几个。

server {
  listen       80;
  server_name  localhost;

  location / {
    root   html;
    index  index.html index.htm;
  }

  location /t1/ {
   return 200 '201';
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
   root   html;
  }
}
server {
  listen       8080;
  server_name  localhost;

  location / {
    root   html;
    index  index.html index.htm;
  }

  location /t1/ {
   return 200 '202';
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
   root   html;
  }
}
server {
  listen       80;
  server_name  tp;

  location / {
    root   html;
    index  index.html index.htm;
  }

  location /t1/ {
   return 200 '203';
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
   root   html;
  }
}

注意上面三个配置中 listen 和 server_name 的区别。现在访问 http://192.168.56.88/t1/ 、http://192.168.56.88:8080/t1/ 和改完 hosts 指向的 http://tp/t1/ 看看返回值是不是对应的 201、202 和 203 。如果你的浏览器访问弹出下载的话,可以使用 curl 工具,或者修改一下 http 配置中的 default_type 为 text/html 。

其实从这里就可以看出,listen 是监控端口,server_name 是域名和主机名配置的,它们俩都可以设置多个,但形式略有不同。如果有重复的,比如多个 server 中都有端口 80 ,域名是 localhost 的配置就会报错,报错条件是其它 server 中不能同时满足这两个条件,否则就会产生监听的端口和域名冲突。不过这个错误是一个警告错误,也就是 Nginx 还可以正常运行,但会按照顺序从前往后匹配,或者说,第一个匹配上了就走第一个了。因此,我们一再强调,特别是线上生产环境,在修改 nginx.conf 文件之后一定要 nginx -t 一下,即使是警告,也要看一下原因,避免配置后产生无效的内容。

server_name

只能在 server 下配置,设置虚拟主机名,是 Server 模块中非常重要的一个配置指令。

server_name name ...;

可以配置多个主机名,第一个为虚拟主机的首要主机名。主机名中可以带星号,这样就可以匹配主机名的开始或者结尾部分。

server_name   tp *.tp tp.*; #core.php*;#*.sss.*;

注意,星号只能在前后,并且要配合一个点,后面注释中的两种形式都无法配置,直接检查就会报错。现在我们可以通过多种形式的域名访问这个配置。

192.168.56.88 tp www.tp w.y.tp tp.com tp.com.cn

当然,它也支持正则表达式进行匹配,并且正则还可以匹配组,然后将匹配到的内容将给后面其它的配置指令使用。

server_name   tp *.tp tp.*; #core.php*;#*.sss.*;
server_name ~^www(\d?)\.core(?<domain>.+)$;
……………………
location /t2/ {
 return 200 $1$domain;
}

本地我们 Hosts 指向一个 www4.core.opll.ppsd 域名,然后访问 /t2 路径,就会看到输出的内容是 4.opll.ppsd 是不是很神奇,之前我还真不知道这里可以这么用。$1 表示的是正则的第一个匹配项,也就是括号 \d 的内容,而后面的内容则是 <domain> 输出的,它是通过正则直接定义了一个 Nginx 内部变量。因此,我们可以在下面直接使用 $domain 来输出变量的内容。

这个时候,如果访问上面不带正则和变量的域名会返回什么内容呢?大家可以试试,直接就是空内容,没有别的东西。

另外,上面的配置大家也可以看出,server_name 这个指令是可以写多个的。但需要注意的是像上面说过的,域名+端口的冲突问题,既然可以配置相同的域名,那么它们的匹配顺序是什么呢?以第一个配置的为准(和 listen 有关,我们下个小节再说),也就是按照文件顺序。另外还有同一个 Server 下同时有普通、星号、正则域名,它们的顺序又是什么呢?完全匹配最高,通配符在前面的次之,通配符在后面的第三,正则匹配的最后。Nginx 中大部分和匹配有关的,基本都是这个顺序。

如果指定一个空字符串,那么就表示请求头中,没有 Host 的和这个 Server 信息相匹配。

server_names_hash_bucket_size

设置主机名哈希桶大小,其默认值取决于处理器的缓存线长度。

server_names_hash_bucket_size size;

只能在 http 下配置,默认值是 32|64|128,为了通过 哈希表 快速匹配主机名,这里就是设置这个哈希表的大小。

server_names_hash_max_size

只能在 http 下配置,设置主机名哈希表的最大size(容量)。

server_names_hash_max_size size;

默认值是 512 和上面一个类似,设置的越大,占用的内存越高,但哈希冲突越低,检索速度也越快。

server_tokens

开启或关闭在错误信息的 “Server” 响应头中输出 Nginx 版本号。

server_tokens on | off | build | string;

默认值是 on ,其实它配置的就是我们平常在请求 Nginx 服务时,响应头中 Server 字段返回的内容。默认情况下,它会返回 nginx/1.23.0 。同样的,在 Nginx 的默认报错页面,比如 404 页面,也会返回这样的版本号。

如果不想返回具体的版本号,那么我们就可以修改这个配置指令,设置为 off 。在 1.11.10 版本之后,还可以使用 build 参数,返回的是构建版本号。最后就是 1.9.13 之后的商业版版本可以直接设置一个字符串,这个在大家日常使用的开源版本中是没办法用的。

相信有的小伙伴要问了,能不能直接去掉 Server 响应头,完全不让别人知道我们是使用的 Nginx 呢?可以,但是要修改源码重新编译,这个就超出我的能力范围了,虽说也实验过,但是这里就不贴出来了,毕竟网上的教程已经非常多了,大家照着弄就可以了。

端口监听 listen

把 listen 单独拿出来 ,是因为它的配置定义非常长,而且非常复杂,但是我们日常用不到那么多非常复杂的配置。所以还是以常用的配置为基础,其它的内容了解一下就好。

listen address[:port] [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen port [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen unix:path [default_server] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ssl] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];

是不是有点吓人,这应该是整个 Nginx 中配置选项最多的一个了吧。

它就是设置 Nginx 的监听地址,Nginx 从这里接受请求,只能写在 server 模块中。对于IP协议,这个地址就是 address 和 port 。对于 UNIX 域套接字协议,这个地址就是 path 。 一条 listen 指令只能指定一个 address 或者 port ,不能像 server_name 那样在一行写多个,如果要监听不同的端口,就需要写多个 listen 。

大部分情况下我们都只是简单地这样写一个监听 80 的就行了。

listen       80;

其实这个不写也行,因为在没有定义 listen 指令的情况下,如果以超级用户权限运行 Nginx ,它将监听 *:80 ,否则他将监听*:8000。不过为了保险起见,一般我们都会写上这个配置。只写一个端口号就表示前面的 address 就是 * ,表示所有地址都监听。

偶尔在特殊情况下,我们可能监听多个端口。

server {
  listen 8081;
  listen 8082;
  listen 8083;
  server_name localhost;

  location / {
   return 200 listen1;
  }
}

这样,当前的 server 就会同时监听 8081、8082、8083 这三个端口。通过这三个端口访问的内容都会进入到这个 server 中。在同一个 server 中,不能定义相同端口号的。而如果是另外一个 server 中,就和上面说过的域名问题一样,如果域名不同就没事,如果域名也相同的话,会报警告错误。

监听的 address ,是可以指定域名的。

listen 127.0.0.1:8000;
listen localhost:8000;

或者你的主机上 hosts 指向的任何主机,甚至外网域名都可以,不过一般很少人会这样做。另外不指定端口号也可以。

listen 127.0.0.1;

这样默认就会走 80 端口,和上面的默认规则一样。如果是 ipv6 地址,则要使用 [] 的形式。

listen [::]:8000;
listen [fe80::1];

另外,还可以使用 unix socket ,就是前面说过的 Unix域套接字形式。

listen unix:/var/run/nginx.sock;

另外还有一个重要的配置就是 default_server 。可以为 listen 指定这个参数,然后当前的虚拟主机将成为指定 address:port 的默认虚拟主机。 如果任何 listen 指令都没有携带 default_server 参数,那么第一个监听 address:port 的虚拟主机将被作为这个地址的默认虚拟主机。

其实这里就是解释了之前我们说的同域名,同端口的主机问题。默认会报一个警告错误,同时会以第一个配置为准,但如果我们给第二个配置添加上 default_server 的话,那么现在就会走第二个配置。

server {
  listen 8081;
  listen 8082;
  listen 8083;
  server_name localhost;

  location / {
   return 200 listen1;
  }
}

server {
  listen 8082 default_server;
  listen 8084;
  server_name localhost;

  location / {
   return 200 listen2;
  }
}

我们给 8082 的第二个 server 配置的 listen 上添加了 default_server ,现在访问 8082 端口,会返回的内容是 listen2 。那么可以定义多个 default_server 吗?答案是不行的,Nginx 检查会报出 emerg 错误,这个就不是警告那么简单了,无法启用或者重新加载配置文件的。default_server 只能有一个。在 0.8.21 版本以前这个选项叫做 default 。

其它还有一些参数,我们就不一一配置了,在这里列出来大家一起了解一下,有需要用到的直接配上使用就好了。(在 0.8.21 版以前,只有为 listen 指令定义了 default 参数,才能定义这些额外的参数)

  • setfib=number 这个参数(0.8.44)为监听套接字设置关联路由表FIB(SO_SETFIB选项)。 当前这个参数仅工作在FreeBSD上。
  • backlog=number 为系统调用 listen() 设置 backlog 参数,用以限制未接受(Accept)连接的队列的最大长度。 FreeBSD 和 Mac OS X 下,backlog 的默认值是 -1 ,在其他系统中,默认值是 511 。
  • rcvbuf=size 为监听套接字设置接收缓冲区大小(SO_RCVBUF参数)。
  • sndbuf=size 为监听套接字设置发送缓冲区大小(SO_SNDBUF参数)。
  • accept_filter=filter 为监听套接字设置接受过滤器的名称(SO_ACCEPTFILTER选项)。 对每个到来的连接,接受过滤器先进行过滤,然后才将它们呈现给accept()。 本特性仅工作在 FreeBSD 系统和 NetBSD 5.0+ 系统下。 可接受的值是 dataready 和 httpready 。
  • deferred 指示在Linux系统使用延迟的accept()(TCP_DEFER_ACCEPT选项)。在设置该参数后,若用户发起建立连接请求,并且完成了TCP的三次握手,内核也不会为了这次的连接调度worker进程来处理,只有用户真的发送请求数据时(内核已经在网卡中收到请求数据包),内核才会唤醒worker进程处理这个连接。这个参数适用于大并发的情况下。
  • bind 指示nginx为设置的address:port单独调用一次 bind() 。 这是因为当有多条 listen 指令监听不同地址下的相同端口, 而其中一条 listen 指令监听了这个端口的所有地址(*:port)时, Nginx只会为 *:port 调用一次 bind() 绑定套接字。 需要留意的是,这种情况下,Nginx 会调用 getsockname() 系统调用来确定接受请求的套接字地址。 如果为某个address:port 定义了参数 backlog、rcvbuf、 sndbuf、accept_filter、deferred 或者 so_keepalive , Nginx 总会为这个地址单独调用一次 bind() 绑定套接字。
  • ipv6only=on|off 这个参数(0.7.42)(通过IPV6_V6ONLY选项)决定监听在通配地址[::]上的 IPv6 套接字是只支持 IPv6 连接,还是同时支持 IPv6 和 IPv4 连接。 这个参数默认打开,并且只能在 Nginx 启动时设置。在1.3.4版以前,如果省略此参数,那么操作系统的套接字设置将生效。
  • ssl 本参数(0.7.14)与套接字相关的系统调用无关,但是它可以指定从这个端口接受的连接应该以SSL模式工作。 本参数在某服务器同时处理HTTP和HTTPS请求时,可以使配置更为紧凑。例如 listen 443 ssl;,这个参数现在比较常用。
  • so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt] 这个参数(1.1.11)为监听套接字配置 “TCP keepalive” 行为。 如果省略此参数,操作系统默认的设置将对此端口生效。 如果参数值设置为“on”,监听套接字的 SO_KEEPALIVE 属性将被开启。 如果参数值设置为 “off” ,监听套接字的 SO_KEEPALIVE 属性将被关闭。 有些操作系统支持为每个连接调整 TCP 长连接的参数。调整参数可以使用套接字选项 TCP_KEEPIDLE,TCP_KEEPINTVL和TCP_KEEPCNT 。 在这些操作系统上(当前就是Linux 2.4+,嬀NetBSD 5+FreeBSD 9.0-STABLE),可以使用 keepidle,keepintvl 和 keepcnt 参数来配置。 省略一到两个参数的话,对应套接字属性的系统默认设置将生效。

好多都看不懂吧?没事,我也看不懂,全是各种网络编程以及TCP相关的基础知识,所以说,基础知识真的很重要。学习 Nginx 的最大收获其实就是让自己发现自己的基础知识有多么的薄弱,为了让我们能够更加坚定地去学习基础知识来铺路打气的。

总结

Server 模块是整个 HTTP 模块中非常重要的部分,也是下篇我们要讲的 Location 模块的上层,是非常重要的内容。但其实,更核心的是它的 server_name 和 listen 两个配置指令的作用及配置方法。

好了,话不多说,接下来我们就赶紧进入到 Location 相关的学习吧。

参考文档:

http:///en/docs/http/ngx_http_core_module.html#server

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多