nginx学习笔记
1.虚拟主机
Nginx中的server_name指令主要用于配置基于名称的虚拟主机,server_name指令在接到请求后的匹配顺序分别为:
1、精准的server_name匹配,例如:
server {
listen 80;
server_name domain.com www.domain.com;
...
}
2、通配符匹配
server {
listen 80;
server_name *.domain.com;
...
}
3、正则表达式匹配
server {
listen 80;
server_name ~^(\w+).domain.com$;
...
}
如果所有的server_name都不匹配,就会进入端口号相同的虚拟主机。
2.常用操作命令
Nginx 的命令在控制台中输入 nginx -h 就可以看到完整的命令,这里列举几个常用的命令:
nginx -s reload # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen # 重启 Nginx
nginx -s stop # 快速关闭
nginx -s quit # 等待工作进程处理完成后关闭
nginx -T # 查看当前 Nginx 最终的配置
nginx -t #检查配置文件是否合法
nginx -c 配置文件 #指定配置文件
nginx -t -c <配置路径> # 检查配置文件是否有问题,如果已经在配置目录,则不需要-c
nginx -V #查看版本和安装配置信息
3.Nginx 配置语法
就跟前面文件作用讲解的图所示,Nginx 的主配置文件是 /etc/nginx/nginx.conf,你可以使用 cat -n nginx.conf 来查看配置。
nginx.conf 结构图可以这样概括:
main # 全局配置,对全局生效
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│ ├── server # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│ ├── server
│ │ ├── location # server 块可以包含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...
一个 Nginx 配置文件的结构就像 nginx.conf 显示的那样,配置文件的语法规则:
- 配置文件由指令与指令块构成;
- 每条指令以
;分号结尾,指令与参数间以空格符号分隔; - 指令块以
{}大括号将多条指令组织在一起; include语句允许组合多个配置文件以提升可维护性;- 使用
#符号添加注释,提高可读性; - 使用
$符号使用变量; - 部分指令的参数支持正则表达式;
3.1 典型配置
Nginx 的典型配置:
user nginx; # 运行用户,默认即是nginx,可以不进行设置
worker_processes 1; # Nginx 进程数,一般设置为和 CPU 核数一样
error_log /var/log/nginx/error.log warn; # Nginx 的错误日志存放目录
pid /var/run/nginx.pid; # Nginx 服务启动时的 pid 存放位置
events {
use epoll; # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
worker_connections 1024; # 每个进程允许最大并发数
}
http { # 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
# 设置日志模式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main; # Nginx访问日志存放位置
sendfile on; # 开启高效传输模式
tcp_nopush on; # 减少网络报文段的数量
tcp_nodelay on;
keepalive_timeout 65; # 保持连接的时间,也叫超时时间,单位秒
types_hash_max_size 2048;
include /etc/nginx/mime.types; # 文件扩展名与类型映射表
default_type application/octet-stream; # 默认文件类型
include /etc/nginx/conf.d/*.conf; # 加载子配置项
server {
listen 80; # 配置监听的端口
server_name localhost; # 配置的域名
location / {
root /usr/share/nginx/html; # 网站根目录
index index.html index.htm; # 默认首页文件
deny 172.168.22.11; # 禁止访问的ip地址,可以为all
allow 172.168.33.44; # 允许访问的ip地址,可以为all
}
error_page 500 502 503 504 /50x.html; # 默认50x对应的访问页面
error_page 400 404 error.html; # 同上
}
}
server 块可以包含多个 location 块,location 指令用于匹配 uri,语法:
location [ = | ~ | ~* | ^~] uri {
...
}
复制代码
指令后面:
=精确匹配路径,只有完全匹配上才能生效,如果匹配成功,不再进行后续的查找;^~对URL路径进行前缀匹配,并且在正则之前;匹配后继续尝试匹配,匹配/ui最长为准~表示区分大小写的正则匹配,匹配后不会再继续匹配,多个正则匹配与配置文件中的顺序有关;~*表示不区分大小写的正则匹配,匹配后不会再继续匹配;多个正则匹配与配置文件中的顺序有关。/uri不带任何修饰符,也表示前缀匹配,但是优先级在正则匹配之后,匹配后继续尝试匹配,以匹配/uri最长为准/通用匹配,如果其他都没匹配上,则命中此配置。
如果 uri 包含正则表达式,则必须要有 ~ 或 ~* 标志。
3.2 全局变量
Nginx 有一些常用的全局变量,你可以在配置的任何位置使用它们,如下表:
| 全局变量名 | 功能 |
|---|---|
$host | 请求头中的 Host,不包含端口 |
$http_host | 请求头中的Host 包含端口号 www.ldk.com:8080 |
$request_uri | 请求路径 和$uri类似 $request_uri带参数,$uri不带参数 |
$request_method | 客户端请求类型,如 GET、POST |
$request | 完整的HTTP请求行,包括HTTP方法、URI和协议版本 |
$status | HTTP响应状态码 200表示成功 |
$is_args | 如果请求中有参数,值为?,否则为空字符串。 |
$args | 请求中的参数 如:a=10&b=20 |
$arg_PARAMETER | GET 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer... |
$content_length | 请求头中的 Content-length 字段 |
$http_user_agent | 客户端agent信息 |
$http_cookie | 客户端cookie信息 |
$remote_addr | 客户端的IP地址 |
$remote_port | 客户端的端口 |
$remote_user | 远程用户 |
$http_user_agent | 客户端agent信息 |
$server_protocol | 请求使用的协议,如 HTTP/1.0、HTTP/1.1 |
$server_addr | 服务器地址 |
$server_name | 服务器名称 |
$server_port | 服务器的端口号 |
$scheme | HTTP 方法(如http,https) |
$time_local | 访问时间和日期,以服务器的本地时区为准 |
$body_bytes_sent | 响应体字节数 |
$http_referer | 请求头中得referer |
$http_user_agent | 客户端的User-Agent标头 |
$scheme | 请求模式,http或https |
$pid | 进程id |
$proxy_host | 代理服务器主机,如localhost:8080 |
$http_x_forwarded_for | 通过代理服务器传递的客户端IP地址 |
$proxy_add_x_forwarded_for客户端发送请求,有多个代理,会把客户端ip和代理ip拼接在一起,用逗号分隔。例如请求路径:clinet1-->proxy1-->proxy2-->proxy3
那么$proxy_add_x_forwarded_for值为:client1,proxy1,proxy2,proxy3
3.3Rewrite相关指令
Rewrite命令
语法:
rewrite <regex> <replacement> [flag];
regex 正则表达式
replacement 替换的内容
flag 标记
flag标记说明:
| 标记 | 说明 |
|---|---|
| last | 会再次进入server块,重试location匹配,地址栏不变 |
| break | 本条规则匹配完成即终止,不再匹配后面的任务规则 地址栏不变 |
| redirect | 返回302临时重定向,浏览器地址会显示跳转后的URL地址,爬虫不会更新url |
| permanent | 返回301永久重定向,浏览器地址会显示跳转后的URL地址,爬虫更新url |
set指令
该指令用来设置一个新的变量。
| 语法 | set $variable value; |
|---|---|
| 默认值 | — |
| 位置 | server、location、if |
variable:变量的名称,该变量名称要用"$"作为变量的第一个字符,且不要与Nginx服务器预设的全局变量同名。
value:变量的值,可以是字符串、其他变量或者变量的组合等。
set $cusArgs $args;
set $myname 'ldk';
if指令
该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。if和后面括号之间需要加空格
| 语法 | if (condition){...} |
|---|---|
| 默认值 | — |
| 位置 | server、location |
condition为判定条件,可以支持以下写法:
- 变量名。如果变量名对应的值为空字符串或"0",if都判断为false,其他条件为true。
#if后面需要加空格
if ($param){
}
if ($is_args){
set $a '你好中国';
}
- 使用"="和"!="比较变量和字符串是否相等,满足条件为true,不满足为false
#if后面需要加空格
if ($request_method = POST){
return 405;
}
注意:此处和Java不太一样的地方是字符串不需要添加引号,并且等号和不等号前后到需要加空格。
-
使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用"
","","!","!"来连接。"~"代表匹配正则表达式过程中区分大小写,
"~*"代表匹配正则表达式过程中不区分大小写
"!
"和"!*"刚好和上面取相反值,如果匹配上返回false,匹配不上返回true
if ($http_user_agent ~ MSIE){
#$http_user_agent的值中是否包含MSIE字符串,如果包含返回true
}
注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}"或者是";"等字符时,就需要把引号加上。
- 判断请求的文件是否存在使用"-f"和"!-f",
if (-f $request_filename){
#判断请求的文件是否存在
}
if (!-f $request_filename){
#判断请求的文件是否不存在
}
5. 判断请求的目录是否存在使用"-d"和"!-d" 6. 判断请求的目录或者文件是否存在使用"-e"和"!-e" 7. 判断请求的文件是否可执行使用"-x"和"!-x"
break指令
该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。并且break还有另外一个功能就是终止当前的匹配并把当前的URI在本location进行重定向访问处理。
| 语法 | break; |
|---|---|
| 默认值 | — |
| 位置 | server、location、if |
例子:
location /testbreak{
default_type text/plain;
set $username TOM;
if ($args){
Set $username JERRY;
break;
set $username ROSE;
}
add_header username $username;
return 200 $username;
}
return指令
该指令用于完成对请求的处理,直接向客户端返回。在return后的所有Nginx配置都是无效的。
| 语法 | return code [text]; return code URL; return URL; |
|---|---|
| 默认值 | — |
| 位置 | server、location、if |
code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理
text:为返回给客户端的响应体内容,支持变量的使用
URL:为返回给客户端的URL地址
location /testreturn {
return 200 success;
}
location /testreturn {
return https://www.baidu.com; // 302重定向到百度
}
location /testreturn {
return 302 https://www.baidu.com;
}
location /testreturn {
return 302 www.baidu.com;//不允许这么写
}
4. 配置反向代理
反向代理是工作中最常用的服务器功能,经常被用来解决跨域问题,下面简单介绍一下如何实现反向代理。
首先进入 Nginx 的主配置文件:
vim /etc/nginx/nginx.conf
为了看起来方便,把行号显示出来 :set nu (个人习惯),然后我们去 http 模块的 server 块中的 location /,增加一行将默认网址重定向到最大学习网站 Bilibili 的 proxy_pass 配置 🤓 :
改完保存退出,nginx -s reload 重新加载,进入默认网址,那么现在就直接跳转到 B 站了,实现了一个简单的代理。
实际使用中,可以将请求转发到本机另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。
比如我们监听 9001 端口,然后把访问不同路径的请求进行反向代理:
- 把访问
http://127.0.0.1:9001/edu的请求转发到http://127.0.0.1:8080 - 把访问
http://127.0.0.1:9001/vod的请求转发到http://127.0.0.1:8081
这种要怎么配置呢,首先同样打开主配置文件,然后在 http 模块下增加一个 server 块:
upstream backend{
server 172.168.254.4:8080 weight=8;
server 172.168.254.5:8080 weight=2 backup; #backup 表示备份,如果上面的server没有挂,不会接收请求,如果上面的server 宕机,开始接收请求。
server 172.168.254.6:8080 down; #down表示已下线
}
server {
listen 9001;
server_name *.sherlocked93.club;
location ~ /edu/ {
proxy_pass http://127.0.0.1:8080;
}
location ~ /vod/ {
proxy_pass http://127.0.0.1:8081;
}
location ~ /abc/ {
proxy_pass http://backend;
}
}
反向代理还有一些其他的指令,可以了解一下:
proxy_set_header:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息。proxy_connect_timeout:配置Nginx与后端代理服务器尝试建立连接的超时时间。proxy_read_timeout:配置Nginx向后端服务器组发出read请求后,等待相应的超时时间。proxy_send_timeout:配置Nginx向后端服务器组发出write请求后,等待相应的超时时间。proxy_redirect:用于修改后端服务器返回的响应头中的Location和Refresh。
4.1反向代理路径后加斜杠问题
我浏览器中访问的地址:http://192.168.10.1/proxy/test.html
第一种(末尾加斜杠,proxy_pass中不包含路径)
location /proxy/ {
proxy_pass http://127.0.0.1:81/; #注意:这里的路径加了一个斜杠
}
生成代理后路径:http://127.0.0.1:81/test.html ,proxy_pass+请求url匹配的location路径后的内容。
第二种(末尾不加斜杠,proxy_pass不包含路径)
location /proxy/ {
proxy_pass http://127.0.0.1:81; #注意:这里的代理路径没有斜杠
}
生成代理后路径:http://127.0.0.1:81/proxy/test.html ,(proxy_pass替换请求url的ip和端口)
第三种(末尾加斜杠,proxy_pass包含路径):
location /proxy/ {
proxy_pass http://127.0.0.1:81/abc/; #注意:这里的代理路径不仅有ip和端口,还有uri路径,并且以斜杠结尾。
}
结论:会被代理到http://127.0.0.1:81/abc/test.html (proxy_pass+请求url匹配的location路径后的内容)
第四种(末尾不加斜杠,url包含路径):
location /proxy/ {
proxy_pass http://127.0.0.1:81/abc; #注意:这里的代理路径不仅有ip和端口,还有uri路径,并且结尾没有斜杠。
}
结论:会被代理到http://127.0.0.1:81/abctest.html (proxy_pass+请求url匹配的location路径后的内容)
5. 跨域 CORS 配置
关于简单请求、非简单请求、跨域的概念,前面已经介绍过了,还不了解的可以看看前面的讲解。现在前后端分离的项目一统天下,经常本地起了前端服务,需要访问不同的后端地址,不可避免遇到跨域问题。
要解决跨域问题,我们来制造一个跨域问题。首先和前面设置二级域名的方式一样,先设置好 fe.sherlocked93.club 和 be.sherlocked93.club 二级域名,都指向本云服务器地址,虽然对应 IP 是一样的,但是在 fe.sherlocked93.club 域名发出的请求访问 be.sherlocked93.club 域名的请求还是跨域了,因为访问的 host 不一致(如果不知道啥原因参见前面跨域的内容)。
5.1 使用反向代理解决跨域
在前端服务地址为 fe.sherlocked93.club 的页面请求 be.sherlocked93.club 的后端服务导致的跨域,可以这样配置:
server {
listen 9001;
server_name fe.sherlocked93.club;
location / {
proxy_pass be.sherlocked93.club;
}
}
这样就将对前一个域名 fe.sherlocked93.club 的请求全都代理到了 be.sherlocked93.club,前端的请求都被我们用服务器代理到了后端地址下,绕过了跨域。
这里对静态文件的请求和后端服务的请求都以 fe.sherlocked93.club 开始,不易区分,所以为了实现对后端服务请求的统一转发,通常我们会约定对后端服务的请求加上 /apis/ 前缀或者其他的 path 来和对静态资源的请求加以区分,此时我们可以这样配置:
# 请求跨域,约定代理后端服务请求path以/apis/开头
location ^~/apis/ {
# 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass be.sherlocked93.club;
# 两个域名之间cookie的传递与回写
proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;
}
这样,静态资源我们使用 fe.sherlocked93.club/xx.html,动态资源我们使用 fe.sherlocked93.club/apis/getAwo,浏览器页面看起来仍然访问的前端服务器,绕过了浏览器的同源策略,毕竟我们看起来并没有跨域。
也可以统一一点,直接把前后端服务器地址直接都转发到另一个 server.sherlocked93.club,只通过在后面添加的 path 来区分请求的是静态资源还是后端服务,看需求了。
5.2 配置 header 解决跨域
server {
listen 80;
server_name be.sherlocked93.club;
add_header 'Access-Control-Allow-Origin' $http_origin; # 全局变量获得当前请求origin,带cookie的请求不支持*
add_header 'Access-Control-Allow-Credentials' 'true'; # 为 true 可带上 cookie
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 允许请求方法
add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers; # 允许请求的 header,可以为 *
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000; # OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204; # 200 也可以
}
location / {
root /usr/share/nginx/html/be;
index index.html;
}
}
6.常用指令
6.1try_files指令
try_files指令可以按顺序检查文件是否存在,并返回第一个找到的文件, 如果未找到任何文件,则会调用最后一个参数进行内部重定向。
示例一:
location /whsir/ {
try_files $uri /whsir/default.gif;
}
说明:
1、访问www.example.com/whsir/123/321(文件不存在)时,此时看到的是default.gif图片,URL地址不变
2、访问www.example.com/whsir/123.png(文件存在)时,此时看到的是123.png图片,URL地址不变
总结:当images目录下文件不存在时,默认返回default.gif
示例二:
location /whsir/ {
try_files $uri =403;
}
说明:
1、访问www.example.com/whsir/123.html(文件存在)时,此时看到的是123.html内容,URL地址不变
2、访问www.example.com/whsir/21.html(文件不存在)时,此时看到的是403状态,URL地址不变
总结:和示例一一样,只是将默认图片换成了403状态
示例三:
location /whsir/ {
try_files $uri @ab;
}
location @ab {
rewrite ^/(.*)$ https://blog.whsir.com;
}
说明:
1、访问www.example.com/whsir/123.html(文件存在)时,此时看到的是123.html内容,URL地址不变
2、访问www.example.com/whsir/21.html(文件不存在)时,此时跳转到吴昊博客,URL地址改变
总结:当文件不存在时,会去查找@ab值,此时在location中定义@ab值跳转到吴昊博客
示例四:
try_files $uri @pro;
location @pro {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://blog.whsir.com;
}
说明:
1、访问www.example.com/123.html(文件存在)时,此时看到的是123.html内容,URL地址不变
2、访问www.example.com/post-3647.html(文件不存在)时,此时看到的是吴昊博客的内容,URL地址不变
示例五:
location /abc {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
说明: 在目录/usr/share/nginx/html/abc下有index.html文件
1、访问http://192.168.254.4:8001/abc/ 会显示/abc/index.html文件
2、访问http://192.168.254.4:8001/abc/def 会重定向到/usr/share/nginx/html/index.html文件
7.资源压缩
建立在动静分离的基础之上,如果一个静态资源的Size越小,那么自然传输速度会更快,同时也会更节省带宽,因此我们在部署项目时,也可以通过Nginx对于静态资源实现压缩传输,一方面可以节省带宽资源,第二方面也可以加快响应速度并提升系统整体吞吐。
在Nginx也提供了三个支持资源压缩的模块ngx_http_gzip_module、ngx_http_gzip_static_module、ngx_http_gunzip_module,其中ngx_http_gzip_module属于内置模块,代表着可以直接使用该模块下的一些压缩指令,后续的资源压缩操作都基于该模块,先来看看压缩配置的一些参数/指令:
| 参数项 | 释义 | 参数值 |
|---|---|---|
gzip | 开启或关闭压缩机制 | on/off; |
gzip_types | 根据文件类型选择性开启压缩机制 | image/png、text/css... |
gzip_comp_level | 用于设置压缩级别,级别越高越耗时 | 1~9(越高压缩效果越好) |
gzip_vary | 设置是否携带Vary:Accept-Encoding头域的响应头部 | on/off; |
gzip_buffers | 设置处理压缩请求的缓冲区数量和大小 | 数量 大小,如16 8k; |
gzip_disable | 针对不同客户端的请求来设置是否开启压缩 | 如 .*Chrome.*; |
gzip_http_version | 指定压缩响应所需要的最低HTTP请求版本 | 如1.1; |
gzip_min_length | 设置触发压缩的文件最低大小 | 如512k; |
gzip_proxied | 对于后端服务器的响应结果是否开启压缩 | off、expired、no-cache... |
了解了Nginx中的基本压缩配置后,接下来可以在Nginx中简单配置一下:
http{
# 开启压缩机制
gzip on;
# 指定会被压缩的文件类型(也可自己配置其他类型)
gzip_types text/plain application/javascript text/css application/xml text/javascript image/jpeg image/gif image/png;
# 设置压缩级别,越高资源消耗越大,但压缩效果越好
gzip_comp_level 5;
# 在头部中添加Vary: Accept-Encoding(建议开启)
gzip_vary on;
# 处理压缩请求的缓冲区数量和大小
gzip_buffers 16 8k;
# 对于不支持压缩功能的客户端请求不开启压缩机制
gzip_disable "MSIE [1-6]."; # 低版本的IE浏览器不支持压缩
# 设置压缩响应所支持的HTTP最低版本
gzip_http_version 1.1;
# 设置触发压缩的最小阈值
gzip_min_length 2k;
# 关闭对后端服务器的响应结果进行压缩
gzip_proxied off;
}
在上述的压缩配置中,最后一个gzip_proxied选项,可以根据系统的实际情况决定,总共存在多种选项:
off:关闭Nginx对后台服务器的响应结果进行压缩。expired:如果响应头中包含Expires信息,则开启压缩。no-cache:如果响应头中包含Cache-Control:no-cache信息,则开启压缩。no-store:如果响应头中包含Cache-Control:no-store信息,则开启压缩。private:如果响应头中包含Cache-Control:private信息,则开启压缩。no_last_modified:如果响应头中不包含Last-Modified信息,则开启压缩。no_etag:如果响应头中不包含ETag信息,则开启压缩。auth:如果响应头中包含Authorization信息,则开启压缩。any:无条件对后端的响应结果开启压缩机制。
注意点: ①对于图片、视频类型的数据,会默认开启压缩机制,因此一般无需再次开启压缩。 ②对于
.js文件而言,需要指定压缩类型为application/javascript,而并非text/javascript、application/x-javascript。
响应头:
Content-Encoding: gzip
Vary: Accept-Encoding
8.缓存
http{
# 设置缓存的目录,并且内存中缓存区名为hot_cache,大小为128m,
# 三天未被访问过的缓存自动清除,磁盘中缓存的最大容量为2GB。
proxy_cache_path /soft/nginx/cache levels=1:2 keys_zone=hot_cache:128m inactive=3d max_size=2g;
server{
location / {
# 使用名为hot_cache的缓存空间
proxy_cache hot_cache;
# 对于200、206、304、301、302状态码的数据缓存1天
proxy_cache_valid 200 206 304 301 302 1d;
# 对于其他状态的数据缓存30分钟
proxy_cache_valid any 30m;
# 定义生成缓存键的规则(请求的url+参数作为key)
proxy_cache_key $host$uri$is_args$args;
# 资源至少被重复访问三次后再加入缓存
proxy_cache_min_uses 3;
# 出现重复请求时,只让一个去后端读数据,其他的从缓存中读取
proxy_cache_lock on;
# 上面的锁超时时间为3s,超过3s未获取数据,其他请求直接去后端
proxy_cache_lock_timeout 3s;
# 对于请求参数或cookie中声明了不缓存的数据,不再加入缓存
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
# 在响应头中添加一个缓存是否命中的状态(便于调试)
add_header Cache-status $upstream_cache_status;
}
}
}
proxy_cache_path:代理缓存的路径。
-
语法:
proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time]; -
是的,你没有看错,就是这么长....,解释一下每个参数项的含义:
-
path:缓存的路径地址。 -
levels:缓存存储的层次结构,最多允许三层目录。levels=1:2 缓存空间有两层目录,第一次是1个字母,第二次是2个字母 举例说明: proxy_cache_key通过MD5加密以后的值为 43c8233266edce38c2c9af0694e2107d levels=1:2 最终的存储路径为/usr/local/proxy_cache/d/07 levels=2:1:2 最终的存储路径为/usr/local/proxy_cache/7d/0/21 levels=2:2:2 最终的存储路径为/usr/local/proxy_cache/7d/10/e2 -
use_temp_path:是否使用临时目录。 -
keys_zone:指定一个共享内存空间来存储热点Key(1M可存储8000个Key)。 -
inactive:设置缓存多长时间未被访问后删除(默认是十分钟)。 -
max_size:允许缓存的最大存储空间,超出后会基于LRU算法移除缓存,Nginx会创建一个Cache manager的进程移除数据,也可以通过purge方式。 -
manager_files:manager进程每次移除缓存文件数量的上限。 -
manager_sleep:manager进程每次移除缓存文件的时间上限。 -
manager_threshold:manager进程每次移除缓存后的间隔时间。 -
loader_files:重启Nginx载入缓存时,每次加载的个数,默认100。 -
loader_sleep:每次载入时,允许的最大时间上限,默认200ms。 -
loader_threshold:一次载入后,停顿的时间间隔,默认50ms。 -
purger:是否开启purge方式移除数据。 -
purger_files:每次移除缓存文件时的数量。 -
purger_sleep:每次移除时,允许消耗的最大时间。 -
purger_threshold:每次移除完成后,停顿的间隔时间。
-
proxy_cache:开启或关闭代理缓存,开启时需要指定一个共享内存区域。
-
语法:
proxy_cache zone | off;zone为内存区域的名称,即上面中keys_zone设置的名称。
proxy_cache_key:定义如何生成缓存的键。
-
语法:
proxy_cache_key string;string为生成Key的规则,如$scheme$proxy_host$request_uri。
proxy_cache_valid:缓存生效的状态码与过期时间。
-
语法:
proxy_cache_valid [code ...] time;code为状态码,time为有效时间,可以根据状态码设置不同的缓存时间。- 例如:
proxy_cache_valid 200 302 30m;
proxy_cache_min_uses:设置资源被请求多少次后被缓存。
-
语法:
proxy_cache_min_uses number;number为次数,默认为1。
proxy_cache_use_stale:当后端出现异常时,是否允许Nginx返回缓存作为响应。
-
语法:
proxy_cache_use_stale error;error为错误类型,可配置timeout|invalid_header|updating|http_500...。
proxy_cache_lock:对于相同的请求,是否开启锁机制,只允许一个请求发往后端。
- 语法:
proxy_cache_lock on | off;
proxy_cache_lock_timeout:配置锁超时机制,超出规定时间后会释放请求。
proxy_cache_lock_timeout time;
proxy_cache_methods:设置对于那些HTTP方法开启缓存。
-
语法:
proxy_cache_methods method;method为请求方法类型,如GET、HEAD等。
proxy_no_cache:定义不存储缓存的条件,符合时不会保存。
-
语法:
proxy_no_cache string...;-
string为条件,例如$cookie_nocache $arg_nocache $arg_comment;$cookie_nocache 指的是当前请求的cookie中键的名称为nocache对应的值 $arg_nocache和$arg_comment 指的是当前请求的参数中属性名为nocache和comment对应的属性值
-
proxy_cache_bypass:定义不读取缓存的条件,符合时不会从缓存中读取。
-
语法:
proxy_cache_bypass string...;- 和上面
proxy_no_cache的配置方法类似。
- 和上面
add_header:往响应头中添加字段信息。
- 语法:
add_header fieldName fieldValue;
$upstream_cache_status:记录了缓存是否命中的信息,存在多种情况:
MISS:请求未命中缓存。HIT:请求命中缓存。EXPIRED:请求命中缓存但缓存已过期。STALE:请求命中了陈旧缓存。REVALIDDATED:Nginx验证陈旧缓存依然有效。UPDATING:命中的缓存内容陈旧,但正在更新缓存。BYPASS:响应结果是从原始服务器获取的。- PS:这个和之前的不同,之前的都是参数项,这个是一个
Nginx内置变量。
8.1缓存清理
当缓存过多时,如果不及时清理会导致磁盘空间被“吃光”,因此我们需要一套完善的缓存清理机制去删除缓存,在之前的proxy_cache_path参数中有purger相关的选项,开启后可以帮我们自动清理缓存,但遗憾的是:purger系列参数只有商业版的NginxPlus才能使用,因此需要付费才可使用。
不过天无绝人之路,我们可以通过强大的第三方模块ngx_cache_purge来替代,先来安装一下该插件: ①首先去到Nginx的安装目录下,创建一个cache_purge目录:
[root@localhost]# mkdir cache_purge && cd cache_purge
②通过wget指令从github上拉取安装包的压缩文件并解压:
[root@localhost]# wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz
[root@localhost]# tar -xvzf 2.3.tar.gz
③再次去到之前Nginx的解压目录下:
[root@localhost]# cd /soft/nginx/nginx1.21.6
④重新构建一次Nginx,通过--add-module的指令添加刚刚的第三方模块:
[root@localhost]# ./configure --prefix=/soft/nginx/ --add-module=/soft/nginx/cache_purge/ngx_cache_purge-2.3/
⑤重新根据刚刚构建的Nginx,再次编译一下,但切记不要make install:
[root@localhost]# make
⑥删除之前Nginx的启动文件,不放心的也可以移动到其他位置:
[root@localhost]# rm -rf /soft/nginx/sbin/nginx
⑦从生成的objs目录中,重新复制一个Nginx的启动文件到原来的位置:
[root@localhost]# cp objs/nginx /soft/nginx/sbin/nginx
8.使用make进行升级
make upgrade
至此,第三方缓存清除模块ngx_cache_purge就安装完成了,接下来稍微修改一下nginx.conf配置,再添加一条location规则:
location ~ /purge(/.*) {
# 配置可以执行清除操作的IP(线上可以配置成内网机器)
# allow 127.0.0.1; # 代表本机
allow all; # 代表允许任意IP清除缓存
proxy_cache_purge $host$1$is_args$args;
}
然后再重启Nginx,接下来即可通过http://xxx/purge/xx的方式清除缓存。
9.Nginx实现IP黑白名单
有时候往往有些需求,可能某些接口只能开放给对应的合作商,或者购买/接入API的合作伙伴,那么此时就需要实现类似于IP白名单的功能。而有时候有些恶意攻击者或爬虫程序,被识别后需要禁止其再次访问网站,因此也需要实现IP黑名单。那么这些功能无需交由后端实现,可直接在Nginx中处理。
Nginx做黑白名单机制,主要是通过allow、deny配置项来实现:
allow xxx.xxx.xxx.xxx; # 允许指定的IP访问,可以用于实现白名单。
deny xxx.xxx.xxx.xxx; # 禁止指定的IP访问,可以用于实现黑名单。
要同时屏蔽/开放多个IP访问时,如果所有IP全部写在nginx.conf文件中定然是不显示的,这种方式比较冗余,那么可以新建两个文件BlocksIP.conf、WhiteIP.conf:
# --------黑名单:BlocksIP.conf---------
deny 192.177.12.222; # 屏蔽192.177.12.222访问
deny 192.177.44.201; # 屏蔽192.177.44.201访问
deny 127.0.0.0/8; # 屏蔽127.0.0.1到127.255.255.254网段中的所有IP访问
# --------白名单:WhiteIP.conf---------
allow 192.177.12.222; # 允许192.177.12.222访问
allow 192.177.44.201; # 允许192.177.44.201访问
allow 127.45.0.0/16; # 允许127.45.0.1到127.45.255.254网段中的所有IP访问
deny all; # 除开上述IP外,其他IP全部禁止访问
分别将要禁止/开放的IP添加到对应的文件后,可以再将这两个文件在nginx.conf中导入:
http{
# 屏蔽该文件中的所有IP
include /soft/nginx/IP/BlocksIP.conf;
server{
location xxx {
# 某一系列接口只开放给白名单中的IP
include /soft/nginx/IP/blockip.conf;
}
}
}
对于文件具体在哪儿导入,这个也并非随意的,如果要整站屏蔽/开放就在http中导入,如果只需要一个域名下屏蔽/开放就在sever中导入,如果只需要针对于某一系列接口屏蔽/开放IP,那么就在location中导入。
当然,上述只是最简单的
IP黑/白名单实现方式,同时也可以通过ngx_http_geo_module、ngx_http_geo_module第三方库去实现(这种方式可以按地区、国家进行屏蔽,并且提供了IP库)。