一 相关指令
背景'知识':请求行中的'域名或ip'负责定位'服务(nginx)'所在的主机,确保请求是发送到这个节点上
续: NS记录'优先'于A记录;A记录'优先'于CNAME记录
补充1: 如果域名做了'CNAME'只是DNS内部的解析,归根结底还是'ip'的问题
场景: A CNAME C, B NAME C, C A ip -->用户的'HOST'头是'A|B',根据'ip'定位nginx主机
① 引言
引言: 假定'nginx'已经'解析了请求行',拿到了'Host'头
+++++++++++ '影响选择server块的因素' +++++++++++
请求源: 请求'行'中的'Host'、HTTP(1.0|1.1)、proxy_protocol'协议'、请求'头'中的'Host'
解析源: 'listen'、'server_name'指令
请求行的主机头 https的SNI也会影响server块的选择
② listen
注意: listen 指令 '相关参数的顺序'
说明: listen指令发生在'TCP连接建立完成'时,它对'server{}'块进行'首次(first)'匹配
通俗: 首次'匹配'上,说明server端有'该监听端口',客户端可以发送'data'数据了
核心关注: 'default_server'、'ssl' 、'http2'、'ipv6only'、'proxy_protocol'
1)'default_server' -->'默认虚拟主机'
2)'ssl、http2' --> 支持http2的'https'
3)'proxy_protocol' -->'pp'协议,获取'real_client_ip'
1) 通过listen port 可以'筛选出一批'对应server块的'server_name'
2) 然后'host请求头'与'server_name'匹配,如果有'多个匹配项',根据'优先级'匹配
3) 如果'不匹配',就会选择'默认'的server_name
规则: 相同listen端口的default_server或按照配置文件顺序的第一个'listen port'
absolute_redirect、port_in_redirect、server_name_in_redirect使用$server_name
++++++++ 下面讲解'server_name取值'形式 ++++++++
(1)精确匹配
说明: '多域名'的时候通过'空格'分割;通过'$server_name'获取主域名
+++++++++++ '精确匹配'形式 +++++++++++
1)'裸字符串'域名
2)特殊的'$hostname'变量 --> server_name $hostname;
说明: $hostname取值于'hostname'命令
( 2)泛域名
泛域名:server_name 中支持通配符 "*",主要是为了通配'子域名'
注意: 通配符'不能'出现在域名的'中间',只能出现在'首(start)'段或'尾(end)'段
补充: 如果带有'~'的域名中含有'*',则'不是'泛域名
(3)混合形式
说明: 特殊的'泛域名'符号 --> '.' , 是为了'简化',可以理解为一种'语法糖'
(4)PCRE正则
特殊场景:匹配所有的域名 '~ \.*$',然后通过'listen port'来识别'不同'的服务
1)正则表达式创建变量
说明: 正则中通过'(小括号)'来创建变量,实质是'分组的补获引用'
(5)补充
说明: 当listen'出现了ip'时,server_name就'失去了意义',所以'不配置'也罢了
1)同一层级泛域名匹配,'最长(精确的意味)'通配符的匹配
server_name *.com; --> 'www.abc.com' 匹配上
server_name *.wzj.com; --> 'www.wzj.com' 匹配上
解读: 当所有server{}块'都没有匹配上'域名,此时必须有一个'默认server {} 块'来处理这个请求
+++++++++++ '显示'和'隐式'默认域名匹配的'顺序' +++++++++++
1)当listen指令后明确的跟着'default_server选项'时,它所属的server{ }就是'默认'server
2)如果'监听同一个端口'的所有server{}'都没有'通过listen指令'显式'设置default_server,那么这些server{}配置块中,在nginx.conf配置文件里'第1个出现'的就是默认server
思考:server_name和listen都有ip,哪个优先级最高
说明: listen上的'ip'是tcp层面的;server_name上面的'ip'是HTTP层面的'Host'匹配的
server_name _; -->'_'只是个'没意义'字符['可换成其它'],主要近似是'default_server'起作用
server_name "" -->'解释同上',是'无数的无效'域名之一,同样可以使用其他无效名称,例如"-"和"!、@、#"等
curl -H 'Host:""' https://www.wzj.com -->"匹配的是空主机头"-->'server_name ""'
解读:传统做法我们将'server_name _;'或'server_name'放到http下的'第一个'server块中,'希望'作为'默认主机'
原因:如果没有配置'default_server',默认第一个'server'块就是默认主机
+++++++++++++定义'默认服务器'+++++++++++++
server {
# 0.8.21+版本,default_server可以'简化为'default'
listen 192.168.1.1:80 default_server;
server_name _;
...
}
补充:如果'没有'指定default_server,'不匹配'会走到第一个'server'块内
(1)案例1
① 案例引入
备注:关于'虚拟主机',一般就是'相同的ip:不同port'或者'不同域名对应同一ip'两种形式
② 命令行curl测试
现象:请求时在'请求头指定'Host: server2.wzj.com ; 此时的结果会很'出乎意料',该请求就会由'第二块'server处理.
'简化'解读: 'Host'的请求头[如果是"域名的形式"]在'服务端'不做域名解析
补充:如果'server_name'和'Host头匹配上',此时效果'等价'-->'地址栏的请求资源[eg:/v1]'匹配'server_name'的'location'
curl -k -H 'Host:server2.wzj.com' http://172.25.2.100
特点: 直接'ip'不需要'域名'解析
注意:'浏览器[chrome等]'访问、'postman工具'访问、'命令行curl'访问关于'Host'的区别
③ nginx中$host、$http_host和$proxy_host区别
附加: $HTTP_HEADER -->'HTTP中请求头'和'nginx中http变量'对应关系
规则:HTTP请求'请求头[HEADER]'在转换为'小写'字母并将'横杠'转换为'下划线'时的值
例子:'User-Agent-->$http_user_agent'
+++++++++++ "分割线" +++++++++++
$host:是'nginx内置'的变量-->'Host请求头值或者server_name的值' -->涉及通过vip访问可能是'vip'
$http_host: 来自'http请求头 Host'值,带'端口'
$proxy_host:是'proxy_pass中的值',要么是'upstream_name'、或者'域名'、'ip'等形式['可能加端口']
(2)案例2
+++++++++ '禁止ip',只能通过'域名'访问 +++++++++
1) '为什么'要禁止ip访问页面呢?
这样做是为了'避免'其他人把'未备案的域名'解析到'自己的服务器ip',而导致服务器被断网,我们可以通过禁止使用ip访问的方法,防止此类事情的发生
2) nginx'怎么配置'?
server {
# 本地的80
listen 80 default;
server_name _;
return 403; # 不友好
# rewrite ^(.*) https://www.wzj.com/$1 permanent; -->'友好'提示
}
补充:禁止'空主机头'访问 -->可以'if'进行判断或者'server_name "";'