processes
- master process:nginx 主进程,负责管理 worker 进程和读取配置,不处理具体请求。
- worker process:实际处理客户端请求的进程,数量一般等于 CPU 核心数。2 核就有 2 个 worker。
- cache manager process:nginx 缓存管理进程,用于清理过期缓存文件,不计入worker_processes。
案例1:
如果现在有一个 2核 的服务器,nginx 配置 worker_processes auto; 执行ps -ef|grep nginx之后
root 31722 1 0 13:20 ? 00:00:00 nginx: master process ...
www 31723 31722 0 13:20 ? 00:00:00 nginx: worker process
www 31724 31722 0 13:20 ? 00:00:00 nginx: worker process
www 31725 31722 0 13:20 ? 00:00:00 nginx: cache manager process
为什么会多一个进程
当启用了 nginx 的 缓存功能(例如 proxy_cache_path),nginx 会额外启动 cache manager 和 cache loader 进程:
- cache manager:定期检查缓存目录,删除过期的缓存文件。
- cache loader:在 nginx 启动时加载磁盘上的缓存元数据到内存,启动完成后会退出。
验证方法:nginx.conf 里搜索proxy_cache_path或fastcgi_cache_path
worker_connections
events{
worker_connections 1024;
}
在 Nginx 配置中,events 块的 worker_connections 用于定义单个 worker 进程可同时处理的最大连接数(默认通常为 1024)。若将其配置得 “非常大”(如远超系统承载能力的 10 万、100 万),不会单纯带来 “连接数提升” 的好处,反而会引发一系列系统资源过载、性能反降甚至服务崩溃的问题,具体后果可从资源消耗、系统限制、Nginx 自身逻辑三个维度拆解:
一、核心后果:系统资源被过度占用,引发连锁故障
worker_connections 并非 “配置越大越好”—— 每个连接(即使是空闲连接)都需要消耗系统的内存和文件描述符,配置过大会直接导致这两类核心资源耗尽。
- 内存耗尽(最直接、最致命的后果)
Nginx 的每个连接(包括 TCP 连接、HTTP 连接)都需要占用一块 “连接结构体” 内存(约 2KB~10KB,取决于连接类型和 Nginx 版本),同时 Linux 内核为每个 TCP 连接也会分配 “套接字(socket)缓冲区”(默认约 8KB 接收缓冲区 + 8KB 发送缓冲区,可通过sysctl调整)。
当worker_connections配置过大时(如 100 万),即使实际连接数未达上限,Nginx 启动时也可能因 “预分配连接资源” 或 “内核为潜在连接预留缓冲区” 导致内存被大量占用:
- 若服务器物理内存 / 虚拟内存不足,会触发 OOM(Out Of Memory)杀手:系统会强制杀死占用内存最高的进程(通常是 Nginx worker 进程),直接导致 Nginx 服务崩溃;
- 若内存未完全耗尽,剩余内存会被大量用于连接缓冲,导致 Nginx 处理 “实际请求”(如解析 HTTP 头、转发静态文件)的内存不足,引发请求处理延迟飙升、超时率上升;
- 极端情况下,系统内存耗尽会导致其他服务(如数据库、监控工具)也被 OOM 杀死,引发整机故障。
- 文件描述符(FD)耗尽,新连接无法建立
在 Linux 系统中,一切皆文件——Nginx 的每个连接(socket)、打开的配置文件、日志文件都需要占用一个 “文件描述符(File Descriptor,FD)”。
worker_connections的最大值受限于两个层面的 FD 限制,配置过大会直接突破限制:
- 进程级 FD 限制:Linux 对单个进程的最大 FD 数有默认限制(如
ulimit -n默认值通常为 1024 或 65535)。若worker_connections超过该值,Nginx 启动时会报错too many open files,worker 进程无法正常启动; - 系统级 FD 限制:Linux 还会限制整机的最大 FD 数(通过
sysctl -a | grep fs.file-max查看,默认可能为几十万)。若worker_connections × worker_processes(总最大连接数)超过系统级限制,即使进程级 FD 已调大,新连接仍会被内核拒绝,表现为 “客户端无法建立连接(Connection Refused)”。 即使手动调大 FD 限制(如通过ulimit -n 1000000),也会导致系统 FD 资源被 Nginx 独占,其他进程(如 SSH、日志收集工具)无法获取 FD,进而无法正常工作。
二、性能反降:连接数远超 “实际处理能力”,资源错配
Nginx 的 “连接处理” 并非孤立 —— 每个连接背后可能对应一个 HTTP 请求,而请求处理需要 CPU 计算(解析请求头、执行路由逻辑)、磁盘 I/O(读取静态文件)或 网络 I/O(反向代理到后端服务)。
若 worker_connections 配置过大,会出现 “连接数远超实际处理能力” 的情况:
- CPU 过载:单个 worker 进程是 “单线程、事件驱动” 的,若同时有几十万连接触发请求,worker 会陷入 “频繁处理事件循环” 的状态,无法高效处理核心请求(如静态文件转发),导致 CPU 使用率飙升至 100%,请求响应时间(RTT)从毫秒级变为秒级;
- I/O 瓶颈凸显:即使 CPU 未过载,磁盘 I/O(如机械硬盘每秒只能处理几百次读写)或网络带宽(如 1G 网卡每秒最大传输约 100MB)也会成为瓶颈。此时多余的连接只会处于 “排队等待 I/O” 的状态,不仅无法提升吞吐量,还会因连接超时(如
keepalive_timeout)导致大量重试,进一步加剧 I/O 压力; - 空闲连接浪费资源:实际业务中,大量连接是 “长连接(keepalive)” 或 “空闲连接”(如客户端建立连接后未发送请求)。若
worker_connections过大,这些空闲连接会长期占用内存和 FD,挤占 “活跃连接” 的资源,导致活跃请求被阻塞。
三、Nginx 自身逻辑限制:配置过大可能触发启动失败或异常
Nginx 对 worker_connections 有隐性逻辑限制,并非 “配置多少就支持多少”:
- 启动时校验失败:若
worker_connections超过worker_rlimit_nofile(Nginx 进程级 FD 限制,默认继承系统ulimit -n),Nginx 启动日志会输出worker_connections exceed open file resource limit,直接启动失败; - 连接数与 worker 进程的匹配问题:总最大连接数 =
worker_processes × worker_connections(通常建议worker_processes等于 CPU 核心数)。若worker_connections过大,总连接数可能远超服务器的 “TCP 端口范围”(Linux 端口默认范围是 1024~65535,即单个 IP 最多支持约 6.4 万 outbound 连接)—— 若 Nginx 作为反向代理(需主动连接后端服务),会因 “无法分配新端口” 导致后端连接失败; - 事件模型限制:Nginx 依赖 Linux 的事件模型(如
epoll)处理连接,epoll的 “最大监听连接数” 受限于fs.epoll.max_user_watches(默认约 10 万)。若worker_connections超过该值,epoll无法注册新连接,Nginx 会无法感知新连接请求,表现为 “客户端连接超时,但 Nginx 日志无任何记录”。
四、总结:合理配置 worker_connections 的原则
worker_connections 的合理值并非固定,需结合服务器硬件(CPU、内存、带宽)、业务场景(长连接 / 短连接、请求量)、系统限制综合计算,核心原则如下:
- 不超过系统 / 进程 FD 限制:确保
worker_connections ≤ worker_rlimit_nofile(建议worker_rlimit_nofile手动设置为 65535 或更高,避免依赖系统默认值); - 不超过内存承载能力:按 “每个连接占用 20KB 内存” 估算(保守值),若服务器内存为 8GB,可分配给 Nginx 连接的内存若为 4GB,则单 worker 最大连接数 ≈ 4GB / 20KB ≈ 20 万(需结合
worker_processes分摊); - 匹配实际业务吞吐量:通过监控工具(如
nginx-status、Prometheus)观察 “实际最大并发连接数”,通常配置为 “实际峰值的 1.2~1.5 倍” 即可(如实际峰值 1 万连接,配置 1.5 万即可,无需追求几十万); - 参考内核参数:调优相关内核参数以匹配
worker_connections,如:
# 系统级最大 FD 数
sysctl -w fs.file-max=1000000
# epoll 最大监听数
sysctl -w fs.epoll.max_user_watches=1000000
# TCP 连接超时回收(减少空闲连接)
sysctl -w net.ipv4.tcp_keepalive_time=600
总之,worker_connections 是 “系统资源与业务需求的平衡参数”,而非 “越大越好的性能开关”。配置过大会直接触发资源耗尽、性能反降甚至服务崩溃,合理的做法是 “基于实际监控数据,结合硬件上限逐步调优”。
http
include mime.types;
1. 什么是 MIME 类型
mime.types 文件是 Nginx 用来映射文件扩展名与 MIME 类型的配置文件。
它的主要作用是:当 Nginx 处理静态文件时,告诉浏览器(或其他客户端)该文件的类型,从而让客户端正确解析和显示内容。
MIME(Multipurpose Internet Mail Extensions)类型是一种标准化的方式,用来表示文档、文件或字节流的性质和格式。
- 在 HTTP 协议中,通过响应头
Content-Type告诉客户端返回的文件类型。 - 例如:
text/html表示 HTML 页面application/javascript表示 JavaScript 文件image/png表示 PNG 图片
如果服务器返回的 Content-Type 不正确,浏览器可能会:
- 直接下载文件而不是显示
- 显示乱码
- 无法正确执行脚本或渲染图片
2. mime.types 的作用
mime.types 文件里定义了 “文件扩展名” 和 “MIME 类型” 的对应关系,例如:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/json json;
}
- 左边是 MIME 类型
- 右边是对应的文件扩展名(多个扩展名用空格分隔)
当 Nginx 处理一个
.js文件时:
- 查找
mime.types,发现.js对应application/javascript - 在 HTTP 响应头中加入:
Content-Type: application/javascript
- 浏览器收到后,就知道这是 JavaScript 文件,会执行而不是下载。
3. Nginx 中如何使用 mime.types
在 nginx.conf 中,通常会这样引用:
http {
include mime.types;
default_type application/octet-stream;
}
include mime.types;:加载mime.types文件中的映射关系default_type application/octet-stream;:如果文件扩展名没有在mime.types中找到匹配项,就使用默认类型(通常会触发浏览器流式下载该文件)
4. 如果不配置 mime.types 会怎样
- 所有未匹配到类型的文件都会返回
application/octet-stream - 浏览器可能会下载这些文件,而不是直接显示或执行
- 例如
.html文件不会被解析为网页,而是直接下载
server
server 主要是用来 定义一个虚拟主机(Virtual Host) 的配置。当有请求到达时,如何处理针对某个域名(或 IP + 端口)的访问。
核心指令说明
listen
指定监听的端口,例如80、443 ssl。server_name
指定匹配的域名,可以写多个,空格分隔。location
根据 URL 路径匹配不同的处理规则,例如反向代理、静态文件等。root
指定静态文件的根目录。index
默认首页文件名。access_log/error_log
访问日志和错误日志路径。
多域名部署多站点
通过 server_name 指令区分不同域名,共用 80/443 端口。
基本配置思路
- 一个服务器监听 80/443 端口
- 用
server_name区分不同域名 - 每个域名对应不同的根目录或反向代理
# 站点A配置
server {
listen 80;
server_name site-a.com www.site-a.com;
root /var/www/site-a;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
}
# 站点B配置
server {
listen 80;
server_name site-b.com www.site-b.com;
root /var/www/site-b;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
}
include
用于在一个配置文件中引入其他配置文件的内容,能有效提高配置的可维护性。
主配置文件 nginx.conf:
http {
include mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
}
子配置文件 conf.d/default.conf:
server {
listen 80;
server_name example.com;
root /var/www/html;
}
nginx 日志
nginx 默认已经帮我们记录了日志,在 /var/log/nginx/ 目录下面。
错误日志
[root@web01 nginx]# cat error.log
2023/04/12 11:34:25 [error] 2342#2342: *1 open() "/web/one/favicon.ico" failed (2: No such file or directory), client: 192.168.61.1, server: [localhost](https://localhost/), request: "GET /favicon.ico HTTP/1.1", host: "192.168.61.139", referrer: "<http://192.168.61.139/>"
# 没有 favicon.ico 文件,可以切换到站点目录中去下载一个:wget <https://www.mi.com/favicon.ico>
# 还有人故意访问一个错误的路径,让你的网站报错,显示出 nginx 的版本。
error_log /opt/nginx_error.log info;
访问日志
访问日志要配置在在 server 配置外面
# 定制日志记录格式:这个必须配置在在 server 配置外面
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"http_referer" "$http_user_agent" "$gzip_ratio"';
# compression 可以理解为是这个格式的名字,谁想用这个格式,谁就用这个名字来指定格式
192.168.61.1 - - [12/Apr/2023:14:19:59 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
# $remote_addr 客户端的 ip 地址
# $remote_user 客户端的用户名
# $time_local 当前时间
# $request 请求起始行
# $status http 状态码
# $bytes_sent 响应资源的大小
# $http_referer 记录资源的跳转地址
# $http_user_agent 用户的终端信息
# $gzip_ratio gzip 的压缩级别
记录日志
server {
listen 80;
server_name b.jaden.com;
access_log /opt/nginx/b.jaden.com_log compression; # compression 是上面指定的日志格式的名称,/opt/ 目录下面没有 nginx 目录,需要我们手动创建,这个目录是随意指定的昂,mkdir /opt/nginx,还要授权:chown nginx:nginx /opt/nginx,不然 nginx 用户没办法访问这个目录
location / {
root /web/two;
index index.html index.htm;
}
}
htps 原理
上述非对称加密在数据传输的过程中,容易被黑客拦截。
上述非对称加密,被黑客拿到之后,也可以篡改,将篡改后的消息返回给客户端,客户端没办法判断服务器公钥是黑客的还是真实服务器的。
TLS证书
Transport Layer Security:传输加密协议,规定了如何为网络中传输的数据进行加密和解密。
SSL(Secure Socket Layer):早期由网景公司设计的加密协议,后贡献给 IETF 组织,并最终重命名为 TLS,SSL 是TLS的前身。TLS 方式有:对称加密、非对称加密。
服务端安装 SSL证书
服务端安装了 SSL 证书之后,网站就可以采用 https 了。
- 申请域名
- 去阿里云申请一个证书
- CA 公司会创建一个证书并返回
- 下载
- 解压
.key一般是 私钥文件,由服务器端唯一持有,必须严格保密,不能泄露给任何第三方。在 TLS/SSL 握手时,服务器用私钥解密客户端发来的加密数据,- 私钥必须与证书文件(.pem)配对使用,否则无法建立 HTTPS 连接。
.pem证书文件,证书中含有服务器的公钥、域名信息、有效期、签发机构等。客户端(浏览器)会用证书验证服务器身份,并使用其中的公钥加密传输数据。
.key= 私钥(服务器端独有)
.pem= 公钥证书(可公开,发给客户端) - 将这两个文件放到服务器中的一个目录下即可
- 配置nginx,使用下载的证书
阿里云的 nginx 的证书部署文档中建议如下的配置:
# 以下属性中,以 ssl 开头的属性表示与证书配置有关。
server {
# 配置 HTTPS 的默认访问端口为 443。
# 如果未在此处配置 HTTPS 的默认访问端口,可能会造成 Nginx 无法启动。
# 如果您使用 Nginx 1.15.0 及以上版本,请使用 listen 443 ssl 代替 listen 443 和 ssl on。
listen 443 ssl; # http--80 https -- 443
#填写证书绑定的域名
server_name <yourdomain>; #www.wulaoban.top
root html;
index index.html index.htm;
#填写证书文件名称
ssl_certificate cert/<cert-file-name>.pem;
# 填写证书私钥文件名称
ssl_certificate_key cert/<cert-file-name>.key;
ssl_session_timeout 5m;
# 表示使用的加密套件的类型
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:NULL:!aNULL:!MD5:!ADH:!RC4;
# 表示使用的 TLS 协议的类型,您需要自行评估是否配置 TLSv1.1 协议。
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
#web 网站程序存放目录
root html;
index index.html index.htm;
}
}
配置原理:
- 第一步:浏览器请求建立 HTTPS 连接
用户输入
https://你的域名,浏览器会向服务器的 443 端口。 - 第二步:Nginx 发送证书(.pem 文件)给浏览器
Nginx 收到请求后,会把你配置的
.pem证书(包含公钥、域名、CA 签名等信息)发给浏览器。 - 第三步:浏览器验证证书合法性
浏览器会检查:
- 证书是否由可信的 CA 机构(如阿里云)签发;
- 证书的域名是否和你访问的域名一致;
- 证书是否在有效期内。
- 验证通过后,浏览器会用证书里的 公钥,生成一个 “随机加密密钥”(用于后续传输数据的对称密钥),并把这个密钥加密后发给 Nginx。
- 第四步:Nginx 用私钥(.key 文件)解密
Nginx 收到浏览器发来的 “加密密钥” 后,会用你配置的
.key私钥(只有你的服务器有)解密,得到这个 “随机加密密钥”。 - 第五步:建立加密连接,传输数据
Nginx 和浏览器就用这个 “随机加密密钥” 来加密 / 解密所有传输的数据(比如静态网页的 HTML/CSS),确保数据不会被中途窃取或篡改。
注意检查安全组是否正确放行443端口
return 网址跳转
我的网站支持 https 了,当以 http 的链接访问的时候,能跳转到 https
# HTTP 跳转 HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 永久跳转 (301) 到 HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL 证书配置
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# SSL 优化
...
# 根目录与索引文件
root /var/www/html;
index index.html index.htm;
# 日志
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
rewrite 网址跳转
Nginx 里的 return 和 rewrite 虽然都能实现跳转,但它们在功能、性能和使用场景上有明显区别。
| 特性 | return | rewrite |
|---|---|---|
| 主要用途 | 直接返回状态码和(可选)URL,适合固定规则的跳转 | 基于正则表达式匹配 URL,适合动态规则的重写或跳转 |
| 执行方式 | 立即终止当前请求处理,返回响应 | 按顺序匹配正则,如果匹配成功,可以继续执行后面的指令(除非用 last 或 break) |
| 状态码支持 | 支持所有 HTTP 状态码(如 301、302、307、403、500 等) | 跳转时只能返回 301 或 302(permanent 或 redirect 参数),或者内部重写(不返回客户端) |
| 性能 | 更高,不涉及正则解析 | 较低,因为要进行正则匹配 |
| 使用场景 | HTTP 跳 HTTPS、维护页、固定地址跳转 | URL 重写(如 SEO 友好链接)、带参数的跳转、复杂匹配规则 |
#使用 rewrite 跳转
server {
access_log off;
listen 80;
server_name www.example.top;
location / {
rewrite ^/(.*) https://www.wulaoban.top/$1 redirect; # redirect代表302状态码,临时跳转,^代表网址https://www.wulaoban.top,/(.*)其实就是匹配uri,$1 表示 () 中匹配到的内容,也就是.* 匹配到的内容
# rewrite ^/(.*) https://www.wulaoban.top/$1 permanent; # permanent 代表 301 状态码,永久跳转
}}
Gzip 压缩
服务器能够做压缩,既能够省流量,又能够加快传输速度。但是我们如果自己手动给每个文件进行压缩,就太慢了,所以我们部署 Nginx 的时候,一般都会给 Nginx 做自动压缩的配置:
gzip on; #开启 gzip 压缩
gzip_min_length 1k; #最小压缩文件,小于 1KB 的就不压缩了
gzip_buffers 4 32k; #内容缓冲,压缩需要提前规划一些内存空间出来,4 个 32KB 的空间gzip_http_version 1.1; #http 版本,默认是 1.0,1.1 需要自己声明,不过现在比较新的 nginx 应该默认就是 1.1 了
gzip_comp_level 9; #压缩等级,等级数 1 - 9,压缩等级越高,压缩用的时长越长,但是压缩的就越小
gzip_types text/css text/xml application/javascript; #压缩的文件类型,这些类型的文件才会被压缩,为什么压缩的都是文本文件,而不压缩图片、视频和音频等多媒体文件呢,因为文本文件的压缩比是最高的,值得压缩。比如 jpg 图片文件,这种格式的图片本身就是压缩过的文件,再压缩的意义不大。
gzip_vary on; #http 响应头添加 gzip 标识
gzip_disable "MSIE [1 - 7]."; #遇到 IE 浏览器 1 - 7 取消 gzip 压缩
传输时的文件格式
当在 Nginx 等服务器上开启 gzip 压缩功能后,服务器会对 JS 文件进行压缩处理。压缩后的文件会以特定的 gzip 格式(通常对应的 MIME 类型是application/gzip)进行传输。
这个压缩后的文件,从存储和传输角度看,已经不是原始的.js 格式文本,而是经过 gzip 算法处理生成的二进制数据 ,可以理解为是一种全新的、专门用于高效传输的格式。
浏览器端的处理
当浏览器接收到经过 gzip 压缩传输过来的数据时,它会检测到响应头中的Content-Encoding: gzip字段,这表明数据是经过 gzip 压缩的。然后浏览器会自动调用自身的解压机制,对这份压缩数据进行解压缩,将其还原成原始的 JS 代码,此时文件对于浏览器执行环境来说,就是一个正常的.js 格式文件,可以按照 JavaScript 语法规则进行解析和执行。
nginx 访问控制
访问控制行为无非就两种,允许(如白)和禁止(如黑)
访问控制有两个方式,一种是在 OSI 模型的四层传输层,一种是在第七层应用层。主机防火墙就是在四层控制,nginx 就是在七层控制。演示访问控制,需要开启防火墙。
这里只展示 nginx 的配置,简直某个IP 地址访问网站
server {
listen 80;
server_name a.jaden.com;
access_log /opt/nginx/a.jaden.com_log jaden;
location / {
deny 192.168.61.1; # 黑名单,不允许192.168.61.1访问这个网站
allow 0.0.0.0/0; # 白名单,0.0.0.0/0表示所有ip都在白名单
gzip on;
#...
root /web/one;
index index.html index.htm;
}
}
deny 192.168.61.1;:表示拒绝 IP 地址为192.168.61.1的客户端访问该虚拟主机,实现了黑名单的访问控制,即这个 IP 被禁止访问。allow 0.0.0.0/0;:0.0.0.0/0表示所有 IP 地址,allow指令允许所有 IP 访问,实现了白名单的访问控制(这里允许所有 IP,除了被deny的那个 IP)。Nginx 中访问控制指令的匹配顺序是先deny后allow,所以会先检查是否在黑名单(被deny),如果不在,再检查是否在白名单(被allow),这里由于allow了所有 IP,所以除了192.168.61.1外,其他 IP 都可以访问。
nginx 禁止 是页面显示 Forbidden
refer 防盗链
盗链:你自己网站视频下载地址,被别人放到他的网站上了,别人从他网站上点击你的下载链接,下载动作和流量走的是你的服务器,他收获了人气,你损失了流量。通过 referer 请求头就可以防盗链。只要下载请求数据中的 referer 值不是你自己网站的网址,那就不让下载。
server {
listen 80;
server_name example.com;
location ~* .(gif|jpg|jpeg|png|bmp|swf|flv|mp4)$ { # 匹配常见的媒体文件类型
valid_referers none blocked example.com;
if ($invalid_referer) {
return 403; # 如果Referer不合法,返回403 Forbidden状态码
}
}
}
none表示没有Referer头的请求,比如直接在浏览器地址栏输入资源地址访问的情况。blocked表示Referer头被代理服务器或者客户端软件修改、伪装或被防火墙等阻止的情况,此时Referer头可能是unknown等非法值。example.com表示允许来自example.com域名的请求。
if ($invalid_referer) :Nginx 会根据valid_referers的配置,自动设置$invalid_referer变量,如果请求的Referer不合法,该变量值为1,此时执行return 403;返回 403 状态码,禁止访问。