nginx 资料整理(三)
导言:本系列整理资料中,在第一章我们概述了nginx以及搭建简单web服务器,由于nginx是基于http协议开发的web服务器软件,所以我们在第二章介绍了http协议相关内容,重点是请求和响应相关内容,在本章中,我们将继续介绍nginx作为web服务器的相关功能,从最简单的示例开始,逐渐追加功能
1. server
虚拟主机,就是把一台物理服务器划分成多个 “虚拟” 的服务器,这样我们的一台物理服务器就可以当做多个服务器来使用,从而可以配置多个网站。Nginx 提供虚拟主机的功能,就是为了让我们不需要安装多个 Nginx,就可以运行多个域名不同的网站。或者虚拟主机技术是将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器,从而充分利用服务器硬件资源。
在Nginx 中,一个 server 标签就是一个虚拟主机。nginx 的虚拟主机是通过 nginx.conf
中 server
节点指定的。想要设置多个虚拟主机,配置多个server
节点即可。
1. 格式
server
指令主要用来配置虚拟主机,所属模块 Module ngx_http_core_module
说明 | 配置 |
---|---|
Syntax | server { … } |
Default | — |
Context | http |
可以看到server
只能出现在http
模块中。虚拟主机配置有三种形式:
- 基于端口号配置
- 基于域名配置
- 基于ip配置
下面我们详细讲解具体配置内容
1. 基于端口号配置
基于端口的虚拟主机配置,使用端口来区分;浏览器使用同一个域名: 端口
或 同一个ip地址:端口
访问;
子配置配置文件
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name www.cainiao.cn;
root /app/code/www;
location / {
index index.html;
}
}
server {
listen 81;
server_name www.cainiao.cn;
root /app/code/www2;
location / {
index index.html;
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# systemctl reload nginx
首页文件
[root@web-svr-01 conf.d]# echo 'www.cainiao.cn -> port 80' > /app/code/www/index.html
[root@web-svr-01 conf.d]# mkdir /app/code/www2/
[root@web-svr-01 conf.d]# echo 'www.cainiao.cn -> port 81' > /app/code/www2/index.html
[root@web-svr-01 conf.d]# cat /app/code/www2/index.html
www.cainiao.cn -> port 81
[root@web-svr-01 conf.d]# cat /app/code/www/index.html
www.cainiao.cn -> port 80
验证
2. 基于域名配置
基于域名的虚拟主机是最常见的一种虚拟主机,通过域名配置虚拟主机。
我们在前面的例子中,通过子配置文件区分不同的虚拟主机,就是这种配置形式,不过为了清晰,子配置文件是分开的。在本例中,我们把不同的域名写在同一个子配置文件中,仅为了显示效果,生产环境中还是建议:一个子配置文件对应一个虚拟主机。
子配置文件
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name www.cainiao.cn;
root /app/code/www;
location / {
index index.html;
}
}
server {
listen 80;
server_name www.cainiao1.cn;
root /app/code/www2;
location / {
index index.html;
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# systemctl reload nginx
注意:笔者每次修改完配置文件,都会通过
nginx -t
对nginx
的配置文件进行语法检查,如果不检查容易把nginx挂掉,这在生产环境中是不允许的。
修改首页文件
[root@web-svr-01 conf.d]# cat /app/code/www/index.html
www.cainiao.cn
[root@web-svr-01 conf.d]# cat /app/code/www2/index.html
www.cainiao1.cn
验证
这里注意要修改
hosts
文件
3. 基于ip配置
基于ip配置虚拟主机可能是使用的最少的一种虚拟主机配置形式,建议读者了解即可
本地新增ip
[root@web-svr-01 conf.d]# ip addr add 192.168.202.132 dev ens33
[root@web-svr-01 conf.d]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:fe:8a:09 brd ff:ff:ff:ff:ff:ff
inet 192.168.202.131/24 brd 192.168.202.255 scope global noprefixroute dynamic ens33
valid_lft 1593sec preferred_lft 1593sec
inet 192.168.202.132/32 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::7fd7:bd03:f1c1:ee7c/64 scope link noprefixroute
修改子配置文件
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name 192.168.202.131;
root /app/code/www;
location / {
index index.html;
}
}
server {
listen 80;
server_name 192.168.202.132;
root /app/code/www2;
location / {
index index.html;
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# systemctl reload nginx
首页文件
[root@web-svr-01 conf.d]# cat /app/code/www/index.html
192.168.202.131
[root@web-svr-01 conf.d]# cat /app/code/www2/index.html
192.168.202.132
验证
2. server块常用指令
1. listen
用于指定虚拟主机的服务端口,所属模块 Module ngx_http_core_module
,只能出现在server
块中
格式:
说明 | 配置 |
---|---|
Syntax | listen address[:port]; listen port ; listen unix:path ; |
Default: | listen *:80 | *:8000; |
Context | server |
语法中可以配置参数实在太多,有兴趣的读者不妨自行查看,不过常用的还是默认的
2. server_name
用来指定IP地址或者域名,多个域名之间用空格分开
格式:
说明 | 配置 |
---|---|
Syntax | server_name name …; |
Default | server_name “”; |
Context | server |
关于server_name的配置方式有三种,分别是:
- 1、精确匹配
如:server_name test1.cn;
- 2、通配符匹配
server_name中支持通配符"*
",但需要注意的是通配符不能出现在域名的中间(只能出现在首段或尾段)。
如:server_name *1.cn tes1.*;
- 3、正则表达式匹配
server_name中可以使用正则表达式,并且使用~
作为正则表达式字符串的开始标记。
如:server_name ~^www\.(\w)+\.cn$;
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name ~^www\.(\w)+\.cn$;
root /app/code/www;
location / {
index index.html;
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# systemctl reload nginx
[root@web-svr-01 conf.d]# echo "server_name ~^www\.(\w)+\.cn$server_name ~^www\.(\w)+\.cn$" > /app/code/www/index.html
[root@web-svr-01 conf.d]# cat /app/code/www/index.html
server_name ~^www\.(\w)+\.cn ~^www\.(\w)+\.cn$
3. root
用于配置服务器的默认网站根目录位置,,所属模块 Module ngx_http_core_module
说明 | 配置 |
---|---|
Syntax | root path; |
Default | root html; |
Context | http, server, location, if in location |
path
: 为Nginx服务器接收到请求以后查找资源的根目录路径。
4. index
用于设置网站的默认首页,所属模块Module ngx_http_index_module
格式:
说明 | 配置 |
---|---|
Syntax | index file …; |
Default | index index.html; |
Context | http, server, location |
示例:
location / {
root html;
index test2.html test1.html;
}
index
后面可以跟多个设置,如果访问的时候没有指定具体访问的资源,则会依次进行查找,找到第一个为止。
访问该location
的时候,可以通过 http://server_name:port/
,地址后面如果不添加任何内容,则默认依次访问index.html
和index.htm
,找到第一个来进行返回
5. error_page
设置网站的错误页面,所属模块 Module ngx_http_core_module
说明 | 配置 |
---|---|
Syntax | error_page code … [=[response]] uri; |
Default | — |
Context | http, server, location, if in location |
Example:
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
在默认情况下,Nginx会在主目录的html目录中查找指定的返回页面,特别需要注意的是,这些错误信息的返回页面大小一定要超过512K
,否者会被ie
浏览器替换为ie
默认的错误页面。
示例一,以cainiao
为例,当访问不存在的资源时,浏览器会跳转到baidu
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# systemctl reload nginx
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name www.cainiao.cn;
root /app/code/www;
location / {
index index.html;
}
error_page 403 404 http://www.baidu.com;
}
示例二,可以重定向地址
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name www.cainiao.cn;
root /app/code/www;
location / {
index index.html;
}
error_page 403 404 /40x.html;
location = /40x.html {
root /app/code/www2;
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# !sys
systemctl reload nginx
[root@web-svr-01 conf.d]# echo "error page 404" > /app/code/www2/40x.html
[root@web-svr-01 conf.d]# curl -H Host:www.cainiao.cn 127.0.0.1/admin
error page 404
admin
这个文件是不存在的,正常访问应该提示nginx
默认的404
页面。但我们设置错误网页跳转之后,返回我们设置的错误网页。主要用来优化网站错误页效果,例如哔哩哔哩等等。
示例三,使用location的@符号完成错误信息展示
[root@web-svr-01 conf.d]# cat www.cainiao.cn.conf
server {
listen 80;
server_name www.cainiao.cn;
root /app/code/www;
location / {
index index.html;
}
error_page 403 404 @error;
location @error {
return 404 "cainiao error";
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# !sys
systemctl reload nginx
[root@web-svr-01 conf.d]# curl -H Host:www.cainiao.cn 127.0.0.1/admin
cainiao error[root@web-svr-01 conf.d]#
6. default_type
在Nginx中,default_type指令用于设置默认的MIME类型,即当Nginx不能确定响应的Content-Type时使用的类型。,所属模块 Module ngx_http_core_module
说明 | 配置 |
---|---|
Syntax | default_type mime-type; |
Default | default_type text/plain; |
Context | http, server, location |
例如,如果你正在传输一个静态文件,Nginx可能不知道文件的具体类型,这时就会使用default_type指定的类型。
默认情况下,default_type被设置为text/plain,这意味着如果Nginx不能确定文件的类型,它会将其视为普通文本。
请注意,default_type应该谨慎使用,因为它可能影响到Nginx的性能,尤其是在配置高性能的服务器时。通常,只有当Nginx无法确定文件类型,并且你确实需要为所有这些文件设置同一种类型时,才使用default_type。
下面我们来介绍location
指令,理论上应该在server中介绍,不过其内容较多,所以单独介绍
2. location
Nginx的location
指令是用来匹配请求URI
的,它告诉Nginx如何处理特定的请求。 location指令通常用于配置不同URI的访问规则,例如重定向、反向代理、设置缓存等。
具体来说,location指令在Nginx配置中扮演着重要角色。它根据请求的URI将请求定位到一个特定的规则块,然后由该规则块决定如何处理用户的请求。location指令允许根据请求的URI来匹配和处理客户端请求,这包括但不限于静态文件的服务、动态内容的处理、重定向等
1. 格式
location
指令主要用来匹配请求URI
,所属模块 Module ngx_http_core_module
说明 | 配置 |
---|---|
Syntax | location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... } |
Default | — |
Context | server, location |
符号说明:
符号 | 说明 | 示例 |
---|---|---|
= |
精确匹配。 | location = /test { ... } |
^~ |
最长前缀字符串匹配,表示从请求 URI 的开头开始进行匹配,不是正则匹配; | location ^~ /test { ... } |
~ |
区分大小写的正则匹配;常用 |
location ~ /test { ... } |
~* |
不区分大小写的正则匹配;常用 |
location ~* /test { ... } |
[空串] |
无符号,普通前缀匹配 | location /test { ... } |
/ |
通用匹配, 也是默认匹配。如果其它location没有匹配到,则会使用默认匹配;常用 |
location / { ... } |
优先级:
- 精确匹配(
=
) - 最长前缀匹配(
^~
),但会停止后续的正则匹配搜索 - 正则表达式匹配(
~
和~*
),按配置顺序 - 普通前缀匹配(无修饰符),也按配置顺序
- 默认匹配(
/
)
2. 解析过程
location 解析过程说明如下:
精确匹配(
=
):
Nginx 首先会尝试找到与请求的 URI 完全匹配的 location 块。例如,有一个location = /test
的配置,当请求的 URI 是/test
时,则应用这个配置。最长前缀匹配(
^~
):
没有找到精确匹配的 location 块,Nginx 会尝试寻找以请求的 URI 开头的前缀匹配。在多个前缀匹配的情况下,Nginx 会选择最长的那个前缀(最长前缀匹配)。最长前缀匹配,意思就是以location后面的字符开始的且最长匹配,有的地方叫做非正则匹配,意思是满足了最长前缀匹配,就不会再匹配正则匹配了,也可以理解为即满足最长前缀匹配,也满足正则匹配,就匹配最长前缀匹配,也就是所说的最长前缀匹配优先级高于正则匹配,所谓的优先级是两者或多着都匹配的情况下,才会显现优先级
正则表达式匹配(
~|*~
):
如果仍然没有找到匹配的 location 块,Nginx 会尝试使用正则表达式进行匹配。正则表达式 location 块以~
(区分大小写)或~*
(不区分大小写)开始。如果存在多个正则表达式匹配,Nginx 会选择第一个匹配项,因此正则表达式的顺序很重要。普通前缀匹配(
无符号
):普通前缀匹配也按照配置文件中出现的先后顺序进行匹配,先出现的location指令优先匹配。例如,对于URI:/test/page
,location /test/
会比location /te
更优先。默认匹配(
\
):
如果所有的精确匹配、前缀匹配和正则表达式匹配都失败,Nginx 会使用默认的 location 块(通常是不带任何参数的 location 块)。
3. 示例演示
[root@web-svr-01 conf.d]# cat test.cainiao.cn.conf
server {
listen 80;
server_name test.cainiao.cn;
location / {
return 200 201\n;
}
location = / {
return 200 202\n;
}
location /cainiao {
return 200 203\n;
}
location = /cainiao {
return 200 204\n;
}
location /cainiao/ {
return 200 205\n;
}
}
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/index.html
201
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/
202
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao
204
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao/
205
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/caini
201
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao123
203
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/niaocai
201
示例分析
curl -H Host:test.cainiao.cn 127.0.0.1/cainiao
符合条件的有203和204,但204是精确匹配,所以优先级高
curl -H Host:test.cainiao.cn 127.0.0.1/cainiao123
没有符合精确匹配的location,所以进行前缀匹配,203比较吻合
curl -H Host:test.cainiao.cn 127.0.0.1/niaocai
精确和前缀匹配都没有吻合的location,所以最后使用了默认匹配
示例扩充
[root@web-svr-01 conf.d]# cat test.cainiao.cn.conf
server {
listen 80;
server_name test.cainiao.cn;
location / {
return 200 201\n;
}
location = / {
return 200 202\n;
}
location /cainiao {
return 200 203\n;
}
location = /cainiao {
return 200 204\n;
}
location /cainiao/ {
return 200 205\n;
}
location ^~ /cai {
return 200 206\n;
}
location ~ /cai {
return 200 207\n;
}
location ^~ /caini {
return 200 208\n;
}
location ~ \.(png|jpg|jpeg|MP4)$ {
return 200 209\n;
}
location ~* \.(png|jpg|jpeg|MP4)$ {
return 200 210\n;
}
location ~* \.(PNG|JPEG|jpeg|MP4)$ {
return 200 211\n;
}
}
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/index.html #默认
201
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/ #精确
202
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cain #最长前缀
206
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/caini #最长前缀
208
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainia #最长前缀
208
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao #精确
204
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao1 #正则
207
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/1.png #区分大小写正则,匹配第一个
209
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/1.PNG #不区分大小写正则
210
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiaay
208
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao
204
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiaoy
207
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiay
208
笔者这里不建议混的太多了,上面后几条示例,笔者还是想不太明白。如果不使用最长前缀匹配,看起来就很清晰了。下面有个解析顺序参考图片,参考使用
4. @符号
用于定义一个 Location块,且该块不能被外部Client 所访问,只能被Nginx内部配置指令所访问,比如try_files 或 error_page
[root@web-svr-01 conf.d]# cat test.cainiao.cn.conf
server {
listen 80;
server_name test.cainiao.cn;
location / {
index index.html;
}
location @cn {
return 200 212;
}
location /cainiao {
try_files $uri @cn;
}
}
访问
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cn
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao
212[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/cainiao123
212
比如上面的配置,我们直接访问 /cn
是没有效果的,而访问 /cainiao
才会返回 212 的内容,也就是说,@ 符号定义的 location 是需要配合 try_files
这类的指令进行操作的。可以当做内部使用的一些预备命名路径。
[root@web-svr-01 conf.d]# cat test.cainiao.cn.conf
server {
listen 80;
server_name test.cainiao.cn;
location / {
error_page 414 = @one;
if($args ~ "service=one") {return 414;}
}
location @one {
return 200 "test @ one";
}
}
[root@web-svr-01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web-svr-01 conf.d]# !sys
systemctl reload nginx
[root@web-svr-01 conf.d]# curl -H Host:test.cainiao.cn 127.0.0.1/?service=one
test @ one[root@web-svr-01 conf.d]#
@
,nginx内部跳转
location /img/ {
error_page 404 @img_err;
}
location @img_err {
# 规则
}
#以 /img/ 开头的请求,如果链接的状态为 404。则会匹配到 @img_err 这条规则上。
5. 结尾 /
location 中的字符有没有/
都没有影响。也就是说 /user/ 和 /user 是一样的(精确匹配和普通匹配同时存在时会有不一样的情况)。
注意,这里有问题,官网这个地方说明的应该是访问请求时(浏览器),客户端发来的请求有无 / 的结果是一样的。而 location 后面定义的 uri 是否有结尾的 / 却是不一样的。
如果 URI 结构是 https://www.zyblog.com.cn/
的形式,尾部有没有/
都不会造成重定向。因为浏览器在发起请求的时候,默认加上了/
。虽然很多浏览器在地址栏里也不会显示/
。这一点,可以访问baidu验证一下。
如果 URI 的结构是 https://www.zyblog.com.cn/some-dir/
。尾部如果缺少/
将导致重定向。因为根据约定,URL 尾部的/
表示目录,没有/
表示文件。所以访问 /some-dir/ 时,服务器会自动去该目录下找对应的默认文件。如果访问 /some-dir 的话,服务器会先去找 some-dir 文件,找不到的话会将 some-dir 当成目录,301重定向到 /some-dir/ ,去该目录下找默认文件。
[root@web-svr-01 conf.d]# curl -H Host:www.cainiao.cn 127.0.0.1/abc/
abc index
[root@web-svr-01 conf.d]# curl -H Host:www.cainiao.cn 127.0.0.1/abc
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>