本文目录
[[toc]]
语法规则
配置文件由指令与指令块构成,每条指令以
;结尾,指令与参数间使用分割,指令块使用{}包裹。使用
include语句可以组合多个配置文件,提升可维护性。使用
#添加单行注释,使用$调用变量时间单位为有:
ms: 毫秒s: 秒m: 分钟h: 小时d: 天w: 周M: 月份,固定一个月 = 30 天y: 年份,固定一年 = 365 天
空间单位有:
- 不加单位: 字节
k/K: 1024 字节m/M: 1024 * 1024 字节g/G: 1024 * 1024 * 1024 字节
指令块有四种:
- http: 根配置
- upstream: 配置上游服务信息
- server: 指定站点信息
- location: 配置路径、资源匹配等
常见 Nginx 配置
日志配置
http {
# 配置日志输出的内容格式,命名为 main
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 配置访问日志存放位置,记录日志使用 main 格式
access_log /var/log/nginx/access.log main;
# 配置错误日志存放位置
error_log /var/log/nginx/error.log;
}gzip
http {
# 开启 gzip
gzip on;
# 声明小于 1KB 的文件不开启 gzip
gzip_min_length 1k;
# gzip 压缩级别
gzip_comp_level 2;
# 针对哪些 MIME 类型开启 gzip 压缩
gzip_types text/plain text/css application/xml text/javascript image/jpeg image/png;
}自动索引
http {
# 开启自动索引支持,直接访问目录时将会展示目录下所有文件,样式由 Nginx 提供
autoindex on;
}访问限流
http {
# 限制传输速度最大为 1k/s
# 避免大资源占满带宽,影响其他正常业务请求连接
set $limit_rate 1k;
}连接池
# 每个 worker 支持的并发连接数,包括 client 连接与 upstream 连接
worker_connections: 512;负载均衡
先配置提供服务的 Nginx 只能接受网关请求,限制外部直接访问
http {
server {
# 限制只能接受本机发来的请求,如果是集群可以配置集群的内网地址,比如 192.168.0.1:8080
listen 127.0.0.1:8080
}
}网关 Nginx 配置如下:
http {
# 为提供服务的集群命名为 local
upstream local {
# 前面配置的提供服务的设备 1
server 127.0.0.1:8080
# 前面配置的提供服务的设备 2
server 127.0.0.1:8081
# 前面配置的提供服务的设备 3
server 127.0.0.1:8082
}
# 定义一份缓存配置
# /tmp/nginx_cache 缓存文件的根目录
# levels=1:2 生成两层子目录,比如 `hash(key)` 为 `d41d8cd98f00b204e9800998ecf8427e`
# 会存放到 `/d/41/d41d8cd98f00b204e9800998ecf8427e` 的目录中
# keys_zone=test_cache:10m 定义共享内存区域的名称与 key 容量, 1M 约 8000 个 key
# max_size=10g 设置缓存总容量上限,超出会使用 LRU 淘汰
# inactive=60m 缓存过期时间为 1 小时,只要 1 小时没有被访问就过期
# use_temp_path=off 控制是否使用临时路径存储缓存文件
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=test_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
# 配置站点的域名
server_name nginx.he110.site
# 配置监听任意 IP 发来的消息
listen 80
location / {
# 更新 header 中的 Host 为客户端的信息,而不是反向代理的信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 将反向代理的结果缓存起来,提高性能
# 此缓存类似浏览器强缓存,没到时间不会过期
# test_cache 为之前配置的共享内存区名称
proxy_cache test_cache;
# 缓存的 key 配置,通过 主机 + uri + 参数 缓存请求结果
proxy_cache_key $host$uri$is_args$args;
# 针对这些状态码的请求,缓存时间设置为 1 天
proxy_cache_valid 200 304 302 1d;
# 所有请求转发到前面配置的集群中
proxy_pass http://local;
}
}
}Nginx 指令
常见指令
- 查询运行中的 Nginx:
ps -ef | grep nginx - 热部署升级 Nginx:
kill -USR2 ${Nginx 进程 pid},会自动平滑过度,新老 Nginx 一起工作,流量逐步切换到新 Nginx - 停止老 Nginx:
kill -WINCH ${Nginx 进程 pid},老 Nginx 会关闭worker,但是进程还在运行,不接收流量了,方便回退老 Nginx - 日志切割:
mv /var/log/nginx /var/log/nginx-bak && nginx -s reopen,直接将日志挪走再重新运行,就可以切割日志了,可以通过crontab自动备份 Nginx 日志
指令冲突
指令生效条件
Nginx 指令生效的条件是:
该条指令能在这个配置块中生效。例如: log_format 指令只能在 http 块下生效,在 server 、 location 中不会生效。
如果指令生效,并且相同指令使用了不同的值时,即为指令冲突。
指令将划分为两种类型:
- 值指令: 存储配置项的值,例如:
root、access_log、gzip - 动作指令: 指定 Nginx 行为,例如:
rewrite、proxy_pass
值指令是可以合并的,而动作类指令是不能合并的。
通常情况下,在 server_rewite 、 rewrite 、 content 等阶段能够生效的,就是动作类指令。
值指令继承
值指令继承规则:
- 子配置块定义: 直接使用子配置块的配置
- 子配置块未定义: 使用父配置块的值,如果父配置块未定义,使用默认值
参考如下示例
server {
listen 8080;
root /home/he110/nginx/html;
accesss_log logs/he110.access.log main;
location /test {
# 子块 root 覆盖父块的 root
root /home/he110/nginx/test;
# 子块 accesss_log 覆盖父块的 accesss_log
accesss_log logs/access.test.log main;
}
location /dlib {
# 直接使用子块的 alias 配置
alias dlib/;
# 不能定义到 location 中,不会生效
listen 4396;
}
location / {
# 继承父块的 root 与 accesss_log
}
}第三方 Nginx 模块
针对于第三方 Nginx 模块,指令是值指令还是动作指令不太好确定,可以从以下方面考虑:
- 指令在哪个块下生效。 当指令生效时,其值就被确定,不可被覆盖了。
- 指令允许出现在哪些块中。 如果允许在多个块中出现,粒度更细的块更具备决定作用。
- 如果是
server块中生效,会通过merge_srv_conf进行合并,可以通过源码确定是否合并,以及合并流程。 - 如果是
location块中生效,会通过merge_loc_conf进行合并,可以通过源码确定是否合并,以及合并流程。
listen 指令
- 作用: 立即响应该请求,跳过后续的所有阶段
- 默认值:
listen *:80 | *:8000; - 作用域:
server
# 监听 socket ,性能更好的方式
listen unix:/var/run/nginx.sock;
# 监听本地的 8080 端口
listen 127.0.0.1:8080;
# 监听本地请求
listen 127.0.0.1;
# 监听 IPv4 的 8080 端口
listen 8080;
# 监听 IPv4 + IPv6 的 8080 端口
listen *:8080;
# 老的 Nginx 需要使用 bind 覆盖 * ,从而实现单独的 listen
# 新版本的 Nginx 已经不需要了
listen localhost:8080 bind;
# 只监听 IPv6 的 8080
listen [::]:8080 ipv6only=on;
# 监听本机 IPv6
listen [::1];server_name 指令
server_name- 作用: 决定了请求应该走到哪个配置块中,支持多域名、泛域名、正则表达式等方式。
- 默认值:
server_name _; - 作用域:
http、server、location
server_name_in_redirect- 作用: 返回响应的时候,是否修改为 主域名 返回
- 默认值:
server_name_in_redirect off; - 作用域:
http、server、location
server_name 的匹配顺序为:
- 精确匹配,比如:
www.he110.site *在前面的泛域名,比如:*.he110.site*在后面的泛域名,比如:wap.*.he110.site- 按照配置中, server 块定义顺序匹配正则表达式
- 按顺序匹配第一个 default server
- 没有配置 server_name 的第一个 server 就是 default server
- 配置了
listen default;的 server 也是 default server
# 配置单域名
server_name www.he110.site;
# 配置多域名,第一个域名为主域名
server_name m.he110.site wap.he110.site;
# 返回响应的时候,修改为 主域名 返回
# 例如用户请求 wap.he110.site ,响应头中的 url 会自动修改为 m.he110.site
server_name_in_redirect on;
# 配置泛域名,支持 *.domain 或者直接省略 * 的写法
server_name www.he110.site wap.*.he110.site .m.he110.site;
# 配置正则表达式,需要使用 ~ 前缀,说明是正则匹配,可以与普通域名一起混用
server_name www.he110.site ~www\d+\.he110\.site$;
# 可以匹配所有没有传递 Host 头的请求
server_name "";
# 可以匹配所有未被 server 捕获的请求
server_name _;Nginx 进程间通信
基础同步工具
- 信号: 早期 Nginx 会基于信号,也就是 Signal 传递消息
- 共享内存: 现在更换为共享内存通信
- 锁: 通过锁确保进程操作的原子性,使用共享内存的模块有以下几个
- ngx_http_lua_api
- rbtree( 红黑树 )
- ngx_http_limit_conn_module
- ngx_stream_limit_conn_module: 流控模块
- ngx_stream_limit_req_module: 流控模块
- http cache: http 缓存
- ngx_http_file_cache
- ngx_http_proxy_cache
- ngx_http_scgi_cache
- ngx_http_uwsgi_cache
- ngx_http_fastcgi_cache
- ssl: TLS/SSL
- ngx_http_ssl_module
- ngx_mail_ssl_module
- ngx_stream_ssl_module
- 单链表:
- ngx_http_upstream_zone_module
- ngx_stream_upstream_zone_module
- Slab 内存管理器
- 锁: 通过锁确保进程操作的原子性,使用共享内存的模块有以下几个
Nginx 信号
| 信号 | 作用 | |
|---|---|---|
master 进程 | CHLD | 子进程给父进程发送该信号说明子进程故障,需要重新拉起 worker |
master 进程 | TERM | 立即停止 Nginx 进程,对应 nginx -s stop |
master 进程 | INT | 立即停止 Nginx 进程,对应 nginx -s stop |
master 进程 | QUIT | 不再接受新请求,当前所有请求处理完成后停止 Nginx 进程,对应 nginx -s quit |
master 进程 | HUP | 重载配置文件,对应 nginx -s reload |
master 进程 | USR1 | 重新打开日志文件,用于日志文件分割,对应 nginx -s reopen |
master 进程 | USR2 | 热部署使用,两 Nginx 平滑过度,老进程不再接收流量,但是也不会退出,无对应指令 |
master 进程 | WINCH | 热部署使用,停止老的 Nginx 所有 worker 子进程, Nginx 主进程不退出,无对应指令 |
worker 进程 | TERM | 立即停止 worker 进程,一般通过 Nginx 主进程统一管理,不会单独使用 |
worker 进程 | INT | 立即停止 worker 进程,一般通过 Nginx 主进程统一管理,不会单独使用 |
worker 进程 | QUIT | 不再接受新请求,当前所有请求处理完成后停止 worker 进程,一般通过 Nginx 主进程统一管理,不会单独使用 |
worker 进程 | USR1 | 重新打开日志文件,用于日志文件分割,一般通过 Nginx 主进程统一管理,不会单独使用 |
worker 进程 | WINCH | 热部署使用,停止 worker 子进程,一般通过 Nginx 主进程统一管理,不会单独使用 |
OpenResty 使用共享内存代码示例
http {
# 声明使用 10M 共享内存
lua_shared_dict dogs 10m;
server {
location /set {
content_by_lua_block {
# 拿到共享内存
local dogs = ngx.shared.dogs
# 将 Jim = 10 存入共享内存
dogs:set('Jim', 8)
# 发给用户 stoped
ngx.say('stoped')
}
}
location /get {
content_by_lua_block {
# 拿到共享内存
local dogs = ngx.shared.dogs
# 返回共享内存中纯的 Jim
ngx.say(dogs:set('Jim'))
}
}
}
}Slab 内存管理
- 将内存按固定大小,一般为 4kb ,切割为不同的空闲页,空闲页使用链表串联
- 每一页按照内存大小分割为不同类型的 slot ,比如 32 字节、 64 字节、 128 字节等等
- 每一页有三种状态: full 、 partial 、 empty
- 在分配的的时候,优先选择 partial 存放, slot 按顺序排列
- 对象按固定大小分类存储,避免外部碎片;空闲对象复用减少频繁释放导致的内碎片

这套内存管理成为 bestfit ,有以下特点
- 适合小对象
- 避免碎片
- 避免重复初始化
可以使用 ngx_slab_stat 查看不同 slot 的使用情况
http {
server {
listen 80;
location = /slab_stat {
slab_stat;
}
}
}TLS/SSL
根据 Nginx 的主要使用场景,可以针对性的对算法进行优化与选择,包括更换算法、调整加密等级、使用会话缓存等,以提高通信性能
- 小文件传输时,性能瓶颈在非对称加密,也就是握手阶段
- 大文件传输时,性能瓶颈在对称加密,也就是数据传输阶段
完整通信过程如下:
---
title: TLS 通信流程
---
sequenceDiagram
participant Client
participant Server as Nginx
Note over Client,Server: === 握手阶段 ===
Client->>Server: Client Hello<br>通知服务器自身支持哪些 TLS 版本、密码套件列表、Client Random
Server->>Client: Server Hello<br>选择 TLS 版本、密码套件,返回 Server Random
Server->>Client: Server Certificate<br>发送证书链(含公钥)
Server->>Client: Server Key Exchange (可选)<br>如使用ECDHE/DHE算法,发送临时公钥
Server->>Client: Server Hello Done
Note over Client,Server: === 证书验证与密钥交换 ===
Client ->> Client: 验证证书有效性(CA链、有效期、吊销状态等)
Client->>Server: Client Key Exchange<br>生成 PreMasterSecret ,用服务器公钥加密后发送
Client->>Server: ChangeCipherSpec<br>通知切换至加密通信
Client->>Server: Finished<br>加密验证握手完整性
Server->>Client: ChangeCipherSpec
Server->>Client: Finished
Note over Client,Server: === 加密通信阶段 ===
Note over Client,Server: 双方进行会话密钥生成<br>基于 ClientRandom + ServerRandom + PreMasterSecret
Client->>Server: Application Data (Encrypted)
Server->>Client: Application Data (Encrypted)---
title: TLS 通信命中缓存
---
sequenceDiagram
participant Client
participant Server
Note over Client,Server: === 握手阶段 ===
Client->>Server: Client Hello<br>通知服务器自身支持哪些 TLS 版本、密码套件列表、Client Random
Server->>Client: Server Hello<br>确认复用会话,返回 Server Random
Note over Client,Server: === 证书验证与密钥交换 ===
Server->>Client: ChangeCipherSpec
Server->>Client: Finished<br>使用缓存密钥加密验证
Note over Client,Server: === 加密通信阶段 ===
Note over Client,Server: 复用上次通信使用的密钥
Client->>Server: Application Data (Encrypted)
Server->>Client: Application Data (Encrypted)Nginx 添加 TLS 证书相关配置如下:
http {
# HTTPS 使用的是 443 端口
listen 443 ssl;
# 配置证书的公钥
ssl_certificate /etc/letsencrypt/live/me.he110.site/fullchain.pem;
# 配置证书的私钥
ssl_certificate_key /etc/letsencrypt/live/me.he110.site/private.pem;
# session cache 最多缓存多大的空间, 1MB 大约对应 4000 个 session
ssl_session_cache shared:le_nginx_SSL:1m;
# 设置 session cache 有效期为 1 天,也就是说,缓存没溢出的情况下, 1 天内断开后重新连接不需要握手
ssl_session_timeout 1440m;
# 支持的 TLS 协议版本
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
# 通过 ssl_ciphers 决定使用什么安全套件与客户端进行通信
ssl_prefer_server_ciphers on;
# 声明支持的安全套件,一般越前面的越先使用,除非客户端不支持
ssl_ciphers "ECDHE-ECDSA-CHACHA20-P0LY1305:ECDHE-RSA-CHACHA20-P0LY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
# 非对称加密时的参数,决定了加密强度
ssl_dhparam /etc/letsencrypt/live/me.he110.site/dhparam.pem;
}Nginx 架构
Nginx 本身是多进程架构,由主进程管理 worker 进程、 cache 进程 、 cache-loader 进程。
多进程可以很好的保障共享内存异常时整个服务崩溃的情况,为了保障高可用, Nginx 采用了多进程架构。
Nginx 所有的功能都是由 worker 进程处理的,为了充分利用 CPU 资源,一般会将 worker 数量与 CPU 核心数设置为相同,并为每个 worker 进程绑定一个对应的的 CPU 。
当使用 nginx -s reload 或者 kill -SIGHUP ${Nginx PID} reload Nginx 时,本质上是将已有的 worker 进程 kill 掉,再重新创建 worker 进程。
当通过 kill -SIGTERM ${Nginx worker PID} 单独关闭某个子进程的时候,子进程会通知 Nginx 主进程,主进程会重新创建一个新的 worker 进程。
内存池分配
建立连接

在建立连接后, Nginx 会根据负载均衡策略,选中一个 worker 处理连接, worker 会为连接分配一块内存池,在连接断开时才会回收该内存空间。
在客户端发来请求后,会预先为请求分配 buffer 缓冲区,用于读取请求的 DATA ,空间从 连接内存池 中分配,如果连接内存池不够则进行扩容。
buffer 缓冲区主要用于读取用户发来的请求 data 。
# 默认为连接内存池分配的空间
connection_pool_size: 512;
# 连接的超时时间,默认为 60s ,如果 60s 还没有处理完成请求,就把连接设置为超时,关闭连接
# 该超时时间涵盖的范围包括: 接收请求、解析请求 URI 、 解析 header ,需要根据业务情况调整超时时间
client_header_timeout: 60s;
# 接收到请求后,将请求 data 读取到用户态中,预先分配出来读取 data 的空间
client_header_buffer_size: 1k;接受 URI

读取完请求的 data 后,会预先为请求分配一块请求内存池,用来存储解析后的请求上下文,请求结束后立即回收该内存空间。
开始解析请求 data ,存储到请求内存池中。
如果遇到请求内存池不够用的情况,会进行扩容。
处理完成后,会将存储 URI 的内存块地址,更新到指针中,标识 URI 。
开始解析 header ,存储到之前复用的请求内存池中,解析完成后标识 header 。
全都处理完成后,会移除超时定时器 client_header_timeout 。
# 预先为每个请求分配的内存池大小
request_pool_size: 4k;
# 设置请求内存池最大有多少空间
# 这里不是直接分配 8k ,而是每次分 8k ,如果不够用再扩容 8k ,一共 4 块 8k 的内存空间
# URL + header 都会使用这块空间
large_client_header_buffers: 4 8k;Nginx 工作流程
QUIT
QUIT 只能处理 HTTP 请求,针对 websocket 、 TCP 、 UDP 等通信是无法识别通信是否结束的,只能等待定时器超时。
---
title: worker QUIT 流程
---
graph TB
A[设置定时器 worker_shutdown_timeout] --> B[关闭监听句柄]
B --> C[关闭空闲连接]
C --> D[在循环中等待全部连接关闭,超时会强制关闭]
D --> E[退出进程]reload
---
title: Nginx reload 流程
---
graph TB
A[向 master 进程发送 HUP 信号] --> B[master 进程校验配置语法是否正确]
B --> C[master 进程打开新的监听端口]
C --> D[master 进程使用新配置启动新的 worker 子进程]
D --> E[master 进程向老的 worker 发送 QUIT 信号]
E --> F[老 worker 关闭监听句柄,处理完当前连接后结束进程]由于先启动新 worker 再停止老 worker ,所以 Nginx 不会停止服务,但是可能会存在老 worker 处理时间很长,一直占用资源。
在新版本中 Nginx 引入超时机制,在超时后强行关闭老 worker 进程。
热升级
---
title: Nginx 热升级流程
---
graph TB
A[将旧 Nginx 的二进制文件替换为新的 Nginx 二进制文件] --> B[向 master 进程发送 USR2]
B --> C[master 进程修改 PID 文件名,添加加后缀 .oldbin]
C --> D[master 进程使用新的 Nginx 文件启动新的 master 进程]
D --> E[向老的 master 进程发送 QUIT 信号,关闭老 master 进程]
E --> F[回滚:向老 master 进程发送 HUP ,向新 master 进程发送 QUIT]请求处理
---
title: Nginx 请求处理流程
---
graph TD
POST_READ["POST_READ阶段
(获取真实客户端IP)"] --> SERVER_REWRITE["SERVER_REWRITE阶段
(服务级URI重写)"]
SERVER_REWRITE --> FIND_CONFIG["FIND_CONFIG阶段
(匹配location块)"]
FIND_CONFIG --> REWRITE["REWRITE阶段
(location级URI重写)"]
REWRITE -->|触发重写| FIND_CONFIG
REWRITE --> POST_REWRITE{POST_REWRITE检查}
POST_REWRITE -->|未重写| PREACCESS["PREACCESS阶段
(并发/QPS限制)"]
POST_REWRITE -->|已重写| FIND_CONFIG
subgraph 权限验证
PREACCESS --> ACCESS["ACCESS阶段
(auth_basic/access控制)"]
ACCESS --> POST_ACCESS{POST_ACCESS检查}
POST_ACCESS -->|验证失败| LOG
POST_ACCESS -->|验证通过| PRECONTENT["PRECONTENT阶段
(try_files/镜像请求)"]
end
PRECONTENT --> CONTENT["CONTENT阶段
(生成响应内容)"]
CONTENT --> LOG["LOG阶段
(记录访问日志)"]
classDef phase fill:#f0f8ff,stroke:#4682b4,stroke-width:2px;
class POST_READ,REWRITE,PREACCESS,ACCESS,CONTENT,LOG phase;| 处理阶段 | 负责的模块 |
|---|---|
POST READ | realip |
SERVER REWRITE | rewrite |
FIND CONFIG | |
REWRITE | rewrite |
POST REWRITE | |
PREACCESS | limit_conn 、 limit_req |
ACCESS | auth_basic 、 access 、 auth_request |
POST ACCESS | |
PRECONTENT | try_files |
CONTENT | index 、 autoindex 、 concat |
LOG | access_log |
涉及的模块处理顺序如下图:

所有模块都会在 ngx_module_names 数组中定义。
不同阶段的模块会按阶段顺序执行。
相同阶段内的模块按顺序执行。
顺序在前的模块可以对流程进行控制,比如: 跳过当前阶段剩下所有模块,进入下一阶段。
Nginx 处理请求的阶段
postread 阶段
ngx_http_realip_module 模块
在网络传输过程中,源 IP 与目的 IP 会被交换机、路由器等网络设备修改,包括防火墙也可以进行修改,所以依据源 IP 、 目的 IP 是无法获取到请求客户端的真实 IP 地址的,只能拿到上一跳设备的地址。
在 HTTP 协议中,有 X-Forwarded-For 与 X-Real-IP 两个请求头,其中:
X-Forwarded-For: 完整的传输链路,链路中的发送端 IP 都会被接收端记录到该字段中X-Real-IP: 传递用户的 IP
realip 模块将会获取用户的真实地址,并记录到变量中,传输给其他模块,所以 realip 模块的执行优先级会比 Nginx 的 rewrite 模块都要高。
realip 模块可以在编译 Nginx 时,通过 --with-http_realip_module 启用。
realip 生成两个变量:
realip_remote_addr: 用户的真实 IPrealip_remote_port: 用户的真实端口
realip 提供了三条指令:
set_real_ip_from:- 基本格式:
set_real_ip_from ${address} / ${CIDR} / ${unix} - 作用: 配置针对哪些来源的数据包,替换 real ip
- 默认值: 无
- 作用域:
http、server、location
- 基本格式:
real_ip_header:- 基本格式:
real_ip_header ${field} / X-Real-IP / X-Forwarded-For / ${proxy_protocol} - 作用: 配置从哪个字段里面取真实 IP
- 默认值:
real_ip_header X-Real-IP; - 作用域:
http、server、location
- 基本格式:
real_ip_recursive:- 基本格式:
real_ip_recursive on / off; - 作用: real ip 可能取到多个字段,当最近的 IP 是环回地址,也即是本机 IP 的时候,是否丢弃该地址,继续取新地址
- 默认值:
real_ip_recursive off; - 作用域:
http、server、location
- 基本格式:
server_rewrite 阶段
rewrite 模块
return 指令
return 是 rewrite 模块提供的指令,一旦被使用,将立即终止请求处理流程,返回响应给客户端
return 指令的基本格式为 return [code] msg , return 省略 code 时,默认使用 302 状态码
- 作用: 立即响应该请求,跳过后续的所有阶段
- 默认值: 无
- 作用域:
server、location、if
error_page 指令
- 作用: 将请求转发到指定的资源上
- 默认值: 无
- 作用域:
http、server、location、location中的if
# 捕获 404 状态码,重定向到 404.html(保持原始 404 状态码)
# 用户访问不存在的资源时返回自定义 404 页面, HTTP 状态码仍为 404
# 需确保 /404.html 文件存在,且路径相对于 root 指令设置的目录
error_page 404 /404.html;
# 捕获服务器内部错误( 500 / 502 / 503 / 504 ),统一跳转至 50x.html
# 适用于上游服务崩溃、网关超时等场景,需在对应 location 配置 50x.html 的路径
error_page 500 502 503 504 /50x.html;
# 强制将 404 状态码改写为 200 ,返回空图像(常用于隐藏敏感错误信息)
# 等号后无具体状态码时默认使用 200
# 适用于需要前端展示正常页面但后端实际资源缺失的场景
error_page 404 =200 /empty.gif;
# 动态处理 404 错误( PHP 需配合 fastcgi_intercept_errors on 使用)
# 等号使 PHP 的 header() 状态码修改生效,若 PHP 返回 404 需改用 410 避免冲突
error_page 404 = /404.php;
# 高级重定向配置(通过命名 location 实现反向代理)
# @fallback 是内部重定向标记,外部无法直接访问
# 当原始请求不存在时,将流量转发至 backend 服务集群做容灾处理
location / {
error_page 404 = @fallback;
}
# 命名 location 块(仅限内部跳转)
# 可在此处配置日志记录、自定义响应头等高级操作
location @fallback {
proxy_pass http://backend;
}
# 直接重定向到外部域名(默认 302 临时跳转)
# 适用于权限校验失败时跳转至统一拦截页
error_page 403 http://example.com/forbidden.html;
# 永久重定向 404 请求到新域名(显式指定 301 状态码)
# 浏览器会缓存该跳转,后续直接访问新地址
error_page 404 =301 http://example.com/forbidden.html;rewrite 与 error_page 同时配置
当两者同时配置时,由于二者都属于动作指令,将控制 Nginx 返回响应,所以不会合并,例如:
server {
server_name return.he110.site;
listen 8080;
root /app/html;
# 定义为语句 1
error_page 404 /404.html;
# 定义为语句 2
return 403;
location / {
# 定义为语句 3
return 404 "nothing!";
}
}如果同时开启,语句执行顺序为:
- 语句 2
- 语句 3
- 语句 1
三个语句只能由一个被执行,会按照优先级,先执行的先返回,后面的被忽略。
rewrite 指令
- 基本语法:
rewrite ${regex} ${replacement} [flag],其中flag有如下取值:last: 用新的 URI 进行location匹配,last后定义的命令会被跳过break: 停止当前脚本指令的执行,等价于break指令,break后定义的命令会被跳过redirect: 返回 302 重定向permanent: 返回 301 重定向
- 作用: 将用户访问的 url 替换为新的 url
- 默认值: 无
- 作用域:
server、location、if
server {
root html/;
location /first {
# 替换 first 为 second ,转发到 location /second 继续解析
rewrite /first(.*) /second$1 last;
# rewrite 已经转发走了,所以不会执行 return
return 200 'first!';
}
location /second {
# 修改 second 为 third ,并读取本地的 /second/xx 文件返回
rewrite /second(.*) /third$1 break;
# break 已经停止了 location 处理,所以 return 不会被执行
return 200 'second!';
}
location /third {
# 执行 return
return 200 'third!';
}
}server {
location /redirectl {
# 返回 301 状态码,因为定义了 permanent
rewrite /redirectl(.*) $1 permanent;
}
location /redirect2 {
# 返回 302 状态码,因为定义了 redirect
rewrite /redirect2(.*) $1 redirect;
}
location /redirect3 {
# 由于返回了 http 请求,并且未指定状态码,会自动填充为 302
rewrite /redirect3(.*) http://rewrite.he110.site$l;
}
location /redirect4 {
# 返回 301 状态码,因为定义了 permanent
rewrite /redirect4(.*) http://rewrite.he110.site$1 permanent;
}
}if 指令
- 基本语法:
if (condition) {},condition取值如下:- 检查变量是否为 空 或者 值为 0
- 使用
=/!=将变量与字符串做匹配 - 使用正则匹配变量,需要加上前缀
~/!~开头表示大小写敏感~*/!~*开头表示大小写不敏感
- 检查文件是否存在:
-f/!-f - 检查目录是否存在:
-d/!-d - 检查文件 / 目录 / 软连接是否存在:
-e/!-e - 检查是否为可执行文件:
-x/!-x
- 作用: 按照
condition确定{}内的命令是否执行 - 默认值: 无
- 作用域:
server、location
# 匹配正则
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
# 匹配正则,不区分大小写
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
# 字符串匹配
if ($request_method = POST) {
return 405;
}
# 变量匹配
if ($slow){
limit_rate 10k;
}
if ($invalid_referer) {
return 403;
}find_config 模块
- location
- 基本语法:
location [= / ~ / ~* / ^~] uri {}uri: 配置 uri 前缀= uri: 完全匹配 uri^~ uri: 正则表达式匹配,匹配后不再进行正则表达式匹配~ uri: 正则表达式匹配,严格大小写~* uri: 正则表达式匹配,大小写不敏感
location @name {}: 跳转到内部的处理流程,该 location 无法通过 uri 直接访问,直接被其他命令跳转进来。
- 默认值: 无
- 作用域:
server、location
- 基本语法:
- merge_slashes
- 作用: 开启后,会将
//合并为/ - 基本语法:
merge_slashes on / off - 默认值:
merge_slashes on; - 作用域:
http、server
- 作用: 开启后,会将
整个 location 匹配顺序如下:
- 完全匹配 (
= uri) - 正则匹配,并且后续不进行正则匹配 (
^~ uri) - 按照最长匹配前缀排序,匹配的前缀最长的,先匹配。

server {
merge_slashes off;
location ~ /Test1/$ {
return 200 'first regular expressions match!';
}
location ~* /Test1/(w+)$ {
return 200 'longest regular expressions match!';
}
location ^~ /Test1/ {
return 200 'stop regular expressions match!';
}
location /Test1/Test2 {
return 200 'longest prefix string match!';
}
location /Test1 {
return 200 'prefix string match!';
}
location = /Test1 {
return 200 'exact match!';
}
}发送以下请求:
/Test1: 命中= /Test1,完全匹配优先级最高,哪怕是最后定义的/Test1/: 命中^~ /Test1/,匹配时遵循最长前缀匹配,所以不会命中完全匹配,而是命中了正则,而正则中^~有高优先级/Test1/Test2: 命中~* /Test1/(w+)$,匹配了正则表达式,并且是最长前缀,先命中/Test1/Test2/: 命中/Test1/Test2,正则表达式没命中,匹配了最长前缀/test1/Test2: 命中~* /Test1/(w+)$,匹配了正则表达式,只有一个匹配项,没什么争议
preaccess 阶段
ngx_http_limit_conn_module 模块
该模块用于限制每秒钟处理的 连接数 。
在 NGX_HTTP_PREACCESS_PHASE 阶段生效,默认编译进 nginx 。
通过共享内存在所有 worker 进程中生效。
使用 key 对链接进行分类,针对同一类的请求进行限流。
用于分类的 key 一般依赖于 realip 模块,需要针对真实 IP 限流才有意义。
- limit_conn_zone
- 作用: 定义共享内存(包括声明内存大小),以及 key 关键字
- 基本语法:
limit_conn_zone ${key} zone=${name:size};${key}: 限流对象,一般为用户真实 IP${name}: 共享内存名称${size}: 共享内存大小
- 默认值: 无
- 作用域:
http
- limit_conn
- 作用: 限制并发连接数
- 基本语法:
limit_conn ${zone} ${number}; - 默认值: 无
- 作用域:
http、server、location
- limit_conn_log_level
- 作用: 触发限流时的日志级别
- 基本语法:
limit_conn_log_level info / notice / warn / error; - 默认值:
limit_conn_log_level error; - 作用域:
http、server、location
- limit_conn_status
- 作用: 触发限流时,返回给客户端的错误码
- 基本语法:
limit_conn_status code; - 默认值:
limit_conn_status 503; - 作用域:
http、server、location
示例:
# 使用二进制的用户 IP 地址作为 key
# 定义了名为 addr 的共享内存,有 10M 大
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
root html/;
error_log logs/limit_conn.log info;
location / {
# 限流时返回 500 错误码
limit_conn_status 500;
# 限流时记录的日志为 warn 级别,避免频繁 IO
limit_conn_log_level warn;
# 使用 addr 内存记录,一次只处理 1 条请求,超过的部分会被限流,返回 limit_conn_status
limit_conn addr 1;
# 限制每秒钟返回 50 字节,延长请求响应时间,便于测试限流场景
limit_rate 50;
}
}ngx_http_limit_req_module 模块
该模块用于限制每秒钟处理的 请求数 。
在 NGX_HTTP_PREACCESS_PHASE 阶段生效,默认编译进 nginx 。
通过共享内存在所有 worker 进程中生效。
限流的算法采用 leaky bucket 算法: 在遇到突发流量时,如果缓冲区已满则返回错误,缓冲区未满则存储到缓冲区中,等待 worker 进程消费。
- limit_req_zone
- 作用: 定义共享内存(包括声明内存大小),以及 key 关键字
- 基本语法:
limit_req_zone ${key} zone=${name:size} rate=${rate};${key}: 限流对象,一般为用户真实 IP${name}: 共享内存名称${size}: 共享内存大小${rate}: 请求处理速率,单位为每秒请求数 ( r/s ) 或者每分钟请求数 ( r/m )
- 默认值: 无
- 作用域:
http
- limit_req
- 作用: 限制并发请求数
- 基本语法:
limit_req ${zone} [burst=${number}] [nodelay];burst: 配置请求缓冲区容纳的请求数nodelay: 声明为nodelay的话,burst内的请求也会被立即处理,也就是返回错误码
- 默认值:
burst默认为 0 - 作用域:
http、server、location
- limit_req_log_level
- 作用: 触发限流时的日志级别
- 基本语法:
limit_req_log_level info / notice / warn / error; - 默认值:
limit_req_log_level error; - 作用域:
http、server、location
- limit_req_status
- 作用: 触发限流时,返回给客户端的错误码
- 基本语法:
limit_req_status code; - 默认值:
limit_req_status 503; - 作用域:
http、server、location
示例:
# 使用二进制的用户 IP 地址作为 key
# 定义了名为 addr 的共享内存,有 10M 大
limit_req_zone $binary_remote_addr zone=addr:10m rate=2r/m;
server {
root html/;
error_log logs/limit_req.log info;
location / {
# 限流时返回 500 错误码
limit_req_status 500;
# 限流时记录的日志为 warn 级别,避免频繁 IO
limit_req_log_level warn;
# 使用 addr 内存记录,一次只处理 3 条请求,超过的部分会被限流,返回 limit_req_status
limit_req zone=addr burst=3 nodelay;
}
}同时配置 limit_conn 与 limit_req
可以使用如下配置,触发 limit_conn 返回 500 ,触发 limit_req 返回 503
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=req:10m rate=2r/m;
server {
root html/;
error_log logs/limit_conn.log info;
location / {
limit_conn_status 500;
limit_conn_log_level warn;
limit_rate 50;
limit_conn addr 1;
limit_req zone=one;
}
}结果是返回 503 ,因为 http_limit_req_module 会比 http_limit_conn_module 先被调用,所以先完成了返回
access 阶段
ngx_http_access_module 模块
该模块用于限制特定 IP 的访问,例如 IP 封禁等功能。
在 NGX_HTTP_ACCESS_PHASE 阶段生效,默认编译进 nginx 。
- allow
- 作用: 允许访问的用户地址
- 基本语法:
allow ${address} / ${CIDR} / ${unix} / all; - 默认值: 无
- 作用域:
http、server、location、limit_except
- deny
- 作用: 禁止访问的用户地址
- 基本语法:
deny ${address} / ${CIDR} / ${unix} / all; - 默认值: 无
- 作用域:
http、server、location、limit_except
例如:
location / {
# 支持配置单个 IP
deny 192.168.0.1;
# 支持子网掩码
allow 192.168.1.0/24;
# 支持 IPv6
allow 2001:0db8::/24;
# deny 与 allow 是顺序执行,全匹配必须放到最后面,否则后续命令都不会生效
deny all;
}ngx_http_auth_basic_module 模块
该模块基于 HTTP Basic Authutication 协议,对用户身份进行明文的账号密码验证,需要搭配 https 一起使用。
在 NGX_HTTP_ACCESS_PHASE 阶段生效,默认编译进 nginx ,通过 --without-http_auth_basic_module 禁用 。
- auth_basic
- 作用: 配置是否开启 HTTP Basic Authutication
- 基本语法:
auth_basic ${string} / off;${string}: 给用户输入账号密码时,展示的提示文本。
- 默认值:
auth_basic off; - 作用域:
http、server、location、limit_except
- auth_basic_user_file
- 作用: 用户密码存储在哪个文件
- 基本语法:
auth_basic_user_file ${file} - 默认值: 无
- 作用域:
http、server、location、limit_except
通过 httpd-tools 安装存储密码的数据库操作工具。
使用 htpasswd -c ${file} -b ${user} ${pass} 添加账号
${file}: 数据库文件地址${user}: 用户名${pass}: 密码,如果同名会覆盖密码
HTTP Basic Authutication 协议基本没有使用了,但是在部署内网服务或者快速上线服务,配合 https 也是一个不错的方案。
ngx_http_auth_request_module 模块
收到请求后,生成子请求,通过反向代理技术传递给上游服务。
若上游服务返回的响应码是 2xx ,则继续执行。
若上游服务返回的是 401 或者 403 ,则将响应返回给客户端。
在 NGX_HTTP_ACCESS_PHASE 阶段生效,默认没有编译进 nginx ,需要通过 --with-http_auth_request_module 编译。
- auth_request
- 作用: 配置鉴权 uri ,或者关闭鉴权功能
- 基本语法:
auth_request ${uri} / off; - 默认值:
auth_request off; - 作用域:
http、server、location
- auth_request_set
- 作用: 在鉴权时设置变量值
- 基本语法:
auth_request_set ${variable} ${value}; - 默认值: 无
- 作用域:
http、server、location
satisfy 指令
access 阶段内,如果配置了多种鉴权方式,需要有一个汇总策略,决定是否放行,也就是 satisfy 指令。
- satisfy
- 作用: 配置 access 认证规则
- 基本语法:
satisfy all | any;all: 必须所有 access 阶段的模块同意放行,才能结束 access 阶段到下一阶段any: 只要有一个 access 阶段的模块同意放行,就结束 access 阶段到下一阶段
- 默认值:
satisfy all; - 作用域:
http、server、location
各个模块的执行顺序在 ngx_modules.c 文件中:
ngx_http_auth_request_modulengx_http_auth_basic_modulengx_http_access_module
location / {
# 只要一条匹配就放行
satisfy any;
# 等待鉴权,鉴权成功放行,否则不放行
authbasic "test authn_basic";
authbasic userfile examples/auth.pass;
# access 直接拒绝
deny all;
}location / {
# 只要一条匹配就放行
satisfy any;
# 不需要鉴权,直接放行,因为有模块已经放行了
authbasic "test authn_basic";
authbasic userfile examples/auth.pass;
# access 直接放行
allow all;
}precontent 阶段
ngx_http_try_files_module 模块
依次试图访问多个 url 对应的文件(由 root 或者 alias 指令指定)。
当文件存在时直接返回文件内容,如果所有文件都不存在,则按最后一个 URL 结果或者 code 返回
- try_files
- 作用: 配置鉴权 uri ,或者关闭鉴权功能
- 基本语法:
try_files ${uri1} [... ${uri N}]; - 默认值: 无
- 作用域:
server、location
server {
root html/;
default_type text/plain;
location /first {
# 先匹配维护模式展示的静态资源
try_files /system/maintenance.html
# 再匹配默认首页
$uri $uri/index.html $uri.html
# 最后走到内置的处理流程
@lasturl;
}
location @lasturl {
return 200 'lasturl!\n';
}
location /second {
# 如果都找不到文件,会返回最后一个 url 以及对应的状态码
# 也就是返回 /second.html ,状态码为 404
try_files $uri $uri/index.html $uri.html =404;
}
}ngx_http_mirror_module 模块
处理请求时,生成子请求访问其他服务,对子请求的返回值不做处理
- mirror
- 作用: nginx 接收到请求后,是否需要上报给指定请求
- 基本语法:
mirror ${uri} / off; - 默认值:
mirror off; - 作用域:
http、server、location
- mirror_request_body
- 作用: 上报时,是否携带请求 body
- 基本语法:
mirror_request_body on / off; - 默认值:
mirror_request_body on; - 作用域:
http、server、location
location / {
# 转发到用户日志接口,记录用户访问数据
mirror /log-access;
mirror_request_body off;
}
location = /log-access {
# 对请求头进行装饰,表明记录数据来源,转发给内网的记录服务
internal;
proxy_pass http://127.0.0.1:10020$request_uri;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}content 阶段
ngx_http_concat_module 模块
阿里开发的 小文件合并模块 ,可以在一次请求中将多个小文件合并成一个响应内容。
使用时,在 URI 后加上 ?? ,通过多个 , 分隔文件,如果还有参数则在末尾通过 ? 添加
例如: http://example.com/static/??foo.css,bar/foobaz.js
- concat
- 作用: 是否开启文件合并功能
- 基本语法:
concat on / off; - 默认值:
concat off; - 作用域:
http、server、location
- concat_types
- 作用: 指定允许合并的文件类型
- 基本语法:
concat_types ${MIME-type} ...; - 默认值:
concat_types text/css application/x-javascript; - 作用域:
http、server、location
- concat_unique
- 作用: 是否只允许合并相同类型的文件
- 基本语法:
concat_unique on / off; - 默认值:
concat_unique on; - 作用域:
http、server、location
- concat_max_files
- 作用: 设置一次请求中最多可以合并的文件数量
- 基本语法:
concat_max_files ${number}; - 默认值:
concat_max_files 10; - 作用域:
http、server、location
- concat_delimiter
- 作用: 设置合并文件之间的分隔符
- 基本语法:
concat_delimiter ${string}; - 默认值:
NONE - 作用域:
http、server、location
- concat_ignore_file_error
- 作用: 是否忽略文件不存在的错误
- 基本语法:
concat_ignore_file_error on / off; - 默认值:
concat_ignore_file_error off; - 作用域:
http、server、location
ngx_http_index_module 模块
指定访问时返回 index 文件内容
- index
- 作用: 配置默认首页文件
- 基本语法:
index ${file 1} [... ${file N}]; - 默认值:
index index.html; - 作用域:
http、server、location
ngx_http_autoindex_module 模块
当 URL 以 / 结尾,并且没有对应的默认首页时,尝试以 html 、 xml 、 json 、 jsonp 等格式返回目录的目录结构
- autoindex
- 作用: 是否开启 autoindex 功能,自动为目录资源生成对应的展示内容
- 基本语法:
autoindex on / off; - 默认值:
autoindex off; - 作用域:
http、server、location
- autoindex_extra_size
- 作用: 是否显示格式化后的文件大小
- 基本语法:
autoindex_extra_size on / off; - 默认值:
autoindex_extra_size on; - 作用域:
http、server、location
- autoindex_format
- 作用: 默认返回的 autoindex 静态资源格式
- 基本语法:
autoindex_format html / xml / json / jsonp; - 默认值:
autoindex_format html; - 作用域:
http、server、location
- autoindex_localtime
- 作用: 静态资源内的时间使用本地时间还是 UTC 时间
- 基本语法:
autoindex_localtime on / off; - 默认值:
autoindex_localtime off; - 作用域:
http、server、location
static 模块
处理静态资源请求,将 uri 映射到本地的文件路径,读取对应的文件作为 uri 响应结果。
- alias
- 作用: 去掉 location 匹配的部分,剩下的部分映射到文件路径中
- 基本语法:
alias ${path}; - 默认值: 无
- 作用域:
location
- root
- 作用: 映射完整的 uri 到文件路径中
- 基本语法:
root ${path}; - 默认值:
root html; - 作用域:
http、server、location、location内的if
- types
- 作用: 配置响应的
Content-Type与文件扩展名的映射 - 基本语法:
types { ${mine-type} ${extension}; }; - 默认值:
types { text/html html; image/gif gif; image/jpeg jpg }; - 作用域:
http、server、location
- 作用: 配置响应的
- default_type
- 作用: 文件扩展名不匹配时,返回的默认的 Content-Type
- 基本语法:
default_type ${mine-type}; - 默认值:
default_type text/plain; - 作用域:
http、server、location
- types_hash_bucket_size
- 作用: 配置存储 types 的哈希表每个元素的大小
- 基本语法:
types_hash_bucket_size ${size}; - 默认值:
types_hash_bucket_size 64; - 作用域:
http、server、location
- types_hash_max_size
- 作用: 设置存储 MIME 类型哈希表的最大容量。
- 基本语法:
types_hash_max_size ${size}; - 默认值:
types_hash_max_size 1024; - 作用域:
http、server、location
- log_not_fount
- 作用: 找不到文件时,是否输出日志。
- 基本语法:
log_not_fount on / off; - 默认值:
log_not_fount on; - 作用域:
http、server、location
- absolute_redirect
- 作用: 控制重定向时是否使用绝对路径(包含协议、主机名和端口),在访问目录,并且没有以
/结尾时, Nginx 会自动触发一个 301 重定向 - 基本语法:
absolute_redirect on / off; - 默认值:
absolute_redirect on; - 作用域:
http、server、location
- 作用: 控制重定向时是否使用绝对路径(包含协议、主机名和端口),在访问目录,并且没有以
- server_name_in_redirect
- 作用: 控制重定向时是否使用 server_name 指令指定的第一个域名作为重定向地址,未开启时,使用请求头的 Host 字段。
- 基本语法:
server_name_in_redirect on / off; - 默认值:
server_name_in_redirect off; - 作用域:
http、server、location
- port_in_redirect
- 作用: 控制重定向时是否在重定向地址中包含端口号
- 基本语法:
port_in_redirect on / off; - 默认值:
port_in_redirect on; - 作用域:
http、server、location
static 模块还会提供以下变量:
request_filename: 待访问文件的完整路径document_root: 由 uri 和 root/alias 规则生成的目录地址realpath_root: 将 document_root 映射出真实地址,会解析软连接等。
log 阶段
ngx_http_log_module 模块
将 http 请求相关信息记录到日志中。
- log_format
- 作用: 定义日志文件格式
- 基本语法:
log_format ${name} [escape=default / json / none] ${string}; - 默认值:
log_format combined "...";,默认值太长了,直接看 Nginx 配置文件吧 - 作用域:
http
- access_log
- 作用: 定义日志文件存储位置,如果没有配置日志格式名,默认使用默认格式,也就是
combined - 基本语法:
access_log ${path} [${format} [buffer=${size}] [gzip[=${level}]] [flush=${time}] [if=${condition}]];gzip: 是否开启 gzip 压缩,以及压缩级别,默认为 1buffer: 内存缓冲区的大小,缓冲区满会将日志数据一次性写入磁盘文件, buffer 默认为 64KBflush: 内存缓冲区定时写入磁盘的时间间隔,到达指定时间间隔也会把缓冲区内容写入磁盘if: 满足条件才记录日志
access_log off;
- 默认值:
access_log logs/access.log combined; - 作用域:
http、server、location、location中的if、limit_except
- 作用: 定义日志文件存储位置,如果没有配置日志格式名,默认使用默认格式,也就是
- open_log_file_cache
- 作用: 配置日志写入功能
- 基本语法:
open_log_file_cache max=${number} [inactive=time] [min_uses=${number}] [valid=${time}];max: 缓存内的最大文件句柄数,超出后进行 LRU 淘汰inactive: 写入日志文化后,保持多久暂不关闭文件句柄,默认 10 秒。min_uses: 在inactive时间内,使用次数超过min_uses次的,继续持有文件句柄,不关闭文件,默认 1。valid: 超出valid事件后,对缓存的日志文件检查是否存在,默认 60 秒。off: 关闭缓存功能。
- 默认值:
open_log_file_cache off; - 作用域:
http、server、location
其他模块
ngx_http_core_module 模块
http 核心模块,处理 http 协议的基础配置和功能
resolver
- 作用: resolver 用于指定 Nginx 进行域名解析时使用的 DNS 服务器地址。当配置上游服务器为域名时,将使用 resolver 配置的 DNS 解析。
- 基本语法:
resolver ${address} ... [valid=${time}] [ipv6=on/off];${address}: 指定域名解析的 DNS ,支持配置多个 DNS 服务器valid=${time}: 指定 DNS 结果需要缓存多长时间
- 默认值: 无
- 作用域:
http、server、location
resolver_timeout
- 作用: 设置 DNS 解析的超时时间。
- 基本语法:
resolver_timeout ${timeout}; - 默认值:
resolver_timeout 30s; - 作用域:
http、server、location
keepalive_requests
- 作用: 在一个连接中最多跑多少个请求,超出请求数后自动关闭连接
- 基本语法:
keepalive_requests ${number}; - 默认值:
keepalive_requests 100; - 作用域:
upstream
keepalive_timeout
- 作用: 配置长连接在空闲多长时间自动关闭
- 基本语法:
keepalive_timeout ${timeout}; - 默认值:
keepalive_timeout 75s; - 作用域:
upstream
HTTP 过滤模块

ngx_http_sub_filter_module 模块
将响应中指定的字符串,替换为新的字符串
- sub_filter
- 作用: 声明需要将什么字符串替换为什么,替换时忽略大小写
- 基本语法:
sub_filter ${string} ${replacement}; - 默认值: 无
- 作用域:
http、server、location
- sub_filter_last_modified
- 作用: 替换后是否保留 Last-Modified 配置,由于文件已经被修改,默认不会返回 Last-Modified
- 基本语法:
sub_filter_last_modified on / off; - 默认值:
sub_filter_last_modified off; - 作用域:
http、server、location
- sub_filter_once
- 作用: 是否只需要替换一次
- 基本语法:
sub_filter_once on / off; - 默认值:
sub_filter_once on; - 作用域:
http、server、location
- sub_filter_types
- 作用: 针对哪些 Mime-type 进行替换
- 基本语法:
sub_filter_types ${Mime-type} ...;,支持使用sub_filter_types *;进行全量匹配 - 默认值:
sub_filter_types text/html; - 作用域:
http、server、location
ngx_http_addition_filter_module 模块
在响应前或响应后,发起一个子请求,获取需要添加的新内容。
- add_before_body
- 作用: 需要在 response body 前插入什么内容
- 基本语法:
add_before_body ${uri}; - 默认值: 无
- 作用域:
http、server、location
- add_after_body
- 作用: 需要在 response body 后插入什么内容
- 基本语法:
add_after_body ${uri}; - 默认值: 无
- 作用域:
http、server、location
- addition_types
- 作用: 添加文件的 Mime 类型
- 基本语法:
addition_types ${Mime-type} ...; - 默认值:
addition_types text/html; - 作用域:
http、server、location
ngx_http_referer_module 模块
浏览器会自动发送 Referer 字段,告知服务端目前客户访问的是哪个 url , ngx_http_referer_module 模块可以拒绝不合法的网站访问系统资源,也就是防盗链。
模块提供了 invalid_referer 变量,允许访问时变量值为空,否则为 1 。
- valid_referers
- 作用: 哪些 Referer 是合法的
- 基本语法:
valid_referers none / blocked / server_names / ${string} ...;none: 不带 Refererblocked: Referer 缺少对应值server_names: 域名与本机配置的任意 server_name 匹配,就允许访问${string}: 自定义 Referer ,支持字符串、正则、*.he110.site、he110.site/*等
- 默认值: 无
- 作用域:
server、location
- referer_hash_bucket_size
- 作用: 记录 Referer 的哈希表块大小
- 基本语法:
referer_hash_bucket_size ${size}; - 默认值:
referer_hash_bucket_size 64; - 作用域:
server、location
- referer_hash_max_size
- 作用: 记录 Referer 的哈希表最大容量
- 基本语法:
referer_hash_max_size ${size}; - 默认值:
referer_hash_max_size 2048; - 作用域:
server、location
ngx_http_secure_link_module 模块
Referer 可以在手动发出请求时在客户端修改,所以依据 Referer 进行防盗链并不可靠, Nginx 提供了 secure_link 模块,能够完成更加可靠的防盗链功能。
secure_link 工作过程为: 服务器或 Nginx 生成加密后的安全链接 url ,返回给客户端。客户端使用安全链接 url 访问 Nginx , Nginx 用 secure_link 变量判断是否验证通过。
secure_link 会将 URI 、 用户信息(比如源 IP ) 、 时间戳 、 密钥等信息,进行 Hash 计算,获得一个安全的 URL ,该 URL 对应的原始内容仅加密服务器以及 Nginx 持有,通过解密可以验证访客身份是否匹配,如果不匹配则拒绝访问。
secure_link
- 作用: 配置从哪些参数中取得 Hash 值与过期时间
- 基本语法:
secure_link ${hash},${expires}; - 默认值: 无
- 作用域:
http、server、location
secure_link_md5
- 作用: 定义生成哈希值的规则,一般包含时间戳和密钥
- 基本语法:
secure_link_md5 "${加密的参数}"; - 默认值: 无
- 作用域:
http、server、location
secure_link_secret
- 作用: 简单的安全链接生成,无法进行过期判断
- 基本语法:
secure_link_secret ${secret_key}; - 默认值: 无
- 作用域:
location
$secure_link: 记录 secure_link 校验结果"": 验证不通过0: URL 过期1: 通过
$secure_link_expires: 哈希中记录的时间戳的值
ngx_http_map_module 模块
基于已有变量,映射出新的变量,类似于 switch 语句
- map
- 作用: 定义变量的映射规则,将
${string}映射成$variable变量 - 基本语法:
map ${string} ${$variable} { }; - 默认值: 无
- 作用域:
http
- 作用: 定义变量的映射规则,将
- map_hash_bucket_size
- 作用: 记录 Map 的哈希表块大小
- 基本语法:
map_hash_bucket_size ${size}; - 默认值:
map_hash_bucket_size 32|64|128; - 作用域:
http
- map_hash_max_size
- 作用: 记录 Map 的哈希表最大容量
- 基本语法:
map_hash_max_size ${size}; - 默认值:
map_hash_max_size 2048; - 作用域:
http
map $http_host $name {
hostnames;
# 类似 case 中的 default 语句
default 0;
# $http_host 变量匹配了左边的表达式,就设置 $name 为右边的值
# 匹配规则可以参考 server_name 的匹配顺序
~map\.test\w+\.org.cn 1;
*.example.org.cn 2;
map.example.tech 3;
map.example.* 4;
}
map $http_user_agent $mobile {
default 0;
"~Opera Mini" 1;
}ngx_http_split_clients_module 模块
与 map 一样,可以基于已有变量创建新变量,主要用于分流功能,也就是 AB 测试、灰度上线。
具体行为是根据已有的字符串、变量、变量 + 字符串,基于 MurmurHash2 算法,生成一个 32 位整型的 Hash 数字。按照 32 位整型最大值为 2 ^ 32 - 1 ,求 Hash 除以最大值,所得的百分比值。
在 case 规则中,声明不同的百分比值范围,根据上述规则计算出来的百分比值落在哪个区间,就将新变量设置为对应的参数,而 * 意味着匹配剩余所有范围,也就是 default 。
- split_clients
- 作用: 将用户进行分流,主要用于 AB 测试、灰度体验等,所有百分比值之和不能超过 100%
- 基本语法:
split ${string} ${$variable} { }; - 默认值: 无
- 作用域:
http
# 按照请求头的 username 参数进行 Hash 计算
split_clients "${http_username}" $variant {
# 统计区间 [0, 0.5%]
0.5% A;
# 统计区间 [0.5%, 1%]
0.5% B;
# 统计区间 [1%, 10%]
9% C;
# 统计区间 [10%, 30%]
20% D;
# 统计区间 [30%, 100%]
* E;
}ngx_http_geo_module 模块
geo 模块需要基于客户端的 IP 地址与端口,计算出新变量
- geo
- 作用: 使用 IP + 掩码确定 IP 范围,基于不同的 IP 范围使用不同的变量。
- 基本语法:
geo: [${address}] $variable {}${address}: 如果省略了,默认使用 realip 模块提供的$remote_addr作为 IP 地址。如果网段重叠了,按照最长匹配选择网段。
- 默认值: 无
- 作用域:
http
geo $country {
# 配置默认值
default CN;
# 在 remote_addr 中跳过可信地址
# 指定可信地址。
proxy 1.1.1.1;
# 开启递归查找。此时 remote_addr 在解析 X-Forwarded-For 时会跳过可信地址
proxy_recursive on;
127.0.0.0/24 US;
127.0.0.1/32 RU;
10.0.0.1/32 RU;
192.168.0.1/32 UK;
}ngx_http_geoip_module 模块
基于 MaxMind 数据库,将客户端 IP 地址映射到具体的地理位置,需要先 安装 MaxMind
geoip_contry
- 作用: 配置 MaxMind 国家数据库文件地址
- 基本语法:
geoip_contry: ${file} - 默认值: 无
- 作用域:
http
geoip_proxy
- 作用: 提供可信地址
- 基本语法:
geoip_proxy: ${address} / ${CIDR} - 默认值: 无
- 作用域:
http
geoip_city
- 作用: 配置 MaxMind 城市数据库文件地址
- 基本语法:
geoip_city: ${file} - 默认值: 无
- 作用域:
http
$geoip_contry_code: 两位字母的国家代码,比如 CN 、 US 等。$geoip_contry_code3: 三位字母的国家代码,比如 CHN 、 USA 等。$geoip_contry_name: 国家名称,比如 “China” 、 “United States” 等。
geoip_city 除了上面三个变量之外,还支持:
$geoip_latitude: 纬度$geoip_longitude: 经度$geoip_city_continent_code: 属于哪个州,比如 AS 、 RU$geoip_region: 州或者省的编码$geoip_region_name: 州或者省的名称,比如 Zhejiang$geoip_city: 城市名$geoip_portal_code: 邮编号码$geoip_area_code: 仅美国使用的电话区号$geoip_dma_code: 仅美国使用的 DMA 编号
Nginx 变量
模块变量
在 preconfiguration 中,模块会定义模块变量,提供给自身或者其他模块使用。
本质上来说,定义的模块变量只是一套获取变量值的规则,当请求到来时,根据规则解析出变量值,再传递给各个模块。
由此衍生出变量的几个特性:
- 惰性求值: 变量本身只是一套获取数据的规则,在变量没有被使用时,不会求值。
- 时刻变化: 在一个请求处理过程中,每个使用的模块都会按照获取变量值的方式去获取值,所以该值随时可能变化。
为了提升性能, Nginx 提供了缓存变量值的 Hash 表:
variables_hash_bucket_size ${size};: 配置变量缓存哈希表的每个值的大小,默认为 64 字节,只能用于http模块。variables_hash_max_size ${size};: 配置变量缓存哈希表的容量,默认为 1024 ,只能用于http模块。
http 框架提供的变量
HTTP 请求相关的变量
arg_参数名: URL中某个具体参数的值args: 全部 URL 参数,也就是 query 不分query_string: 与 args 变量完全相同is_args: 如果请求 URL 中有参数则返回,否则返回空content_length: HTTP 请求中标识包体长度的 Content-Length 头部的值content_type: 标识请求包体类型的 Content-Type 头部的值uri: 请求的 URI ( 不同于 URL ,不包括?后的参数 )document_uri: 与 uri 完全相同request_uri: 请求的 URL ( 包括 URI 以及完整的参数 )scheme: 协议名,例如 HTTP 或者 HTTPSrequest_method: 请求方法,例如 GET 或者 POSTrequest_length: 所有请求内容的大小,包括请求行、头部、包体等remote_user: 由 HTTP Basic Authentication 协议传入的用户名request_body_file: 临时存放请求包体的文件。 如果包体非常小则不会存文件,配置client_body_in_file_only强制所有包体存入文件,且可决定是否删除。request_body: 请求中的包体,这个变量当且仅当使用反向代理,且设定用内存暂存包体时才有效request: 原始的 url 请求,含有方法与协议版本,例如GET /?a=1&b=22 HTTP/1.1Host:- 从请求行中获取
- 如果含有 Host 请求头,使用请求头的值替代请求行的值
- 如果都没有值,使用匹配的 server_name
http_${header}: 获取具体的请求头的值,以下请求头例外,会被 Nginx 额外处理,非原始值:http_hosthttp_user_agenthttp_refererhttp_viahttp_x_forwarded_forhttp_cookie
TCP 连接相关的变量
binary_remote_addr: 客户端地址的整型格式,对于 IPv4 是 4 字节,对于 IPv6 是 16 字节connection: 递增的连接序号connection_requests: 当前连接上执行过的请求数,对 keepalive 连接有意义remote_addr: 客户端地址,字符串格式remote_port: 客户端端口proxy_protocol_addr: 若使用了 proxy_protocol 协议则返回协议中的地址,否则返回空proxy_protocol_port: 若使用了 proxy_protocol 协议则返回协议中的端口,否则返回空server_addr: 服务器端地址server_port: 服务器端端口TCP_INFO: tcp 内核层参数,包括$tcpinfo_rtt,$tcpinfo_rttvar,$tcpinfo_snd_cwnd,$tcpinfo_rcv_spaceserver_protocol: 服务器端协议,例如 HTTP/1.1
Nginx 处理请求过程中产生的变量
request_time: 请求处理到现在的耗时,单位为秒,可以利用小数点,精确到毫秒server_name: 匹配上请求的 server_name 值https: 如果开启了 TLS/SSL ,则返回 on ,否则返回空request_completion: 若请求处理完则返回 OK ,否则返回空request_id: 以 16 进制输出的请求标识 id ,该 id 共含有 16 个字节,是随机生成的request_filename: 待访问文件的完整路径document_root: 由 URI 和root/alias规则生成的文件夹路径realpath_root: 将document_root中的软链接等换成真实路径limit_rate: 返回客户端响应时的速度上限,单位为每秒字节数。可以通过set指令修改对请求产生效果
发送 HTTP 响应相关的变量
body_bytes_sent: 响应中 body 包体的长度特殊处理bytes_sent: 全部 http 响应的长度,包含 headerstatus: http 响应中的返回码sent_trailer_${name}: 把响应结尾内容里值返回sent_http_${header}: 响应中某个具体头部的值,以下字段被特殊处理过sent_http_content_typesent_http_content_lengthsent_http_locationsent_http_last_modifiedsent_http_connectionsent_http_keep_alivesent_http_transfer_encodingsent_http_cache_controlsent_http_link
Nginx 系统变量
time_local: 以本地时间标准输出的当前时间,例如 18/Apr/2025:17:26:31+0800time_iso8601: 使用 ISO8601 标准输出的当前时间,例如 2025-04-18T17:26:31+08:00nginx_version: Nginx 版本号pid: 所属 worker 进程的进程 idpipe: 使用了管道则返回p,否则返回.hostname: 所在服务器的主机名,与 hostname 命令输出一致msec: 1970 年 1 月 1 日到现在的时间,单位为秒,小数点后精确到毫秒
负载均衡
由于对于可靠性的要求,往往需要额外冗余一部分提供相同服务的服务器,可以保证在设备升级、维护、扩容等情况下依旧不需要停机。
Nginx 作为应用网关程序,也内置了负载均衡需要的各种能力:
- 水平扩容: 即增加冗余服务器,减轻各个服务器的压力,一般基于
Round-Robin或者least-connected等算法进行请求的分发。- 用途: 一般在业务扩张的初期阶段,通过增加服务器成本快速解决问题,满足业务需要
- 优点: 操作简单,初期能有不错的效果
- 缺点: 当数据量上来了,单个操作的时间需要大量耗时后,单台服务器难以及时处理完成该请求
- 垂直扩展: 即将服务按照功能,拆分到不同的服务器或者集群上,一般基于 URL 进行识别处理即可,类似于 FaaS 或者 Serverless
- 用途: 一般在业务较为稳定阶段,作为架构优化的时候进行的保障性能的解决方案
- 优点: 可以应对大数据量下的并发操作
- 缺点: 函数拆分与调用较为复杂,底层还涉及到数据库的分库分表设计
- Z 轴扩展: 即将访问的用户按照 IP 地址或者其他指纹信息,映射到某个特定的服务或者集群
- 用途: 将用户按照指纹划分群体,一般用于数据隔离场景,比如国内外隔离、内测版本等
- 优点: 操作难度适中,能缓解服务器压力与数据压力
- 缺点: 更像是妥协方案,数据不可能永远隔离着
以上三种方式往往组合使用,并不会单纯应用某一技术,例如: 通过用户群切分( z 轴扩展)转发到不同的集群(水平扩展),将通用的,数据量大的模块单独拆分为 FaaS (垂直扩展), FaaS 内部还是一个集群(水平扩展)
负载均衡依靠的就是反向代理技术, Nginx 支持 七层反向代理 与 四层反向代理 ,可以按照业务需求选择。
upstream
提供了 Round-Robin 算法
- upstream
- 作用: 配置一组上游服务器
- 基本语法:
upstream ${name} {} - 默认值: 无
- 作用域:
http
- server
- 作用: 指定 upstream 包含哪些地址
- 基本语法:
server ${address} [${paramters}]${address}: 包含域名、 IP 、 unix socket 等。 域名 、 IP 如果不加端口,默认使用 80 端口。${paramters}:backup: 指定当前 server 为备份服务,仅当非备份 server 不可用时,才会转发给该 serverdown: 标记该服务已经下线,不再服务
- 默认值: 无
- 作用域:
upstrea,
上游服务器长连接
可以使用 ngx_http_upstream_keepalive_module 模块,完成对上游服务的长连接配置,在处理大量请求时,会有比较明显的性能提升。
一般会先通过以下配置,预先准备好开启长连接的条件:
# http 1.1 开始才支持长连接,所以指定要求使用 1.1
proxy_http_version 1.1;
# 手动指定一定要长连接,避免客户端发来的请求没有指定长连接
proxy_set_header Connection "";- keepalive
- 作用: 最多保持多少个空闲长连接
- 基本语法:
keepalive ${connections}; - 默认值: 无
- 作用域:
upstream
- keepalive_requests
- 作用: 在一个连接中最多跑多少个请求,超出请求数后自动关闭连接
- 基本语法:
keepalive_requests ${number}; - 默认值:
keepalive_requests 100; - 作用域:
upstream
- keepalive_timeout
- 作用: 配置长连接在空闲多长时间自动关闭
- 基本语法:
keepalive_timeout ${timeout}; - 默认值:
keepalive_timeout 60s; - 作用域:
upstream
加权 Round-Robin 算法
使用加权轮询的方式访问 server 指令指定的上游服务,简单理解就是所有权重加起来作为一个周期,权重即为该服务在这个周期内需要处理多少个请求。
一般其他算法在失效之后,也会转为 加权 Round-Robin 算法。
该算法默认集成在 Nginx 的 upstream 中,不可移除或者更改,提供了以下指令:
weight: 服务访问的权重,默认为 1max_conns: server 的最大并发连接数,仅作用于单 worker 进程。默认是 0 ,表示没有限制。fail_timeout: 单位为秒,默认值为 10 秒。具有 2 个功能:- 指定记录 faile 的时间窗口。
- 将 server 标记为 fail 后,将 server 断开多久的时间
max_fails: 在fail_timeout时间段内,最大的失败次数。当达到最大失败时,会在fail_timeout秒内这台 server 不允许再次被选择。
Hash 算法
IP Hash 算法
该算法位于 ngx_http_upstream_ip_hash_module
使用客户端 IP 地址作为 Hash 算法的参数,将不同的 IP 地址映射给不同的上游服务器处理,此时 server 配置的权重会失效,不再按照权重轮询。
如果对应的上游服务已经挂起,依旧会转发给该服务,因为选择的唯一标准就是 Hash 值。
如果移除该服务,则会导致 Hash 算法变更,导致用户访问了新的服务,随之而来的就是大量的缓存失效,上游服务可能直接被击穿。
所以相对应的,需要水平扩容时,也会导致 Hash 算法修改,导致用户访问了新的服务,随之而来的就是大量的缓存失效,上游服务可能直接被击穿。
对于 IPv4 地址使用前 3 个字节作为关键字,对 IPv6 则使用完整地址。
可以基于 realip 修改 Hash 算法的参数,因为 Hash 算法的地址取的事 realip 提供的变量。
- ip_hash
- 作用: 开启 IP Hash 算法
- 基本语法:
ip_hash; - 默认值: 无
- 作用域:
upstream
upstream Hash 算法
该算法位于 ngx_http_upstream_hash_module
参考 IP Hash 算法,但是参数不局限在 IP 地址,可以使用任意变量、字符串作为 Hash 参数
- hash
- 作用: 开启 Hash 算法,并配置其参数(
${key}) - 基本语法:
hash ${key} [consistent];consistent: 开启一致性 Hash 算法
- 默认值: 无
- 作用域:
upstream
- 作用: 开启 Hash 算法,并配置其参数(
一致性 Hash 算法
一致性 Hash 算法可以缓解前面提到的水平扩容导致的 Hash 算法变更,随之而来的用户访问服务器变化问题。
一致性 Hash 算法将 Hash 后的值域,设置的比较大,比如 [0, 2 ^ 32] 这个区间,用户参数 Hash 后将落到这个区间内,同时对上游服务,也进行 Hash 。
在用户 Hash 与服务 Hash 不匹配时,会沿着区间往数据增大的方向查找,找到的第一个服务,就为这个用户提供服务。
当查找越过区间最大值,也就是 2 ^ 32 时,重新从 0 开始,构成一个循环区间。
当某台服务器挂起时,只有该服务器上的用户被影响,缓存失效,所有用户会移交给下一个服务器,所以单点服务器的负载不能太高,否则可能单点被击穿。
当扩容时,可以很方便的进行扩容,新的用户会在区间查找时,自动索引到新的服务器上。
最少连接算法
该算法位于 ngx_http_upstream_least_conn_module
会从所有上游服务器中,找出当前并发连接数最少的一台服务器,将请求转发给它。
如果找到了多台服务器,按照 加权 Round-Robin 算法处理。
- least_conn
- 作用: 开启最少连接算法
- 基本语法:
least_conn; - 默认值: 无
- 作用域:
upstream
使用共享内存共享负载均衡相关信息
以上介绍的算法,均只对单个 worker 生效,默认负载均衡策略没有写入共享内存中。
需要使用 ngx_http_upstream_zone_module 提供的 zone 指令,才能将信息放到共享内存中,对所有 worker 进程生效。
- zone
- 作用: 分配出共享内存,将其他 upstream 模块定义的负载均衡策略数据、运行时每个上游服务的状态数据存放到共享内存中,让所有 Nginx worker 共享。
- 基本语法:
least_conn ${name} [${size}]; - 默认值: 无
- 作用域:
upstream
upstream 中各个模块的执行顺序
- ngx_http_upstream_hash_module
- ngx_http_upstream_ip_hash_module
- ngx_http_upstream_least_conn_module
- ngx_http_upstream_random_module
- ngx_http_upstream_keepalive_module
- ngx_http_upstream_zone_module
upstream 提供的变量
upstream_addr: 上游服务器的IP地址,格式为可读的字符串,例如 127.0.0.1:8012 upstream_connect_time: 与上游服务建立连接消耗的时间,单位为秒,精确到毫秒 upstream_header_time: 接收上游服务发回响应中 http 头部所消耗的时间,单位为秒,精确到毫秒 upstream_response_time: 接收完整的上游服务响应所消耗的时间,单位为秒,精确到毫秒 upstream_http_${name}: 从上游服务返回的响应头部的值
反向代理
反向代理模块相关功能都在 ngx_http_proxy_module 模块中,整个反向代理的流程如下图:

content 阶段
指定哪些内容需要被反向代理
- proxy_pass
- 作用: 开启反向代理
- 基本语法:
proxy_pass ${url}; - 默认值: 无
- 作用域:
location、location中的if、limit_except
${url} 需要满足以下条件:
- 必须以
http:///https://开头 - 协议之后跟 域名 、 IP 、 unix socket 、 upstream name 等,域名与 IP 后可以接端口,如果省略默认为
80 - 最后是可选的 uri ,也就是浏览器地址中的 path 以及之后的部分,可以通过携带 uri 将 Nginx 参数传递给上游服务,比如 request id 等。
- 如果不携带 uri ,请求中的 URL 会直接发给上游服务,一般在 location 采用正则、
@${name}时使用 - 如果携带 uri ,请求中的 URL 匹配的部分,会被替换为 uri
- 如果不携带 uri ,请求中的 URL 会直接发给上游服务,一般在 location 采用正则、
生成 http 头与包体阶段
修改请求行,可以使用以下命令:
- proxy_method
- 作用: 修改请求的方法
- 基本语法:
proxy_method ${method}; - 默认值: 无
- 作用域:
http、server、location
- proxy_http_version
- 作用: 指定 http 版本号,不支持将
http2/http3代理到上游服务器中。 - 基本语法:
proxy_http_version 1.0 / 1.1; - 默认值: 无
- 作用域:
http、server、location
- 作用: 指定 http 版本号,不支持将
修改请求头,可以使用以下命令:
- proxy_set_header
- 作用: 设置请求头,将会覆盖用户发来的请求头信息
- 基本语法:
proxy_set_header ${filed} ${value}; - 默认值: 默认会修改 Host 与 Connection ,默认会更正 Host 的值,同时关闭 keepalive
proxy_set_header Host $proxy_host;: 如果$proxy_host值为空,该命令不会添加,还是保留请求头中的 Hostproxy_set_header Connection close;
- 作用域:
http、server、location
- proxy_pass_request_headers
- 作用: 是否要将用户发来的请求头发送给上游服务
- 基本语法:
proxy_pass_request_headers on / off; - 默认值:
proxy_pass_request_headers on; - 作用域:
http、server、location
修改请求包体,可以使用以下命令:
- proxy_set_body
- 作用: 设置请求包体值,将会覆盖用户发来的请求头信息
- 基本语法:
proxy_set_body ${value}; - 默认值: 无
- 作用域:
http、server、location
- proxy_pass_request_body
- 作用: 是否要将用户发来的请求包体发送给上游服务
- 基本语法:
proxy_pass_request_body on / off; - 默认值:
proxy_pass_request_body on; - 作用域:
http、server、location
读取请求包体阶段
请求包体读取有两种方式:
通过流式传输,边读边给上游服务发
一次性读入,再传递给上游服务
proxy_request_buffering
- 作用: 是否要接收完用户发来的请求包体,再传递给上游服务
- 基本语法:
proxy_request_buffering on / off;on: 用户网速较慢、上游处理并发能力较差、高吞吐量场景下建议开启off: 需要及时响应、降低 Nginx 磁盘 I/O 则关闭该功能,同时关闭后对proxy_next_upstream指令会有影响
- 默认值:
proxy_request_buffering on; - 作用域:
http、server、location
读取包体相关配置
- client_body_buffer_size
- 作用: 分配接收包体的 buffer 块大小
- 基本语法:
client_body_buffer_size ${size};- 如果处理请求头的时候已经接收完包体了,就不需要额外分配
- 如果剩余包体长度小于 client_body_buffer_size ,需要多少分配多少
- 如果超出,以 client_body_buffer_size 为单位,创建不同的 buffer 块读取包体
- 默认值:
client_body_buffer_size 8k|16k; - 作用域:
http、server、location
- client_body_in_single_buffer
- 作用: 是否将所有 body 都塞到一个缓冲区中,需要考虑包体体积,开启后才能使用
$request_body变量 - 基本语法:
client_body_in_single_buffer on / off; - 默认值:
client_body_in_single_buffer off; - 作用域:
http、server、location
- 作用: 是否将所有 body 都塞到一个缓冲区中,需要考虑包体体积,开启后才能使用
- client_max_body_size
- 作用: 限制包体的最大长度,通过
Content-Length字段校验,校验失败返回 413 状态码 - 基本语法:
client_max_body_size ${size}; - 默认值:
client_max_body_size 1m; - 作用域:
http、server、location
- 作用: 限制包体的最大长度,通过
读取包体后,会通过 I/O 缓存到磁盘,在后续需要时再从磁盘上读,缓存的文件就是临时文件,通过以下命令控制:
- client_body_temp_path
- 作用: 配置临时文件路径,通过 level 将文件 Hash 按位分割,存放到不同子目录中。由于 Linux 文件名都放到目录中记录,所以在一个目录中放大量文件会影响读写性能。
- 基本语法:
client_body_temp_path ${path} [level1 [level2 [level3]]]; - 默认值:
client_body_temp_path client_body_temp; - 作用域:
http、server、location
- client_body_in_file_only
- 作用: 包体是否必须放到文件中
- 基本语法:
client_body_in_file_only on | clean | off;on: 必须写入文件,在处理完成后不删除clean: 必须写入文件,在处理完成后自动删除off: 在内存操作即可,不需要写入文件
- 默认值:
client_body_in_file_only off; - 作用域:
http、server、location
- client_body_timeout
- 作用: 配置读取包体的最长时间。如果一个包体在指定时间内都读取不完,返回 408 超时错误
- 基本语法:
client_body_timeout ${time}; - 默认值:
client_body_timeout 60s; - 作用域:
http、server、location
与上游服务建立连接
- proxy_connect_timeout
- 用法: 与上游服务器建立连接的超时时间,只要连接建立超时,都是返回 502 错误码
- 基本语法:
proxy_connect_timeout ${time}; - 默认值:
proxy_connect_timeout 60s; - 作用域:
http、server、location
- proxy_next_upstream
- 用法: 在与上游服务器建立连接失败后,更换上游服务器
- 基本语法:
proxy_next_upstream ${http_502} | ..; - 默认值:
proxy_next_upstream error timeout; - 作用域:
http、server、location
- proxy_socket_keepalive
- 用法: 是否开启 TCP keepalive ,通过探测包机制,在空闲时与上游服务通信探活,在上游服务关闭或者挂起时自动关闭连接
- 基本语法:
proxy_socket_keepalive on | off; - 默认值:
proxy_socket_keepalive off; - 作用域:
http、server、location
- keepalive
- 作用: 最多保持多少个空闲长连接
- 基本语法:
keepalive ${connections}; - 默认值: 无
- 作用域:
upstream
- keepalive_requests
- 作用: 在一个连接中最多跑多少个请求,超出请求数后自动关闭连接
- 基本语法:
keepalive_requests ${number}; - 默认值:
keepalive_requests 100; - 作用域:
upstream
- proxy_bind
- 作用: 修改 TCP 连接中,包中的源 IP
- 有多个 IP 时,指定通信使用的 IP 地址,避免使用网络隔离的 IP 导致通信异常,例如:
proxy_bind $remote_addr; - 使用非本机地址时需要添加 transparent ,例如:
proxy_bind $remote_addr transparent;
- 有多个 IP 时,指定通信使用的 IP 地址,避免使用网络隔离的 IP 导致通信异常,例如:
- 基本语法:
proxy_bind ${address} [transparent] | off; - 默认值: 无
- 作用域:
http、server、location
- 作用: 修改 TCP 连接中,包中的源 IP
- proxy_ignore_client_abort
- 用法: 在客户端 abort 请求后,是否不同步给上游服务,默认关闭,也就是同步
- 基本语法:
proxy_ignore_client_abort on | off; - 默认值:
proxy_ignore_client_abort off; - 作用域:
http、server、location
- proxy_send_timeout
- 用法: 向上游服务器发送请求时的超时时间
- 基本语法:
proxy_send_timeout ${time}; - 默认值:
proxy_send_timeout 60s; - 作用域:
http、server、location
接收上游服务响应
接收上游的响应头
- proxy_buffer_size
- 作用: 限制了接收响应头的最大值
- 基本语法: proxy_buffer_size ${size};
- 默认值: proxy_buffer_size 4k|8k;
- 作用域: http, server, location
接收上游的响应包体
proxy_buffers
- 作用: 内存中能够存储的 body 大小,超出大小后会写入磁盘中
- 基本语法:
proxy_buffers ${number} ${size}; - 默认值:
proxy_buffers 8 4k|8k; - 作用域:
http、server、location
proxy_buffering
- 作用: 是否要接收完成上游发来的请求包体,再返回给客户端
- 基本语法:
proxy_buffering on | off; - 默认值:
proxy_buffering on; - 作用域:
http、server、location
proxy_max_temp_file_size
- 作用: 限制写入文件的最大值,会限制响应包体积
- 基本语法:
proxy_max_temp_file_size ${size}; - 默认值:
proxy_max_temp_file_size 1024m; - 作用域:
http、server、location
proxy_temp_file_write_size
- 作用: 每次向磁盘中写入多少内容
- 基本语法:
proxy_temp_file_write_size ${size}; - 默认值:
proxy_temp_file_write_size 8k|16k; - 作用域:
http、server、location
proxy_temp_path
- 作用: 临时存放响应包体的目录
- 基本语法:
proxy_temp_path ${path} [level1 [level2 [level3]]]; - 默认值:
proxy_temp_path proxy_temp; - 作用域:
http、server、location
proxy_busy_buffers_size
- 作用: 在接收指定大小后立即将该包体传输给客户端
- 基本语法:
proxy_busy_buffers_size ${size}; - 默认值:
proxy_busy_buffers_size 8k|16k; - 作用域:
http、server、location
限制与上游服务的传输速度的命令有:
- proxy_read_timeout
- 作用: TCP 两次读取超时时间,在接收响应时,并不是一次性就能接收到,需要多次读取。该配置用于约束每次读取之间的时间间隔,超时则返回 502 状态码。
- 基本语法:
proxy_read_timeout ${time}; - 默认值:
proxy_read_timeout 60s; - 作用域:
http、server、location
- proxy_limit_rate
- 作用: 限制读取上游服务响应的速度,为 0 不限制
- 基本语法:
proxy_limit_rate ${rate}; - 默认值:
proxy_limit_rate 0; - 作用域:
http、server、location
持久化响应文件:
- proxy_store_access
- 作用: 存储文件时,使用什么样的所属组、权限
- 基本语法:
proxy_store_access users:permissions ...; - 默认值:
proxy_store_access user:rw; - 作用域:
http、server、location
- proxy_store
- 作用: 是否开启持久化文件,配置为 string 会指定存放位置
- 基本语法:
proxy_store on | off | ${string}; - 默认值:
proxy_store off; - 作用域:
http、server、location
返回响应
关于响应头的部分:
- proxy_ignore_headers
- 作用: 某些响应头部可以改变 Nginx 的行为,使用 proxy_ignore_headers 可以禁止它们生效
- 基本语法:
proxy_ignore_headers ${field} ...; - 默认值: 无
- 作用域:
http、server、location
涉及的响应头有:
X-Accel-Redirect: 由上游服务指定在 Nginx 内部重定向,控制请求的执行X-Accel-Limit-Rate: 由上游设置发往客户端的速度限制,等同limit_rate指令X-Accel-Buffering: 由上游控制是否缓存上游的响应X-Accel-Charset: 由上游控制 Content-Type 中的 Charset
缓存相关:
X-Accel-Expires: 设置响应在 Nginx 中的缓存时间,单位秒;@开头表示一天内某时刻Expires: 控制 Nginx 缓存时间,优先级低于X-Accel-ExpiresCache-Control: 控制 Nginx 缓存时间,优先级低于X-Accel-ExpiresSet-Cookie: 响应中出现Set-Cookie则不缓存,可通过proxy_ignore_headers禁止生效Vary: 响应中出现Vary: *则不缓存,同样可禁止生效
隐藏部分客户端用不到的响应头:
- proxy_hide_header
- 作用: 某些响应头部客户端用不上,使用 proxy_hide_header 可以将它们隐藏
- 基本语法:
proxy_hide_header ${field} ...; - 默认值: 默认忽略以下内容
Date: 由ngx_http_header_filter_module过滤模块填写,值为 Nginx 发送响应头部时的时间Server: 由ngx_http_header_filter_module过滤模块填写,值为 Nginx 版本X-Pad: 通常是 Apache 为避免浏览器 BUG 生成的头部,默认忽略X-Accel-${xxx}: 用于控制 Nginx 行为的响应,不需要向客户端转发
- 作用域:
http、server、location
- proxy_pass_header
- 作用: 对于被
proxy_hide_header过滤掉的字段,如果希望发送给客户端,就通过此命令覆盖 - 基本语法:
proxy_pass_header ${field}; - 默认值: 无
- 作用域:
http、server、location
- 作用: 对于被
修改 Set-Cookie:
- proxy_cookie_domain
- 作用: 修改 Set-Cookie 的域名
- 基本语法:
proxy_cookie_domain off;proxy_cookie_domain ${domain} ${replacement};
- 默认值:
proxy_cookie_domain off; - 作用域:
http、server、location
- proxy_cookie_path
- 作用: 修改 Set-Cookie 的子路径
- 基本语法:
proxy_cookie_path off;proxy_cookie_path ${path} ${replacement};
- 默认值:
proxy_cookie_path off; - 作用域:
http、server、location
修改 location:
- proxy_redirect
- 作用: 修改 location 重定向的位置
- 基本语法:
proxy_redirect default;proxy_redirect off;proxy_redirect ${redirect} ${replacement};
- 默认值:
proxy_redirect default; - 作用域:
http、server、location
处理上游错误
上游响应失败时,只要没有开始向客户端发送内容,就可以在内部对错误进行处理:
- proxy_next_upstream
- 作用: 在上游响应失败后,可以拦截对应错误,换个服务重试
- 基本语法:
proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;error: Nginx 与上游服务通信的全链路中,发生错误时生效timeout: 通信超时时生效invalid_header: 后端返回头部不合法时生效http_${code}: 后端返回指定状态码时生效off: 不开启功能
- 默认值:
proxy_next_upstream error timeout; - 作用域:
http、server、location
- proxy_next_upstream_timeout
- 作用: 重选上游服务处理时的超时时间
- 基本语法:
proxy_next_upstream_timeout time; - 默认值:
proxy_next_upstream_timeout 0; - 作用域:
http、server、location
- proxy_next_upstream_tries
- 作用: 最多重试次数
- 基本语法:
proxy_next_upstream_tries number; - 默认值:
proxy_next_upstream_tries 0; - 作用域:
http、server、location
使用 error_page 处理上游返回的错误码:
- proxy_intercept_errors
- 作用: 默认 Nginx 不会使用 error_page 处理上游服务的错误码,通过该命令可以修改这点
- 基本语法:
proxy_intercept_errors on | off; - 默认值:
proxy_intercept_errors off; - 作用域:
http、server、location
双向认证
Nginx 上游为 https 时,会使用双向认证,两端互相进行 https 校验。
Nginx 作为上游时
指定自身使用的证书:
- ssl_certificate
- 作用: 配置自身在通信时使用的 TLS 证书
- 基本语法:
ssl_certificate ${file}; - 默认值: 无
- 作用域:
http、server
- ssl_certificate_key
- 作用: 配置自身在通信时使用的 TLS 私钥
- 基本语法:
ssl_certificate_key ${file}; - 默认值: 无
- 作用域:
http、server
对下游证书进行验证:
- ssl_verify_client
- 作用: 是否对下游证书进行验证
- 基本语法:
ssl_verify_client on | off | optional | optional_no_ca;optional: 传了证书才验证
- 默认值:
ssl_verify_client off; - 作用域:
http、server
- ssl_client_certificate
- 作用:
- 基本语法:
ssl_client_certificate ${file}; - 默认值: 无
- 作用域:
http、server
Nginx 作为下游时
指定自身使用的证书:
- proxy_ssl_certificate
- 作用: 配置自身在通信时使用的 TLS 证书
- 基本语法:
proxy_ssl_certificate ${file}; - 默认值: 无
- 作用域:
http、server
- proxy_ssl_certificate_key
- 作用: 配置自身在通信时使用的 TLS 私钥
- 基本语法:
proxy_ssl_certificate_key ${file}; - 默认值: 无
- 作用域:
http、server
对上游证书进行验证:
- proxy_ssl_verify
- 作用: 是否对上游证书进行验证
- 基本语法:
proxy_ssl_verify on | off; - 默认值:
proxy_ssl_verify off; - 作用域:
http、server
- proxy_ssl_trusted_certificate
- 作用:
- 基本语法:
proxy_ssl_trusted_certificate ${file}; - 默认值: 无
- 作用域:
http、server
ssl 模块提供的变量
安全套件:
ssl_cipher: 本次通讯选用的安全套件,例如 ECDHE-RSA-AES128-GCM-SHA256ssl_ciphers: 客户端支持的所有安全套件ssl_protocol: 本次通讯选用的 TLS 版本,例如 TLSv1.2ssl_curves: 客户端支持的椭圆曲线,例如 secp384r1:secp521r1
证书:
ssl_client_raw_cert: 原始客户端证书内容ssl_client_escaped_cert: 返回客户端证书做 urlencode 编码后的内容ssl_client_cert: 对客户端证书每一行内容前加 tab 制表符空白,增强可读性。ssl_client_fingerprint: 客户端证书的 SHA1 指纹
证书结构化信息:
ssl_server_name: 通过 TLS 插件 SNI(ServerNameIndication) 获取到的服务域名ssl_client_i_dn: 依据 RFC2253 获取到证书 issuer dn 信息,例如:CN=..,O=..,L=..,C=..ssl_client_i_dn_legacy: 依据 RFC2253 获取到证书 issuer dn 信息,例如:/C=.../L=../O=.../CN=..ssl_client_s_dn: 依据 RFC2253 获取到证书 subject dn 信息,例如:CN=..,OU=..,O=..,L=..,ST=..,C=.ssl_client_s_dn_legacy: 同样获取 subject dn 信息,格式为:/C=...ST=.../L=...O=.../OU=...CN=..
证书有效期:
ssl_client_V_end: 返回客户端证书的过期时间,例如 Dec 4 11:56:11 2028 GMTssl_client_V_remain: 返回还有多少天客户端证书过期,例如 3649ssl_client_V_start: 客户端证书的颁发日期,例如 Dec 4 11:56:11 2018 GMT
连接有效性:
ssl_client_serial: 返回连接上客户端证书的序列号,例如 8BE947674841BD44ssl_early_data: 在 TLS 1.3 协议中使用了 early data 且握手未完成返回1,否则返回""ssl_client_verify: 如果验证失败为FAILED: ${reason},如果没有验证证书则为NONE,验证成功则为SUCCESSssl_session_id: 已建立连接的 sessionidssl_session_reused: 如果 session 被复用(参考 session 缓存)则为r,否则为.
缓存
网络链路中的缓存
- 浏览器缓存:
- 优点:
- 使用有效缓存时,没有网络消耗,速度最快
- 即使有网络消耗,但对失效缓存使用 304 响应做到网络流量消耗最小化
- 缺点:
- 仅提升一个用户的体验
- 优点:
- Nginx 缓存
- 优点
- 提升所有用户的体验
- 相比浏览器缓存,有效降低上游服务的负载
- 通过 304 响应减少 Nginx 与上游服务间的流量消耗
- 缺点:
- 用户仍然保持网络消耗
- 同时使用浏览器与 Nginx 缓存
- 优点
浏览器缓存
浏览器缓存流程如下图:

关于 强缓存 、 协商缓存 在浏览器部分有详细介绍,这里主要记录服务端视角下的协商缓存。
Nginx 配置 ETag:
- etag
- 作用: 控制响应是否携带 ETag 信息, ETag 生成规则为:
${last_modified_time}-${content_length} - 语法:
etag: on / off; - 默认值:
etag: on; - 作用域:
http、server、location
- 作用: 控制响应是否携带 ETag 信息, ETag 生成规则为:
全程通过 expires 指令来控制过期时间
- expires
- 作用: 设置静态资源的缓存策略
- 基本语法:
expires [modified] ${time};expires epoch | max | off;max: 设置为最大值,一般是 10 年off: 不添加或者修改Expires和Cache-Control字段epoch: 设置为不缓存,过期时间为时间戳起始时间Expires: Thu, 01 Jan 1970 00:00:01 GMTCache-Control: no-cache
${time}: 设定具体时间,可以带单位- 一天内的具体时刻可以加@,比如下午六点半:
@18h30m
- 一天内的具体时刻可以加@,比如下午六点半:
- 正数: 设定 Cache-Control 时间,计算出
Expires,例如1h - 负数:
Cache-Control: no-cache,计算出Expires,例如-1h
- 默认值:
expires off; - 作用域:
http、server、location、location中的if
验证资源是否过期
针对浏览器协商缓存的校验功能都在 ngx_http_not_modified_module 模块中,如果资源已经 404 了,直接返回错误码,不会决策返回 200 还是 304
验证缓存是否过期流程如下:

- if_modified_since
- 作用: 声明比较过期时间时,如何进行比较
- 基本语法:
if_modified_since off | exact | before;off: 忽略请求中的 if_modified_since 头部exact: 精确匹配 if_modified_since 头部与 last_modified 的值before: 若 if_modified_since 大于等于 last_modified 的值,则返回 304
- 默认值:
if_modified_since exact; - 作用域:
http、server、location
Nginx 配置上游服务缓存
完整缓存流程如下图:


定义缓存载体
- proxy_cache
- 作用: 定义缓存使用的共享内存空间
- 基本语法:
proxy_cache zone | off; - 默认值:
proxy_cache off; - 作用域:
http、server、location
- proxy_cache_path
- 作用: 定义缓存到磁盘中的哪个位置
- 基本语法:
proxy_cache_path ${path}; - 默认值: 无
- 作用域:
http
缓存哪些值
- proxy_cache_key
- 作用: 设置缓存时使用的 key 值,例如静态资源可以只使用 uri 缓存, SSR 资源需要加上用户指纹缓存
- 基本语法:
proxy_cache_key ${key}; - 默认值:
proxy_cache_key $scheme$proxy_host$request_uri; - 作用域:
http、server、location
缓存哪些响应
- proxy_cache_valid
- 作用: 声明哪些响应需要被缓存起来
- 基本语法:
proxy_cache_valid [code ...] ${time};- 如果未配置状态码时,默认缓存 200 、 301 、 302 的请求
X-Accel-Expires也能控制 Nginx 缓存- 如果响应头含有
Set-Cookie或者Vary: *则不缓存
- 默认值: 无
- 作用域:
http、server、location
哪些内容不缓存
proxy_no_cache
- 作用: 指定参数为真时,不进行缓存
- 基本语法:
proxy_no_cache ${string} ...; - 默认值: 无
- 作用域:
http、server、location
proxy_cache_bypass
- 作用: 指定参数为真时,有缓存也不使用缓存
- 基本语法:
proxy_cache_bypass ${string} ...; - 默认值: 无
- 作用域:
http、server、location
缓存回源
当缓存失效时,需要从上游服务中获取新的结果,这个过程称为回源,对应的上游服务称为源站。
如果频繁回源,会导致源站压力升高,可能直接导致源站挂起。
Nginx 提供了一些优化回源的能力。
合并回源请求
同一时间,合并多个相同 key 的请求,只向上游服务发送一条请求,其他请求等待上游服务响应后,使用缓存数据。
主要处理的是热点文件的请求的回源问题,非热点文件基本无效果

- proxy_cache_lock
- 作用: 同一时间,仅第 1 个请求发向上游,其他请求等待第 1 个响应返回或者超时后,使用缓存响应客户端
- 基本用法:
proxy_cache_lock on | off; - 默认值:
proxy_cache_lock off; - 作用域:
http、server、location
- proxy_cache_lock_timeout
- 作用: 被阻塞的其他缓存在等待第 1 个请求返回响应的最大时间,到达后直接向上游发送请求,但不缓存响应
- 基本用法:
proxy_cache_lock_timeout time; - 默认值:
proxy_cache_lock_timeout 5s; - 作用域:
http、server、location
- proxy_cache_lock_age
- 作用: 上一个请求返回响应的超时时间,到达后再放行一个请求发向上游,而不是一次性所有阻塞请求都超时
- 基本用法:
proxy_cache_lock_age ${time}; - 默认值:
proxy_cache_lock_age 5s; - 作用域:
http、server、location
减少回源请求
当前已有缓存,但是失效了,可以先发送陈旧的缓存给用户,同时进行缓存更新操作。

- proxy_cache_use_stale
- 作用: 配置是否使用陈旧缓存
- 基本语法:
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;updating: 当缓存内容过期,有一个请求正在访问上游试图更新缓存时,其他请求直接使用过期内容返回客户端。stale-while-revalidate: Cache-Control 中的配置信息,声明在缓存过期后还可以容忍多长时间,这段时间内可以使用陈旧缓存,否则 updating 设置无效。例如:Cache-Control: max-age=600, stale-while-revalidate=30stale-if-error: Cache-Control 中的配置信息,声明在缓存过期后,在这段时间内如果上游服务报错,就继续使用陈旧缓存,否则会请求上游获取新数据。例如:Cache-Control: max-age=600, stale-if-error=1200
error: 当与上游建立连接、发送请求、读取响应头部等情况出错时,使用缓存timeout: 当与上游建立连接、发送请求、读取响应头部等情况出现定时器超时,使用缓存http_(500|502|503|504|403|404|429): 缓存以上错误响应码的内容
- 默认值:
proxy_cache_use_stale off; - 作用域:
http、server、location
- proxy_cache_background_update
- 作用: 当使用 proxy_cache_use_stale 允许使用过期响应时,将同步生成一个子请求,通过访问上游服务更新过期的缓存
- 基本用法:
proxy_cache_background_update on | off; - 默认值:
proxy_cache_background_update off; - 作用域:
http、server、location
- proxy_cache_revalidate
- 作用: 更新缓存时,使用 If-Modified-Since 和 If-None-Match 作为请求头部,预期内容未发生变更时通过 304 来减少传输的内容
- 基本用法:
proxy_cache_revalidate on | off; - 默认值:
proxy_cache_revalidate off; - 作用域:
http、server、location
清除缓存
开源版 Nginx 没有这项能力,商业版 Nginx 有提供,或者使用免费的第三方模块 ngx_cache_purge
- proxy_cache_purge
- 作用: 声明在什么条件下进行缓存请求,在命令中定义匹配条件
- 基本用法:
proxy_cache_purge on | off | ${method} [from all | ${ip} ... ] - 默认值: 无
- 作用域:
http、server、location
- proxy_cache_purge
- 作用: 只要 location 匹配,就清除缓存,只需要定义声明清除哪个共享内存中的哪些 key ,比如匹配用户登录/登出
- 基本用法:
proxy_cache_purge ${zone_name} ${key} - 默认值: 无
- 作用域:
http、server、location
性能优化
从软件层面提升硬件使用效率
- 增大 CPU 的利用率
- 增大内存的利用率
- 增大磁盘 I/0 的利用率
- 增大网络带宽的利用率
提升硬件规格
- 网卡: 万兆网卡,例如 10G 、 25G 、 40G 等
- 磁盘: 固态硬盘,关注 IOPS 和 BPS 指标
- CPU: 更快的主频,更多的核心,更大的缓存,更优的架构
- 内存: 更快的访问速度
优化 CPU 利用率
整体思路:
- 能够使用 全部 CPU 资源
- master-worker 多进程架构
- worker 进程数量 应当大于等于 CPU 核数
- Nginx 进程间不做无用功浪费 CPU 资源
- worker 进程不应在繁忙时, 主动 让出 CPU ,有以下两种情况:
- worker 进程间不应由于争抢造成资源耗散
- worker 进程数量应当等于 CPU 核数
- 使用
worker_cpu_affinity ${cpumask}为 worker 进程绑定 CPU
- worker 进程不应调用一些 API 导致主动让出 CPU
- 拒绝会导致进程阻塞的第三方模块
- worker 进程间不应由于争抢造成资源耗散
- worker 进程不应在繁忙时, 主动 让出 CPU ,有以下两种情况:
- 不被其他进程争抢资源
- 提升进程优先级,占用 CPU 更长的时间
- 使用
worker_priority -20;配置,设置为最高优先级,默认为worker_priority 0;
- 使用
- 减少操作系统上耗资源的非 Nginx 进程
- 提升进程优先级,占用 CPU 更长的时间
优化网络传输
- 超时重试次数减少,避免占用资源
- 限制 TCP 握手各个阶段的队列数量,比如 SYN_RECV 、 ACCEPT 等状态
- 设置 worker 最大连接数(包含 Nginx 与上下游之间的连接)
- 限制丢包重传次数
- 压缩响应体积
- 升级 HTTP 协议