24-nginx高级篇
以下为你提供一个展示 Nginx 高级知识相关内容及关系的 Mermaid 图示,涵盖了负载均衡、缓存、安全、性能优化等方面,同时会给出代码和详细解释。
graph LR
classDef concept fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef subconcept fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A(Nginx 高级知识):::concept --> B(负载均衡):::subconcept
A --> C(缓存机制):::subconcept
A --> D(安全配置):::subconcept
A --> E(性能优化):::subconcept
A --> F(高可用架构):::subconcept
B --> B1(轮询策略):::subconcept
B --> B2(加权轮询策略):::subconcept
B --> B3(IP 哈希策略):::subconcept
B --> B4(最少连接策略):::subconcept
C --> C1(反向代理缓存):::subconcept
C --> C2(浏览器缓存控制):::subconcept
D --> D1(访问控制):::subconcept
D --> D2(SSL/TLS 配置):::subconcept
D --> D3(防止 DDoS 攻击):::subconcept
E --> E1(连接优化):::subconcept
E --> E2(文件传输优化):::subconcept
E --> E3(压缩配置):::subconcept
F --> F1(Keepalived 实现高可用):::subconcept
F --> F2(Nginx 集群):::subconcept
图示解释
1. 整体结构
Nginx 高级知识主要包含负载均衡、缓存机制、安全配置、性能优化和高可用架构这几个关键方面。
2. 负载均衡
负载均衡用于将客户端请求均匀分配到多个后端服务器,以提高系统的处理能力和可靠性。
- 轮询策略:按顺序依次将请求分配给后端服务器,每个服务器轮流处理请求。
- 加权轮询策略:根据后端服务器的性能为其分配不同的权重,性能好的服务器处理更多的请求。
- IP 哈希策略:根据客户端的 IP 地址进行哈希计算,将相同 IP 的请求始终分配到同一台后端服务器,适用于需要保持会话一致性的场景。
- 最少连接策略:将请求分配给当前连接数最少的后端服务器,确保各服务器的负载相对均衡。
3. 缓存机制
缓存机制可以减少服务器的负载和响应时间,提高网站的性能。
- 反向代理缓存:Nginx 作为反向代理服务器,缓存后端服务器的响应结果,当有相同请求时,直接返回缓存内容,而无需再次请求后端服务器。
- 浏览器缓存控制:通过设置响应头信息,控制浏览器对静态资源的缓存行为,如设置
Cache-Control
、Expires
等头字段。
4. 安全配置
保障网站的安全性,防止各种安全威胁。
- 访问控制:通过
allow
和deny
指令限制特定 IP 地址或 IP 段的访问,只允许授权的用户访问网站。 - SSL/TLS 配置:为网站启用 HTTPS 协议,使用 SSL/TLS 加密数据传输,保护用户信息的安全。
- 防止 DDoS 攻击:通过配置 Nginx 的限流、限速等功能,抵御分布式拒绝服务攻击,确保网站的可用性。
5. 性能优化
提高 Nginx 服务器的性能和响应速度。
- 连接优化:调整 Nginx 的连接参数,如
worker_connections
、keepalive_timeout
等,优化服务器的连接处理能力。 - 文件传输优化:启用
sendfile
功能,避免数据在用户空间和内核空间之间的多次拷贝,提高文件传输效率。 - 压缩配置:启用 Gzip 压缩,对文本类数据(如 HTML、CSS、JavaScript 等)进行压缩后再传输,减少数据传输量。
6. 高可用架构
确保 Nginx 服务在出现故障时能够快速恢复,保证网站的持续可用性。
- Keepalived 实现高可用:结合 Keepalived 软件,实现 Nginx 的主备切换,当主服务器出现故障时,自动切换到备用服务器。
- Nginx 集群:构建 Nginx 集群,通过负载均衡器将请求分发到多个 Nginx 服务器,提高系统的整体性能和可靠性。
一、日志切割(shell脚本)
以下是使用 Mermaid 绘制的 Nginx 日志切割流程图示,同时附上代码和详细解释。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
classDef log fill:#E8F5E9,stroke:#81C784,stroke-width:2px;
A(定时任务触发):::process --> B{是否达到切割条件}:::decision
B -->|是| C(停止 Nginx 写入当前日志):::process
B -->|否| D(继续记录日志):::process
C --> E(重命名当前日志文件):::process
E --> F(创建新的日志文件):::process
F --> G(重新启动 Nginx 写入新日志):::process
E --> H(压缩旧日志文件):::process
H --> I(存储旧日志文件):::process
I --> J{是否需要清理旧日志}:::decision
J -->|是| K(删除过期旧日志):::process
J -->|否| L(保留旧日志):::process
D --> B
图示解释
1. 定时任务触发
通过系统的定时任务(如 cron
)定期检查是否满足日志切割条件,这个时间间隔可以根据实际需求设置,比如每天、每周等。
2. 判断是否达到切割条件
判断是否满足日志切割的条件,常见的切割条件有:
- 时间条件:例如每天凌晨进行切割。
- 文件大小条件:当日志文件达到一定大小(如 1GB)时进行切割。
3. 执行日志切割操作
- 停止 Nginx 写入当前日志:为了确保在重命名和创建新日志文件时不会出现数据丢失,需要暂时停止 Nginx 向当前日志文件写入数据。可以通过向 Nginx 主进程发送信号(如
USR1
)来实现。 - 重命名当前日志文件:将当前正在使用的日志文件重命名,通常会在文件名中添加日期或时间戳,方便后续管理和查找,例如将
access.log
重命名为access.log.20240101
。 - 创建新的日志文件:在重命名旧日志文件后,需要创建一个新的空白日志文件供 Nginx 继续写入日志,文件名保持与原日志文件名一致,如
access.log
。 - 重新启动 Nginx 写入新日志:让 Nginx 重新开始向新创建的日志文件写入数据。
4. 处理旧日志文件
- 压缩旧日志文件:为了节省磁盘空间,通常会对旧的日志文件进行压缩,常见的压缩格式有
gzip
,压缩后的文件扩展名为.gz
。 - 存储旧日志文件:将压缩后的旧日志文件存储到指定的目录中,方便后续的查看和分析。
5. 清理旧日志
- 判断是否需要清理旧日志文件,如果旧日志文件存储时间超过了预设的保留期限,就将其删除,以释放磁盘空间;如果未超过保留期限,则保留旧日志文件。
实际操作示例
以下是一个使用 cron
定时任务和 shell
脚本实现 Nginx 日志切割的示例:
nginx_log_rotate.sh
脚本内容
#!/bin/bash
# 日志文件路径
LOG_PATH="/var/log/nginx"
# 日期格式
DATE=$(date +%Y%m%d)
# 停止 Nginx 写入当前日志
kill -USR1 $(cat /var/run/nginx.pid)
# 重命名日志文件
mv ${LOG_PATH}/access.log ${LOG_PATH}/access.log.${DATE}
mv ${LOG_PATH}/error.log ${LOG_PATH}/error.log.${DATE}
# 压缩旧日志文件
gzip ${LOG_PATH}/access.log.${DATE}
gzip ${LOG_PATH}/error.log.${DATE}
# 删除 7 天前的旧日志
find ${LOG_PATH} -name "*.log.*.gz" -mtime +7 -exec rm -f {} \;
添加 cron
定时任务
# 每天凌晨 2 点执行日志切割脚本
0 2 * * * /path/to/nginx_log_rotate.sh
通过以上流程和示例,就可以实现 Nginx 日志的定期切割和管理。
nginx日志默认是不切割的,网站运行久了自然生成大量日志,导致单文件的处理,太麻烦,因此工作里一般定期切割,一般按天切割。
-rw-r--r-- 1 root root 2.1G May 8 13:57 front_access.log
1.shell脚本切割
1.查看当前的日志
[root@web-9 /var/log/nginx]#ls
access.log error.log error.movie.yuchaoit.log error.www.yuchaoit.log movie.yuchaoit.log www.yuchaoit.log
2.备份当前日志文件,请用rename改名即可
[root@web-9 /var/log/nginx]#ll
total 0
-rw-r--r-- 1 root root 0 May 8 14:31 error.log
-rw-r--r-- 1 root root 0 May 8 14:31 error.movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 error.www.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 www.yuchaoit.log
[root@web-9 /var/log/nginx]#
[root@web-9 /var/log/nginx]#
[root@web-9 /var/log/nginx]#rename log log.$(date +%F) *.log
[root@web-9 /var/log/nginx]#ll
total 0
-rw-r--r-- 1 root root 0 May 8 14:31 error.log.2022-05-08
-rw-r--r-- 1 root root 0 May 8 14:31 error.movie.yuchaoit.log.2022-05-08
-rw-r--r-- 1 root root 0 May 8 14:31 error.www.yuchaoit.log.2022-05-08
-rw-r--r-- 1 root root 0 May 8 14:31 movie.yuchaoit.log.2022-05-08
-rw-r--r-- 1 root root 0 May 8 14:31 www.yuchaoit.log.2022-05-08
3.给nginx master进程发送USR1信号,等于重新打开日志记录
nginx -s reopen或者 kill -USR1 $(cat /var/run/nginx.pid)
4.试试重新生成日志
[root@web-9 /var/log/nginx]#
[root@web-9 /var/log/nginx]#kill -USR1 $(cat /var/run/nginx.pid)
[root@web-9 /var/log/nginx]#ll
total 0
-rw-r--r-- 1 www root 0 May 8 14:36 error.log
-rw-r--r-- 1 root root 0 May 8 14:31 error.log.2022-05-08
-rw-r--r-- 1 www root 0 May 8 14:36 error.movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 error.movie.yuchaoit.log.2022-05-08
-rw-r--r-- 1 www root 0 May 8 14:36 error.www.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 error.www.yuchaoit.log.2022-05-08
-rw-r--r-- 1 www root 0 May 8 14:36 movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 movie.yuchaoit.log.2022-05-08
-rw-r--r-- 1 www root 0 May 8 14:36 www.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 14:31 www.yuchaoit.log.2022-05-08
2.完整的脚本
[root@web-9 /etc/nginx]#cat cut_log.sh
#!/bin/bash
# 源日志目录
logs_path="/var/log/nginx"
# 备份日志目录
back_logs_path="${logs_path}/$(date -d 'yesterday' +'%F')"
# 创建备份目录,以日期命名,注意,每天零点整切割,开始记录新的一天的日志,备份目录应该是昨天
mkdir -p ${back_logs_path}
# 重命名旧日志名,注意日期
cd ${logs_path} && find . -type f |xargs -i mv {} {}.$(date -d 'yesterday' +'%F')
# 移动旧日志文件到该目录下
cd ${logs_path} && find . -type f |xargs -i mv {} ${back_logs_path}
# 重新生成新日志
kill -USR1 `cat /var/run/nginx.pid`
3.实践过程
1.你可以准备如下测试数据
[root@web-9 /var/log/nginx]#systemctl restart nginx
[root@web-9 /var/log/nginx]#ll
total 0
-rw-r--r-- 1 root root 0 May 8 15:17 error.log
-rw-r--r-- 1 root root 0 May 8 15:17 error.movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 15:17 error.www.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 15:17 movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 15:17 www.yuchaoit.log
2.修改日期到第二天0点
[root@web-9 /var/log/nginx]#date -s '2022-5-9 00:00'
Mon May 9 00:00:00 CST 2022
[root@web-9 /var/log/nginx]#date
Mon May 9 00:00:01 CST 2022
3.执行脚本
[root@web-9 /etc/nginx]#bash cut_log.sh
4.查看备份的日志
4.写入定时任务
[root@web-9 /etc/nginx]#crontab -l
* * * * * /usr/sbin/ntpdate time1.aliyun.com > /dev/null 2>&1
0 0 * * * /bin/bash /etc/nginx/cut_log.sh
二、日志切割(logrotate工具)
以下是使用 Mermaid 绘制的 logrotate
对 Nginx 日志进行管理的流程图,同时附上代码和详细解释。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
classDef log fill:#E8F5E9,stroke:#81C784,stroke-width:2px;
A(定时任务触发 logrotate):::process --> B(读取 logrotate 配置文件):::process
B --> C{是否匹配 Nginx 日志规则}:::decision
C -->|是| D(停止 Nginx 写入当前日志):::process
C -->|否| E(处理其他日志):::process
D --> F(重命名当前 Nginx 日志文件):::process
F --> G(创建新的 Nginx 日志文件):::process
G --> H(重新启动 Nginx 写入新日志):::process
F --> I(根据配置处理旧日志):::process
I --> J{是否压缩旧日志}:::decision
J -->|是| K(压缩旧日志文件):::process
J -->|否| L(保留未压缩旧日志):::process
K --> M{是否保留指定数量日志}:::decision
L --> M
M -->|是| N(删除过期旧日志):::process
M -->|否| O(保留所有旧日志):::process
E --> B
图示解释
1. 定时任务触发
系统的定时任务(通常是 cron
)会按照预设的时间间隔触发 logrotate
程序。logrotate
是一个专门用于管理日志文件的工具,它可以根据配置自动对日志文件进行切割、压缩和清理等操作。
2. 读取配置文件
logrotate
启动后,会读取其配置文件(一般位于 /etc/logrotate.conf
和 /etc/logrotate.d/
目录下的各个配置文件)。这些配置文件定义了不同日志文件的处理规则。
3. 匹配 Nginx 日志规则
logrotate
会检查当前要处理的日志文件是否匹配 Nginx 日志的处理规则。如果匹配,则开始对 Nginx 日志进行处理;如果不匹配,则继续处理其他日志文件。
4. 处理 Nginx 日志
- 停止 Nginx 写入当前日志:为了确保在重命名和创建新日志文件时不会丢失数据,
logrotate
会向 Nginx 主进程发送信号(通常是USR1
),让 Nginx 停止向当前日志文件写入数据。 - 重命名当前 Nginx 日志文件:将当前正在使用的 Nginx 日志文件(如
access.log
)重命名,一般会在文件名后添加日期或序号,方便后续管理和查找。 - 创建新的 Nginx 日志文件:在重命名旧日志文件后,
logrotate
会创建一个新的空白日志文件,文件名与原日志文件名相同,供 Nginx 继续写入日志。 - 重新启动 Nginx 写入新日志:让 Nginx 重新开始向新创建的日志文件写入数据。
5. 处理旧日志文件
- 是否压缩旧日志:根据
logrotate
配置文件中的设置,决定是否对旧的 Nginx 日志文件进行压缩。如果需要压缩,会使用gzip
等工具将日志文件压缩成.gz
格式。 - 是否保留指定数量日志:配置文件中可以设置保留旧日志文件的数量。如果达到了保留数量上限,
logrotate
会删除最旧的日志文件;如果没有设置保留数量限制,则保留所有旧日志文件。
logrotate
配置文件示例
以下是一个简单的 Nginx 日志 logrotate
配置文件示例(假设文件名为 /etc/logrotate.d/nginx
):
/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 640 www-data adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
daily
:表示每天进行一次日志切割。missingok
:如果日志文件不存在,不报错。rotate 7
:保留最近 7 天的日志文件。compress
:对旧日志文件进行压缩。delaycompress
:延迟压缩,即下次切割时再压缩本次切割的日志文件。notifempty
:如果日志文件为空,不进行切割。create 640 www-data adm
:创建新的日志文件,权限为 640,所有者为www-data
,所属组为adm
。sharedscripts
:表示在所有日志文件处理完毕后执行一次postrotate
脚本。postrotate
和endscript
:定义了在日志切割后执行的脚本,这里是向 Nginx 主进程发送USR1
信号,让 Nginx 重新打开日志文件。
于超老师提示,清理上一次实验的环境。
shell脚本切割比较简单方便、nginx其实提供了更好用的工具
logrotate是一款自动切割日志的工具
1.检查logrotate
# rpm -qa 检查nginx的配置文件列表
[root@web-9 /etc/nginx]#rpm -qc nginx
/etc/logrotate.d/nginx
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params
/etc/nginx/mime.types
/etc/nginx/nginx.conf
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
2.配置解释
[root@web-9 /etc/nginx]#cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天切割
missingok # 忽略错误
rotate 52 # 最多保留多少个存档
compress # 切割后且压缩
delaycompress # 延迟压缩动作在下一次切割
notifempty # 日志为空就不切割
create 640 nginx adm # 切割的文件权限
sharedscripts # 共享脚本,结果为空
postrotate # 收尾动作,重新生成nginx日志
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript # 结束动作
}
3.测试切割
1.创建压测工具,生成大量日志
yum install httpd-tools -y
2.可以先清空默认日志
3.模拟100个并发用户,共计发出10000个请求
ab -c 100 -n 10000 http://10.0.0.9/
4.检查日志记录
[root@web-9 /var/log/nginx]#ll
total 960
-rw-r--r-- 1 root root 0 May 8 15:41 error.log
-rw-r--r-- 1 root root 0 May 8 15:41 error.movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 15:41 error.www.yuchaoit.log
-rw-r--r-- 1 root root 900000 May 8 15:41 movie.yuchaoit.log
-rw-r--r-- 1 root root 0 May 8 15:41 www.yuchaoit.log
[root@web-9 /var/log/nginx]#cat movie.yuchaoit.log |wc -l
10000
5.主动切割日志
[root@web-9 /var/log/nginx]#logrotate -f /etc/logrotate.d/nginx
[root@web-9 /var/log/nginx]#ll
total 880
-rw-r--r-- 1 www root 0 May 8 15:41 error.log
-rw-r--r-- 1 www root 0 May 8 15:41 error.movie.yuchaoit.log
-rw-r--r-- 1 www root 0 May 8 15:41 error.www.yuchaoit.log
-rw-r----- 1 www adm 0 May 8 15:41 movie.yuchaoit.log
-rw-r--r-- 1 root root 900000 May 8 15:41 movie.yuchaoit.log.1
-rw-r--r-- 1 www root 0 May 8 15:41 www.yuchaoit.log
6.会发现当前并没有压缩,只有下一次切割才会压缩
7.修改系统时间,模拟到了第二天
[root@web-9 /var/log/nginx]#date -s '20220509'
Mon May 9 00:00:00 CST 2022
[root@web-9 /var/log/nginx]#date +%F
2022-05-09
8.再次创建大量日志(否则空日志不会切割)
[root@master-61 ~]#ab -c 100 -n 10000 http://10.0.0.9/
9.再次查看日志
[root@web-9 /var/log/nginx]#ll
total 1840
-rw-r--r-- 1 www root 0 May 8 15:45 error.log
-rw-r--r-- 1 www root 0 May 8 15:45 error.movie.yuchaoit.log
-rw-r--r-- 1 www root 0 May 8 15:45 error.www.yuchaoit.log
-rw-r----- 1 www adm 900000 May 9 00:00 movie.yuchaoit.log
-rw-r--r-- 1 root root 900000 May 8 15:45 movie.yuchaoit.log.1
-rw-r--r-- 1 www root 0 May 8 15:45 www.yuchaoit.log
10.开始切割,查看日志压缩情况
[root@web-9 /var/log/nginx]#logrotate -f /etc/logrotate.d/nginx
[root@web-9 /var/log/nginx]#ll
total 884
-rw-r--r-- 1 www root 0 May 8 15:45 error.log
-rw-r--r-- 1 www root 0 May 8 15:45 error.movie.yuchaoit.log
-rw-r--r-- 1 www root 0 May 8 15:45 error.www.yuchaoit.log
-rw-r----- 1 www adm 0 May 9 00:00 movie.yuchaoit.log
-rw-r----- 1 www adm 900000 May 9 00:00 movie.yuchaoit.log.1
-rw-r--r-- 1 root root 3179 May 8 15:45 movie.yuchaoit.log.2.gz
-rw-r--r-- 1 www root 0 May 8 15:45 www.yuchaoit.log
11.写入定时任务,即可按天切割且压缩nginx日志了
[root@web-9 /var/log/nginx]#crontab -l
01 00 * * * /usr/sbin/logrotate -f /etc/logrotate.d/nginx >> /var/log/nginx/logrotate_nginx.log 2>&1
三、目录索引、文件下载服务
官网文档
http://nginx.org/en/docs/http/ngx_http_autoindex_module.html
利用nginx实现文件下载服务器
以下是使用 Mermaid 绘制的 Nginx autoindex
功能的工作流程图示,同时给出代码和详细解释。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
classDef file fill:#E8F5E9,stroke:#81C784,stroke-width:2px;
classDef dir fill:#FFEBEE,stroke:#E57373,stroke-width:2px;
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C{请求路径是否为目录}:::nginx
C -->|是| D{autoindex 是否开启}:::nginx
C -->|否| E(返回文件内容):::nginx
D -->|是| F(生成目录索引页面):::nginx
D -->|否| G(返回 403 Forbidden):::nginx
F --> H(列出目录下的文件和子目录):::nginx
H --> I(返回目录索引页面给客户端):::nginx
E --> J(客户端接收文件内容):::client
G --> K(客户端收到 403 错误):::client
I --> L(客户端查看目录索引):::client
图示解释
1. 客户端发起请求
客户端(如浏览器)向 Nginx 服务器发送 HTTP 请求,请求访问某个文件或目录。
2. Nginx 接收请求
Nginx 服务器监听指定的端口,接收到客户端的请求后开始进行处理。
3. 判断请求路径是否为目录
Nginx 会检查请求的路径是指向一个文件还是一个目录。
4. 若请求路径为文件
如果请求的路径是一个文件,Nginx 会直接返回该文件的内容给客户端。
5. 若请求路径为目录
- 判断
autoindex
是否开启:autoindex
是 Nginx 的一个指令,用于控制是否开启目录索引功能。如果开启(autoindex on;
),则继续下一步;如果关闭(autoindex off;
),Nginx 会返回 403 Forbidden 错误给客户端,表示客户端没有权限访问该目录。 - 生成目录索引页面:当
autoindex
开启时,Nginx 会生成一个包含该目录下所有文件和子目录列表的 HTML 页面。 - 列出目录下的文件和子目录:在生成的目录索引页面中,会列出目录下的所有文件和子目录的名称、大小、修改时间等信息。
- 返回目录索引页面给客户端:Nginx 将生成的目录索引页面发送给客户端。
6. 客户端接收响应
- 如果请求的是文件,客户端接收并显示文件内容。
- 如果请求的目录
autoindex
关闭,客户端收到 403 错误。 - 如果请求的目录
autoindex
开启,客户端可以查看目录索引页面,从而进一步选择要访问的文件或子目录。
Nginx 配置示例
以下是一个简单的 Nginx 配置示例,展示如何开启 autoindex
功能:
server {
listen 80;
server_name example.com;
root /var/www/html;
location / {
autoindex on;
}
}
在这个配置中,当客户端请求 /var/www/html
目录下的某个目录时,Nginx 会生成并返回该目录的索引页面。
1.参数说明
Syntax: autoindex on | off;
Default:
autoindex off;
Context: http, server, location
# autoindex on ; 表示开启目录索引
Syntax: autoindex_localtime on | off;
Default:
autoindex_localtime off;
Context: http, server, location
# autoindex_localtime on; 显示文件为服务器的时间
Syntax: autoindex_exact_size on | off;
Default:
autoindex_exact_size on;
Context: http, server, location
# autoindex_exact_size on; 显示确切bytes单位
# autoindex_exact_size off; 显示文件大概单位,是KB、MB、GB
若目录有中文,nginx.conf中添加utf8编码
charset utf-8,gbk;
2.配置文件
测试数据
[root@web-9 /var/log/nginx]#dd if=/dev/zero of=/yuchaoit/牛啊牛啊.log^C
[root@web-9 /var/log/nginx]#ll /yuchaoit/ -h
total 236M
-rw-r--r-- 1 root root 236M May 8 16:06 牛啊牛啊.log
-rw-r--r-- 1 root root 0 May 8 16:04 男宾10号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾1号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾2号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾3号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾4号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾5号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾6号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾7号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾8号.png
-rw-r--r-- 1 root root 0 May 8 16:04 男宾9号.png
单独生成子配置文件,专用于下载
cat >/etc/nginx/conf.d/download.conf <<EOF
server{
listen 8888;
server_name localhost;
charset utf-8,gbk;
location / {
root /yuchaoit/;
autoindex on;
autoindex_localtime on;
autoindex_exact_size off;
}
}
EOF
重启,查看结果
systemctl restart nginx
3.访问目录索引
四、连接数监控
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef data fill:#E8F5E9,stroke:#81C784,stroke-width:2px
A(客户端发送状态查询请求):::process --> B(Nginx 接收请求):::process
B --> C{是否开启 stub_status 模块}:::decision
C -->|否| D(返回 404 或拒绝访问):::process
C -->|是| E{是否匹配状态页面路径}:::decision
E -->|否| F(按常规请求处理):::process
E -->|是| G(ngx_http_stub_status_module 介入):::process
G --> H(收集状态数据):::process
H --> I(Active connections 数量):::data
H --> J(Accepts 接受连接数):::data
H --> K(Handled 处理连接数):::data
H --> L(Requests 请求数):::data
H --> M(Reading 正在读取请求头的连接数):::data
H --> N(Writing 正在写入响应的连接数):::data
H --> O(Waiting 空闲等待请求的连接数):::data
I --> P(生成状态报告页面):::process
J --> P
K --> P
L --> P
M --> P
N --> P
O --> P
P --> Q(返回状态报告给客户端):::process
D --> R(客户端接收错误响应):::process
F --> S(客户端接收常规响应):::process
Q --> T(客户端查看状态信息):::process
图示解释
1. 请求接收与初步判断
- 客户端发送状态查询请求:客户端(如运维人员使用工具或浏览器)向 Nginx 发送获取状态信息的请求。
- Nginx 接收请求:Nginx 监听端口并接收到该请求。
- 是否开启 stub_status 模块:Nginx 检查自身是否开启了
ngx_http_stub_status_module
。若未开启,返回 404 或拒绝访问;若开启,则继续下一步判断。
2. 路径匹配与模块介入
- 是否匹配状态页面路径:判断请求的路径是否为配置中允许获取状态信息的路径。若不匹配,按常规请求处理;若匹配,
ngx_http_stub_status_module
开始介入处理。
3. 状态数据收集
- 收集状态数据:该模块收集一系列重要的 Nginx 状态数据,包括:
- Active connections:当前活跃的连接数量。
- Accepts:Nginx 启动以来接受的连接总数。
- Handled:Nginx 启动以来处理的连接总数。
- Requests:Nginx 启动以来处理的请求总数。
- Reading:正在读取客户端请求头的连接数量。
- Writing:正在向客户端写入响应的连接数量。
- Waiting:处于空闲状态,等待客户端请求的连接数量。
4. 生成并返回状态报告
- 生成状态报告页面:将收集到的状态数据整合到一个页面中。
- 返回状态报告给客户端:Nginx 把生成的状态报告页面返回给客户端,客户端可以查看这些状态信息来监控 Nginx 的运行状况。
5. 不同响应结果
- 若模块未开启或路径不匹配,客户端会接收错误响应或常规响应;若一切正常,客户端能顺利查看状态信息。
官网文档
http://nginx.org/en/docs/http/ngx_http_stub_status_module.html 模块介绍
该ngx_http_stub_status_module模块提供对基本状态信息的访问。
默认情况下不构建此模块,应使用 --with-http_stub_status_module 配置参数启用它。
Nginx状态信息(status)介绍 Nginx软件在编译时又一个with-http_stub_status_module模块,这个模块功能是记录Nginx的基本访问状态信息,对于想了解nginx的状态以及监控nginx非常有帮助。
让使用者了解Nginx的工作状态。
要想使用状态模块,在编译时必须增加--with-http_stub_status_module参数。
1.参数解释
Active connections
当前活动客户端连接数,包括Waiting连接数。
accepts
接受的客户端连接总数。
handled
处理的连接总数。
accepts 通常,除非已达到某些资源限制(例如, worker_connections限制) ,否则该参数值相同。
requests
客户端请求的总数。
Reading
nginx 正在读取请求标头的当前连接数。
Writing
nginx 将响应写回客户端的当前连接数。
Waiting
当前等待请求的空闲客户端连接数。
# 注意
一个tcp连接,可以发起多个http请求
可以通过修改保持连接参数修改
keepalive_timeout 0; 表示关闭长连接
2.看下你的nginx支持这个模块吗
nginx -V
3.配置文件
cat >/etc/nginx/conf.d/status.conf<<EOF
server{
listen 9999;
server_name localhost;
stub_status on;
access_log off;
}
EOF
重启
[root@web-9 /var/log/nginx]#systemctl restart nginx
4.访问状态
五、基于IP的访问限制
模块
http://nginx.org/en/docs/http/ngx_http_access_module.html
以下是一个使用 Mermaid 绘制的关于 nginx ngx_http_access_module
工作流程的图示,包含代码和详细解释。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef module fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef allowed fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
classDef denied fill:#FFCDD2,stroke:#F44336,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C(ngx_http_access_module 检查):::module
C --> D{是否有访问规则配置}:::decision
D -->|否| E(允许访问):::allowed
D -->|是| F{是否匹配 allow 规则}:::decision
F -->|是| E
F -->|否| G{是否匹配 deny 规则}:::decision
G -->|是| H(拒绝访问,返回 403):::denied
G -->|否| E
E --> I(正常处理请求):::nginx
H --> J(客户端收到 403 响应):::client
I --> K(返回响应给客户端):::nginx
K --> L(客户端接收正常响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器、其他应用程序等)向 Nginx 服务器发送 HTTP 请求,请求访问特定的资源。
2. Nginx 接收请求
Nginx 监听指定的端口,接收到客户端的请求后,开始对请求进行处理。ngx_http_access_module
模块会参与到这个处理流程中,负责检查客户端的访问权限。
3. 检查访问规则配置
- 无访问规则配置:如果在 Nginx 配置文件中没有针对该请求路径配置任何
allow
或deny
规则,ngx_http_access_module
会默认允许该请求访问,Nginx 会正常处理该请求。 - 有访问规则配置:如果存在访问规则配置,模块会进一步检查客户端的 IP 地址是否匹配这些规则。
4. 匹配 allow
规则
模块首先检查客户端的 IP 地址是否匹配 allow
规则。如果匹配,说明客户端被允许访问,Nginx 会正常处理该请求。
5. 匹配 deny
规则
如果客户端的 IP 地址不匹配 allow
规则,模块会接着检查是否匹配 deny
规则。如果匹配,Nginx 会拒绝该请求,并向客户端返回 403 Forbidden 错误响应。
6. 无匹配规则
如果客户端的 IP 地址既不匹配 allow
规则,也不匹配 deny
规则,ngx_http_access_module
会默认允许该请求访问,Nginx 会正常处理该请求。
7. 处理请求并返回响应
- 允许访问:Nginx 正常处理请求,将处理结果作为响应返回给客户端。
- 拒绝访问:客户端会收到 403 Forbidden 错误响应,表示没有权限访问该资源。
Nginx 配置示例
以下是一个简单的 Nginx 配置示例,展示如何使用 ngx_http_access_module
进行访问控制:
server {
listen 80;
server_name example.com;
location /admin {
allow 192.168.1.0/24; # 允许 192.168.1.0 - 192.168.1.255 的 IP 访问
deny all; # 拒绝其他所有 IP 访问
}
location / {
# 没有访问规则配置,默认允许所有访问
root /var/www/html;
index index.html;
}
}
在这个配置中,只有 IP 地址在 192.168.1.0/24
网段的客户端才能访问 /admin
路径下的资源,其他客户端会被拒绝访问。对于根路径 /
,由于没有配置访问规则,所有客户端都可以正常访问。
1.配置语法
句法: allow address | CIDR | unix: | all;
默认: —
语境: http, server, location,limit_except
允许访问指定的网络或地址。如果指定了特殊值unix:(1.5.1),则允许访问所有 UNIX 域套接字。
句法: deny address | CIDR | unix: | all;
默认: —
语境: http, server, location,limit_except
拒绝对指定网络或地址的访问。如果指定了特殊值unix:(1.5.1),则拒绝所有 UNIX 域套接字的访问。
2.拒绝windows访问www域名
[root@web-9 /etc/nginx/conf.d]#cat www.yuchaoit.conf
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
access_log /var/log/nginx/www.yuchaoit.log;
error_log /var/log/nginx/error.www.yuchaoit.log;
error_page 404 /404.html;
location / {
root /usr/share/nginx/html/game;
index index.html index.htm;
deny 10.0.0.1;
allow all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
但是虚拟机,走内网环境是可以通的。
3.只允许windows访问,其他人拒绝
注意allow和deny的加载顺序是,自上而下加载;
[root@web-9 /etc/nginx/conf.d]#cat www.yuchaoit.conf
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
access_log /var/log/nginx/www.yuchaoit.log;
error_log /var/log/nginx/error.www.yuchaoit.log;
error_page 404 /404.html;
location / {
root /usr/share/nginx/html/game;
index index.html index.htm;
allow 10.0.0.1;
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
windows可访问
linux不可访问
六、基于用户认证的访问限制
有时候,我们一些站点内容想要进行授权查看,只能输入账号密码之后才能访问,例如一些重要的内网平台,CRM,CMDB,企业内部WIKI等等。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef module fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef auth fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
classDef unauth fill:#FFCDD2,stroke:#F44336,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C(ngx_http_auth_basic_module 介入):::module
C --> D{是否开启基本认证}:::decision
D -->|否| E(正常处理请求):::nginx
D -->|是| F(发送 401 响应并要求认证):::nginx
F --> G(客户端收到 401 响应):::client
G --> H(客户端输入用户名和密码):::client
H --> I(客户端发送认证请求):::client
I --> J(Nginx 接收认证请求):::nginx
J --> K(验证用户名和密码):::module
K --> L{认证是否成功}:::decision
L -->|是| E
L -->|否| M(发送 403 响应):::nginx
M --> N(客户端收到 403 响应):::client
E --> O(返回正常响应给客户端):::nginx
O --> P(客户端接收正常响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器等)向 Nginx 服务器发送请求,尝试访问受保护的资源。
2. Nginx 接收请求
Nginx 接收到客户端的请求后,ngx_http_auth_basic_module
开始介入处理,判断是否对该请求开启了基本认证。
3. 判断是否开启基本认证
- 未开启:若未开启基本认证,Nginx 会像处理普通请求一样,直接对请求进行正常处理。
- 已开启:Nginx 会向客户端发送一个 401 状态码的响应,同时在响应头中包含
WWW - Authenticate
字段,提示客户端需要进行基本认证。
4. 客户端处理 401 响应
客户端收到 401 响应后,浏览器通常会弹出一个认证对话框,要求用户输入用户名和密码。用户输入信息后,客户端会将用户名和密码进行 Base64 编码,然后再次向 Nginx 发送认证请求。
5. 认证过程
- 接收认证请求:Nginx 接收客户端发送的认证请求,从中提取编码后的用户名和密码信息。
- 验证用户名和密码:
ngx_http_auth_basic_module
会将接收到的信息与预先配置的用户信息(存储在密码文件中)进行比对验证。
6. 认证结果处理
- 认证成功:如果用户名和密码验证通过,Nginx 会正常处理该请求,并将处理结果作为正常响应返回给客户端。
- 认证失败:若验证不通过,Nginx 会向客户端发送 403 状态码的响应,表示客户端没有权限访问该资源。
Nginx 配置示例
server {
listen 80;
server_name example.com;
location /protected {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
在上述配置中,/protected
路径开启了基本认证,提示信息为 "Restricted Area",用户信息存储在 /etc/nginx/.htpasswd
文件中。
1.语法
https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
句法: auth_basic string | off;
默认:
auth_basic 关闭;
语境: http, server, location,limit_except
启用使用“HTTP 基本身份验证”协议验证用户名和密码。
指定的参数用作realm. 参数值可以包含变量(1.3.10、1.2.7)。
特殊值off取消了auth_basic从先前配置级别继承的指令的效果。
句法: auth_basic_user_file file;
默认: —
语境: http, server, location,limit_except
2.创建密码文件
htpasswd是Apache密码生成工具,Nginx支持auth_basic认证,因此我门可以将生成的密码用于Nginx中,输入一行命令即可安装:
yum -y install httpd-tools
参数
-c 创建passwdfile.如果passwdfile 已经存在,那么它会重新写入并删去原有内容.
-b 命令行中一并输入用户名和密码而不是根据提示输入密码,可以看见明文,不需要交互
#创建认证文件,htpasswd -bc .access username password
#在当前目录生成.access文件,用户名username,密码:password,默认采用MD5加密方式。
具体操作
[root@web-9 ~]#htpasswd -b -c /etc/nginx/auth_passwd yuchao01 yuchao666
Adding password for user yuchao01
3.nginx调用密码文件
[root@web-9 ~]#cat /etc/nginx/conf.d/www.yuchaoit.conf
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
access_log /var/log/nginx/www.yuchaoit.log;
error_log /var/log/nginx/error.www.yuchaoit.log;
error_page 404 /404.html;
location / {
root /usr/share/nginx/html/game;
index index.html index.htm;
auth_basic "yuchaoit.cn welcomes you";
auth_basic_user_file /etc/nginx/auth_passwd;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
4.访问测试
只有www.yuchaoit.cn站点被加了密码。
其他未设置认证的可以直接访问。
七、nginx请求限制
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef module fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef allowed fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
classDef blocked fill:#FFCDD2,stroke:#F44336,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C(ngx_http_limit_req_module 处理):::module
C --> D{是否定义请求限制规则}:::decision
D -->|否| E(正常处理请求):::allowed
D -->|是| F(检查请求速率):::module
F --> G{请求速率是否超过限制}:::decision
G -->|否| E
G -->|是| H{是否设置 burst 缓冲}:::decision
H -->|否| I(返回 503 服务不可用):::blocked
H -->|是| J{burst 缓冲是否已满}:::decision
J -->|是| I
J -->|否| K(将请求放入 burst 缓冲):::module
K --> L(等待队列中的请求依次处理):::module
E --> M(正常响应客户端):::nginx
I --> N(客户端收到 503 响应):::client
M --> O(客户端接收正常响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器、爬虫程序等)向 Nginx 服务器发送 HTTP 请求。
2. Nginx 接收请求
Nginx 监听相应端口,接收到客户端的请求后,ngx_http_limit_req_module
开始介入处理该请求。
3. 判断是否定义请求限制规则
- 未定义规则:如果在 Nginx 配置中没有针对该请求路径或特定条件定义请求限制规则,Nginx 会像处理普通请求一样,直接正常处理该请求。
- 已定义规则:模块会根据配置的规则对请求速率进行检查。
4. 检查请求速率
ngx_http_limit_req_module
会统计客户端的请求速率,将当前请求的速率与配置中设定的速率限制进行对比。
5. 判断请求速率是否超过限制
- 未超过限制:若请求速率在允许的范围内,Nginx 会正常处理该请求,并将处理结果作为正常响应返回给客户端。
- 超过限制:当请求速率超过设定的限制时,模块会进一步判断是否设置了
burst
缓冲。
6. 处理超过速率限制的请求
- 未设置 burst 缓冲:如果没有设置
burst
缓冲,Nginx 会直接向客户端返回 503 服务不可用的响应,表示服务器暂时无法处理该请求。 - 设置了 burst 缓冲:
- 缓冲已满:若
burst
缓冲已经满了,同样会返回 503 响应。 - 缓冲未满:将该请求放入
burst
缓冲队列中,队列中的请求会依次被处理,这样可以在一定程度上允许短时间内的突发请求。
- 缓冲已满:若
Nginx 配置示例
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
server {
listen 80;
server_name example.com;
location / {
limit_req zone=mylimit burst=5;
# 其他配置
}
}
}
在上述配置中,limit_req_zone
定义了一个名为 mylimit
的请求限制区域,基于客户端的 IP 地址($binary_remote_addr
),分配 10MB 的内存空间,速率限制为每秒 1 个请求。在 location
块中使用 limit_req
指令应用该限制,并设置 burst
缓冲为 5,即允许短时间内最多有 5 个突发请求进入缓冲队列。
nginx限流实战
以下是基于不同场景的 Nginx 限流配置案例及详细说明:
一、基础限流类型
1. 按请求速率限流(漏桶算法)
http {
limit_req_zone $binary_remote_addr zone=req_perip:10m rate=10r/s;
server {
location /api/ {
limit_req zone=req_perip burst=20 nodelay;
proxy_pass http://backend;
}
}
}
- 作用:限制同一客户端 IP 每秒最多处理 10 个请求,允许突发 20 个请求(
burst
),超出直接返回 503 - 关键参数:
rate=10r/s
:每秒 10 个请求(实际按毫秒计算,即 1 请求/100ms)burst=20
:允许瞬间堆积 20 个请求nodelay
:不延迟处理突发请求,直接快速响应前 20 个
2. 按并发连接数限流
http {
limit_conn_zone $binary_remote_addr zone=conn_perip:10m;
server {
location /download/ {
limit_conn conn_perip 5; # 每个 IP 并发连接数 ≤5
limit_rate 500k; # 限速 500KB/s
alias /data/files/;
}
}
}
- 适用场景:防止单个用户大量下载占用带宽
二、高级限流场景
1. 多维度联合限流(IP + URL)
http {
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
limit_req_zone $server_name$uri zone=perurl:10m rate=2r/s;
server {
location ~ ^/api/(.*) {
limit_req zone=perip burst=10;
limit_req zone=perurl burst=5;
proxy_pass http://api_backend;
}
}
}
- 效果:同时限制:
- 每个 IP 对全站请求 ≤5r/s
- 每个 URL 的总请求 ≤2r/s
2. 灰度放量(按百分比限流)
map $remote_addr $limit_prob {
default "0%"; # 默认不限流
~^192.168.1. "30%"; # 内网 IP 30% 概率限流
}
server {
location / {
set $limit_rate 100k; # 限速 100KB/s
if ($limit_prob) {
limit_rate_after 1m; # 下载超过 1MB 后触发限速
}
# 其他配置...
}
}
- 用途:逐步验证限流策略对特定用户群体的影响
三、特殊场景案例
1. 防御 CC 攻击
http {
limit_req_zone $binary_remote_addr zone=cc_defense:10m rate=30r/m;
server {
location / {
# 第一阶段:宽松限流
limit_req zone=cc_defense burst=10;
# 第二阶段:频繁触发则封锁 IP(需配合 fail2ban)
access_by_lua_block {
local lim = ngx.shared.limit_dict
local key = ngx.var.binary_remote_addr
local req = lim:get(key) or 0
if req > 50 then # 1 分钟内超过 50 次请求
ngx.exit(444) # 静默丢弃连接
end
lim:incr(key, 1, 60) # 计数器有效期 60 秒
}
}
}
}
2. 下载限速动态调整
map $http_user_agent $download_speed {
~Wget 100k; # wget 用户限速 100KB/s
~curl 200k; # curl 用户限速 200KB/s
default 500k; # 其他客户端 500KB/s
}
server {
location /download/ {
limit_rate $download_speed;
limit_conn perip 3;
}
}
四、调试与监控
1. 实时查看限流状态
http {
vhost_traffic_status_zone;
server {
location /status {
vhost_traffic_status_display;
access_log off;
allow 192.168.0.0/16;
deny all;
}
}
}
- 输出指标:
limit_req_status
:触发限流的请求数limit_conn_status
:触发连接限制数
2. 日志记录触发事件
http {
log_format limiter '$time_iso8601 | $remote_addr | $http_user_agent | '
'$limit_req_status | $limit_conn_status';
server {
access_log /var/log/nginx/limit.log limiter;
}
}
- 日志字段:
limit_req_status
:PASSED/DELAYED/REJECTEDlimit_conn_status
:PASSED/REJECTED
五、常见问题处理
1. 误杀正常用户
解决方案:
geo $whitelist { default 0; 192.168.0.0/24 1; # 内网 IP 不限流 10.0.0.0/8 1; # 专线网络 } map $whitelist $limit_key { 1 ""; # 白名单不参与限流 0 $binary_remote_addr; } limit_req_zone $limit_key zone=dynamic:10m rate=10r/s;
2. 应对代理服务器(X-Forwarded-For)
real_ip_header X-Forwarded-For;
set_real_ip_from 10.0.0.0/8;
limit_req_zone $binary_remote_addr zone=realip:10m rate=10r/s;
六、性能调优参数
参数 | 建议值 | 说明 |
---|---|---|
limit_req_zone size |
1MB ≈ 16,000 IP | 内存分配公式:1MB = 16,000 IP(64字节/IP) |
limit_conn_zone size |
1MB ≈ 8,000 IP | 1MB = 8,000 IP(128字节/IP) |
burst |
rate × 2 | 突发容量建议为基准速率的 2-5 倍 |
limit_req_status |
529 | 自定义返回状态码(默认 503) |
七、压力测试命令
# 测试并发能力(100 并发,持续 30 秒)
wrk -t12 -c100 -d30s http://example.com/api/
# 触发限流观察效果(每秒 20 请求)
siege -c20 -t1M http://example.com/api/
总结选型建议
- 常规防护:
limit_req
+burst
+nodelay
- 下载站/大文件:
limit_conn
+limit_rate
- API 接口:多维度联合限流(IP + URL)
- 高安全场景:Lua + Redis 实现分布式限流
1.官网模块
https://nginx.org/en/docs/http/ngx_http_limit_req_module.html
2.配置语法
限速规则语法
https://docshome.gitbook.io/nginx-docs/he-xin-gong-neng/http/ngx_http_limit_req_module
ngx_http_limit_req_module 模块(0.7.21)用于限制每个已定义 key 的请求处理速率,特别是来自单个 IP 地址请求的处理速率。限制机制采用了 leaky bucket (漏桶算法)方法完成。
3.参数示例
# 1.定义一个限速规则
# 定义限速区域,保持在10兆字节的区域one,该区域的平均处理请求每秒不能超过1个。
# $binary_remote_addr 变量的大小始终为 4 个字节,在64位机器上始终占用64字节
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=two:10m rate=1r/s;
参数解释
limit_req_zone # 引用限速模块
binary_remote_addr # 判定条件,远程的客户端IP
zone # 定义限速区域名称,内存大小
rate # 限速规则,1秒只能1个请求
# 2.引用限速规则
limit_req zone=two burst=5;
limit_req # 引用哪一个限速区域
burst=5 # 令牌桶、平均每秒不超过 1 个请求,并且突发不超过5个请求。
nodelay # 如果不希望排队堆积的请求过多,可以用这个参数。
4.实际用法
- 限速规则是1秒一个请求
- 提供3个vip特殊名额
[root@web-9 /etc/nginx/conf.d]#cat www.yuchaoit.conf
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
access_log /var/log/nginx/www.yuchaoit.log;
error_log /var/log/nginx/error.www.yuchaoit.log;
error_page 404 /404.html;
limit_req zone=one burst=3 nodelay;
location / {
root /usr/share/nginx/html/game; index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
5.访问测试
正常限速内
[root@master-61 ~]#for i in {1..10};do curl -I www.yuchaoit.cn;sleep 1;done
超速访问情况
[root@master-61 ~]#for i in {1..20};do curl -I www.yuchaoit.cn;sleep 0.5 ;done
八、nginx内置变量
官网
https://nginx.org/en/docs/varindex.html
Nginx 内置变量提供了丰富的信息,可用于日志记录、访问控制、请求处理等多种场景。以下是对常见 Nginx 内置变量的表格总结:
客户端相关变量
变量名 | 描述 | 示例 |
---|---|---|
$remote_addr |
客户端的 IP 地址 | 192.168.1.100 |
$remote_user |
客户端用户的名称,用于 HTTP 基本认证,未认证时为空 | username |
$http_user_agent |
客户端使用的用户代理信息,包含浏览器、操作系统等 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 |
$http_referer |
客户端请求的来源页面的 URL | https://www.example.com/page1.html |
$http_x_forwarded_for |
在使用反向代理时,记录客户端的真实 IP 地址,多个 IP 用逗号分隔 | 192.168.1.100, 10.0.0.1 |
请求相关变量
变量名 | 描述 | 示例 |
---|---|---|
$request |
完整的 HTTP 请求行,包含请求方法、URI 和 HTTP 版本 | GET /index.html HTTP/1.1 |
$request_method |
HTTP 请求方法 | GET |
$request_uri |
客户端请求的完整 URI,包括路径和查询参数 | /products?category=electronics |
$query_string |
请求 URI 中的查询参数部分,不包括 ? 符号 |
category=electronics |
$uri |
经过解码和规范化处理后的请求 URI | /products |
$document_uri |
等同于 $uri |
/products |
$args |
请求中的查询参数 | category=electronics |
响应相关变量
变量名 | 描述 | 示例 |
---|---|---|
$status |
HTTP 响应状态码 | 200 |
$body_bytes_sent |
发送给客户端的响应体的字节数,不包括响应头 | 1234 |
$sent_http_<header> |
发送给客户端的指定响应头的值,<header> 为响应头名称 |
$sent_http_content_type 可能返回 text/html |
时间相关变量
变量名 | 描述 | 示例 |
---|---|---|
$time_local |
请求处理完成的本地时间,格式为 [日/月/年:时:分:秒 +时区] |
15/Jul/2023:10:30:45 +0800 |
$request_time |
处理请求所花费的时间,单位为秒,精确到毫秒 | 0.023 |
服务器相关变量
变量名 | 描述 | 示例 |
---|---|---|
$server_name |
处理请求的虚拟主机的名称 | www.example.com |
$server_addr |
服务器的 IP 地址 | 10.0.0.2 |
$server_port |
服务器监听的端口号 | 80 |
$server_protocol |
请求使用的协议版本 | HTTP/1.1 |
上游服务器相关变量(用于反向代理)
变量名 | 描述 | 示例 |
---|---|---|
$upstream_addr |
上游服务器的地址和端口 | 10.0.0.3:8080 |
$upstream_response_time |
上游服务器的响应时间 | 0.05 |
$upstream_status |
上游服务器返回的状态码 | 200 |
其他变量
变量名 | 描述 | 示例 |
---|---|---|
$hostname |
Nginx 服务器的主机名 | nginx-server |
$pid |
Nginx 工作进程的进程 ID | 1234 |
$msec |
当前时间,单位为毫秒 | 1692352800.123 |
这些变量可以在 Nginx 配置文件的不同指令中使用,例如 log_format
、if
语句、rewrite
规则等,以实现各种定制化的功能。
该文档还写明了,这些变量对应了哪些模块。
学这些内置nginx变量,目的是为了在配置文件中使用,如
- 日志功能会用
- url跳转时用
- 等
$args #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr #获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间; 从读取客户端的第一个字节开始计时
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie
$http_post
$http_referer
$http_user_agent
$http_x_forwarded_for
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding
九、nginx添加第三方模块
以下是使用 Mermaid 绘制的 Nginx 安装三方模块的流程图,同时会附上代码和详细解释。
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef action fill:#E8F5E9,stroke:#81C784,stroke-width:2px
A(确定需求):::process --> B(选择三方模块):::process
B --> C{模块是否支持编译安装}:::decision
C -->|是| D(下载 Nginx 源码):::process
C -->|否| E(查找其他安装方式):::process
D --> F(下载三方模块源码):::process
F --> G(解压 Nginx 源码):::process
G --> H(解压三方模块源码):::process
H --> I(配置编译参数):::process
I --> J(添加三方模块配置):::action
J --> K(编译 Nginx):::process
K --> L(安装编译后的 Nginx):::process
L --> M{安装是否成功}:::decision
M -->|是| N(验证模块功能):::process
M -->|否| O(排查安装问题):::process
O --> I(重新配置编译参数):::process
N --> P(重启 Nginx 服务):::process
E --> Q(考虑使用 Docker 或包管理器):::process
Q --> R(按对应方式安装):::process
R --> M
图示解释
1. 确定需求与选择模块
- 确定需求:明确在 Nginx 中需要使用三方模块来实现的具体功能,例如增强安全防护、实现特定的缓存策略等。
- 选择三方模块:根据需求在开源社区或相关资源中挑选合适的三方模块。
2. 判断安装方式
- 是否支持编译安装:检查所选模块是否支持通过编译 Nginx 源码的方式进行安装。如果支持,则进入编译安装流程;如果不支持,则寻找其他安装途径。
3. 编译安装流程
- 下载源码:分别下载 Nginx 官方源码和三方模块的源码。
- 解压源码:将下载的 Nginx 源码和三方模块源码进行解压。
- 配置编译参数:进入 Nginx 源码目录,使用
./configure
命令配置编译参数。 - 添加三方模块配置:在
./configure
命令中添加三方模块的配置选项,指定模块的路径。例如,如果模块解压到/path/to/module
,则可以使用--add-module=/path/to/module
来添加该模块。 - 编译 Nginx:运行
make
命令进行编译。 - 安装编译后的 Nginx:使用
make install
命令将编译好的 Nginx 安装到系统中。
4. 安装结果处理
- 安装是否成功:检查安装过程是否出现错误,判断模块是否成功安装。
- 安装成功:验证模块的功能是否正常工作,可以通过访问 Nginx 服务,检查是否实现了预期的功能。
- 安装失败:排查安装过程中出现的问题,可能是编译参数配置错误、依赖库缺失等原因,解决问题后重新配置编译参数并进行编译安装。
5. 其他安装方式
如果模块不支持编译安装,可以考虑使用 Docker 容器或系统的包管理器进行安装,按照相应的方式完成安装后再检查安装结果。
6. 重启服务
在确认模块安装成功且功能正常后,重启 Nginx 服务,使配置生效。
示例代码
以下是一个简单的编译安装示例:
# 下载 Nginx 源码
wget http://nginx.org/download/nginx-1.23.4.tar.gz
tar -zxvf nginx-1.23.4.tar.gz
# 下载三方模块源码
git clone https://github.com/someuser/somemodule.git
# 配置编译参数并添加三方模块
cd nginx-1.23.4
./configure --add-module=../somemodule
# 编译和安装
make
make install
通过以上流程和示例,你可以清晰地了解 Nginx 安装三方模块的过程。
1.理念
nginx除了支持内置模块,还支持第三方模块,但是第三方模块需要重新编译进nginx。
(重新生成nginx二进制命令)
1.如你的nginx默认不支持https
2.给你的nginx添加echo模块,用于打印nginx的变量。
添加echo三方模块脚本
#!/bin/bash
# 设置变量
NGINX_VERSION="1.24.0"
MODULE_NAME="echo-nginx-module"
MODULE_REPO="https://github.com/openresty/${MODULE_NAME}.git"
INSTALL_PATH="/usr/local/nginx"
# 安装依赖
sudo apt update && sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev git
# 下载 Nginx 源码
cd /usr/local/src || exit
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -xzvf nginx-${NGINX_VERSION}.tar.gz
cd nginx-${NGINX_VERSION} || exit
# 克隆第三方模块
cd /usr/local/src || exit
git clone ${MODULE_REPO}
# 配置编译选项
cd nginx-${NGINX_VERSION} || exit
./configure \
--prefix=${INSTALL_PATH} \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gzip_static_module \
--add-module=/usr/local/src/${MODULE_NAME}
# 编译 & 安装
make -j$(nproc)
sudo make install
# 验证 Nginx 是否安装成功
${INSTALL_PATH}/sbin/nginx -V
验证echo模块
要验证 echo-nginx-module
是否正常工作,可以按照以下步骤操作:
1. 配置 Nginx 以使用 echo
模块
编辑 Nginx 配置文件,通常位于 /usr/local/nginx/conf/nginx.conf
,添加如下配置:
server {
listen 8080;
server_name localhost;
location /echo {
echo "Hello, Nginx Echo Module!";
}
location /echo_var {
echo "Request Method: $request_method";
echo "Request URI: $request_uri";
}
}
2. 启动或重启 Nginx
sudo /usr/local/nginx/sbin/nginx -s reload
如果是首次启动:
sudo /usr/local/nginx/sbin/nginx
3. 测试 echo
模块
使用 curl
进行测试:
curl http://localhost:8080/echo
返回:
Hello, Nginx Echo Module!
测试变量:
curl http://localhost:8080/echo_var
返回:
Request Method: GET
Request URI: /echo_var
这样你就可以确认 echo-nginx-module
是否正常工作了。
2.编译添加echo模块
echo-nginx-module
模块可以在Nginx中用来输出一些信息,可以用来实现简单接口或者排错。
由于网络问题,建议该模块可以手动下载,编译安装
# 1.模块网址 https://github.com/openresty/echo-nginx-module
yum -y install gcc-c++
yum -y install pcre pcre-devel
yum -y install zlib zlib-devel
yum -y install openssl openssl-devel
# 3.准备好nginx编译环境
yum install pcre pcre-devel openssl openssl-devel zlib zlib-devel gzip gcc gcc-c++ make wget httpd-tools vim -y
groupadd www -g 666
useradd www -u 666 -g 666 -M -s /sbin/nologin
mkdir -p /yuchaoit/ ; cd /yuchaoit/
# 下载echo模块
yum install git -y
git clone https://github.com/openresty/echo-nginx-module.git
# 4.编译nginx
wget http://nginx.org/download/nginx-1.19.0.tar.gz
tar -zxf nginx-1.19.0.tar.gz
cd nginx-1.19.0
./configure \
--user=www \
--group=www \
--prefix=/opt/nginx-1-19-0 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre \
--add-module=/yuchaoit/echo-nginx-module
# 5.编译且安装
make && make install
# 6.创建快捷方式
ln -s /opt/nginx-1-19-0/sbin/nginx /usr/sbin/
# 7.验证模块
nginx -V
3.创建新配置文件,验证echo模块
[root@web-9 /etc/nginx/conf.d]#cat echo.conf
server {
listen 11444;
server_name localhost;
charset utf-8;
location / {
echo "yuchaoit.cn welcome you!";
echo $uri;
echo $document_uri;
echo $remote_addr;
echo $remote_port;
echo $http_user_agent;
}
}
4.客户端访问
[root@master-61 ~]#curl 10.0.0.9:11444/hello_chaoge
yuchaoit.cn welcome you!
/hello_chaoge
/hello_chaoge
10.0.0.61
42378
curl/7.29.0
十、nginx location高级实战
location是nginx的核心重要功能,可以设置网站的访问路径,一个web server会有多个路径,那么location就得设置多个。
Nginx的locaiton作用是根据用户请求的URI不同,来执行不同的应用。
针对用户请求的网站URL进行匹配,匹配成功后进行对应的操作。
官网文档
https://nginx.org/en/docs/http/ngx_http_core_module.html#location
以下是使用 Mermaid 绘制的 Nginx location
指令工作流程的图示,同时会给出代码和详细解释。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef location fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef action fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C{匹配 location 块}:::decision
C -->|精确匹配| D([精确 location 块]):::location
C -->|前缀匹配| E([前缀 location 块]):::location
C -->|正则匹配| F([正则 location 块]):::location
C -->|无匹配| G([默认 location 块]):::location
D --> H(执行精确块配置):::action
E --> I(执行前缀块配置):::action
F --> J(执行正则块配置):::action
G --> K(执行默认块配置):::action
H --> L(处理请求):::nginx
I --> L
J --> L
K --> L
L --> M(返回响应给客户端):::nginx
M --> N(客户端接收响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器)向 Nginx 服务器发送 HTTP 请求,请求特定的资源。
2. Nginx 接收请求
Nginx 监听指定的端口,接收到客户端的请求后,开始进行处理,首要任务是匹配合适的 location
块。
3. 匹配 location
块
Nginx 会根据请求的 URI 按照一定的规则去匹配不同类型的 location
块:
- 精确匹配:如果请求的 URI 与某个
location
块的精确匹配规则完全一致,就会选择该精确location
块进行处理。精确匹配使用=
符号,例如location = /exact/path
。 - 前缀匹配:当请求的 URI 以某个
location
块的前缀匹配规则开头时,会选择该前缀location
块。前缀匹配可以使用普通的路径,如location /prefix
。 - 正则匹配:若请求的 URI 符合某个
location
块的正则表达式规则,就会选择该正则location
块。正则匹配使用~
(区分大小写)或~*
(不区分大小写)符号,例如location ~ \.(jpg|png)$
。 - 无匹配:如果请求的 URI 不匹配任何精确、前缀或正则
location
块,Nginx 会使用默认的location
块进行处理。
4. 执行配置和处理请求
根据匹配到的 location
块,Nginx 会执行该块中配置的指令,如设置根目录、重定向、代理请求等。然后对请求进行相应的处理。
5. 返回响应
处理完请求后,Nginx 会将处理结果作为响应返回给客户端,客户端接收该响应。
Nginx 配置示例
server {
listen 80;
server_name example.com;
# 精确匹配
location = /exact {
return 200 "This is an exact match.";
}
# 前缀匹配
location /prefix {
root /var/www/prefix;
}
# 正则匹配
location ~ \.(jpg|png)$ {
expires 30d;
}
# 默认匹配
location / {
root /var/www/html;
index index.html;
}
}
在这个配置中,不同类型的 location
块展示了如何根据请求的 URI 进行匹配和处理。
5.实际工作使用
在生产环境中,Nginx 的 location
指令有很多实用场景,以下为你详细介绍几个常见的生产案例:
1. 静态资源服务
在生产环境中,很多网站都有大量的静态资源,如图片、CSS、JavaScript 文件等。使用 location
指令可以高效地为这些静态资源提供服务。
server {
listen 80;
server_name example.com;
# 处理静态图片资源
location ~* \.(jpg|jpeg|png|gif|ico)$ {
root /var/www/html/static/images;
expires 30d; # 设置缓存过期时间为 30 天
access_log off; # 关闭访问日志记录,减少磁盘 I/O
}
# 处理 CSS 和 JavaScript 资源
location ~* \.(css|js)$ {
root /var/www/html/static/assets;
expires 7d; # 设置缓存过期时间为 7 天
add_header Cache-Control "public, max-age=604800";
}
# 默认处理
location / {
root /var/www/html;
index index.html;
}
}
解释:
location ~* \.(jpg|jpeg|png|gif|ico)$
:使用正则表达式匹配所有图片文件,将这些请求的根目录设置为/var/www/html/static/images
,并设置 30 天的缓存过期时间,同时关闭访问日志以减少磁盘 I/O。location ~* \.(css|js)$
:匹配 CSS 和 JavaScript 文件,将根目录设置为/var/www/html/static/assets
,设置 7 天的缓存过期时间,并添加Cache-Control
头。location /
:作为默认处理,将根目录设置为/var/www/html
,并指定默认索引文件为index.html
。
2. 反向代理
在生产环境中,常常会使用 Nginx 作为反向代理服务器,将客户端的请求转发到后端的应用服务器上。
server {
listen 80;
server_name example.com;
# 反向代理到后端 Node.js 应用
location /api {
proxy_pass http://backend_server:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 反向代理到后端 Python Flask 应用
location /app {
proxy_pass http://flask_server:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 静态页面服务
location / {
root /var/www/html;
index index.html;
}
}
解释:
location /api
:将所有以/api
开头的请求转发到后端的 Node.js 应用服务器(http://backend_server:3000
),并设置一些必要的请求头,如Host
、X-Real-IP
和X-Forwarded-For
,以便后端服务器获取客户端的真实信息。location /app
:将以/app
开头的请求转发到后端的 Python Flask 应用服务器(http://flask_server:5000
),同时设置 HTTP 版本和Upgrade
、Connection
头,适用于需要 WebSocket 支持的场景。location /
:处理其他请求,提供静态页面服务。
3. 访问控制
在生产环境中,有时需要对某些目录或资源进行访问控制,只允许特定的 IP 地址或用户访问。
server {
listen 80;
server_name example.com;
# 管理页面,只允许特定 IP 访问
location /admin {
allow 192.168.1.0/24; # 允许 192.168.1.0 - 192.168.1.255 的 IP 访问
deny all; # 拒绝其他所有 IP 访问
root /var/www/html/admin;
index index.html;
}
# 公共页面
location / {
root /var/www/html;
index index.html;
}
}
解释:
location /admin
:对于/admin
目录,只允许192.168.1.0/24
网段的 IP 地址访问,其他 IP 地址将被拒绝。根目录设置为/var/www/html/admin
,并指定默认索引文件为index.html
。location /
:处理其他请求,提供公共页面服务。
4. URL 重写
在生产环境中,可能需要对 URL 进行重写,以实现更好的用户体验或搜索引擎优化。
server {
listen 80;
server_name example.com;
# 旧 URL 重定向到新 URL
location /old-page {
return 301 /new-page;
}
# 动态 URL 重写
location /products {
rewrite ^/products/([0-9]+)$ /product?id=$1 last;
root /var/www/html;
}
# 默认处理
location / {
root /var/www/html;
index index.html;
}
}
解释:
location /old-page
:将所有访问/old-page
的请求永久重定向(301)到/new-page
。location /products
:使用rewrite
指令将动态 URL/products/123
重写为/product?id=123
,方便后端应用处理。location /
:处理其他请求,提供静态页面服务。
6. location的root和alias
绝大多数资料这里都讲错了。。看于超老师的真理玩法。
以下是使用 Mermaid 绘制的 Nginx location
中 root
和 alias
指令工作原理的图示,同时会给出相应代码和详细解释。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef location fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef root fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
classDef alias fill:#FFE0B2,stroke:#FF9800,stroke-width:2px
classDef file fill:#FFCDD2,stroke:#F44336,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C{匹配 location 块}:::nginx
C -->|使用 root| D([root location 块]):::location
C -->|使用 alias| E([alias location 块]):::location
D --> F(拼接 root 路径和请求 URI):::root
E --> G(替换 alias 路径):::alias
F --> H(查找文件):::file
G --> H
H -->|找到文件| I(返回文件内容):::nginx
H -->|未找到文件| J(返回 404 错误):::nginx
I --> K(客户端接收文件内容):::client
J --> L(客户端接收 404 错误):::client
图示解释
1. 客户端发起请求
客户端(如浏览器)向 Nginx 服务器发送 HTTP 请求,请求特定的资源。
2. Nginx 接收请求并匹配 location
块
Nginx 监听指定端口,接收到请求后,根据请求的 URI 匹配相应的 location
块。匹配到的 location
块可能使用了 root
或 alias
指令。
3. root
指令处理流程
- 拼接路径:当匹配到使用
root
指令的location
块时,Nginx 会将root
指令指定的路径和请求的 URI 直接拼接起来。例如,若root
为/var/www/html
,请求的 URI 为/images/logo.png
,则最终查找的路径为/var/www/html/images/logo.png
。 - 查找文件:根据拼接后的路径在文件系统中查找对应的文件。
4. alias
指令处理流程
- 替换路径:若匹配到使用
alias
指令的location
块,Nginx 会将location
块中匹配的部分替换为alias
指令指定的路径。例如,location /images/
且alias /data/pictures/
,请求的 URI 为/images/logo.png
,则最终查找的路径为/data/pictures/logo.png
。 - 查找文件:同样在文件系统中查找替换路径后对应的文件。
5. 文件查找结果处理
- 找到文件:如果在文件系统中找到了对应的文件,Nginx 会将文件内容返回给客户端。
- 未找到文件:若未找到文件,Nginx 会向客户端返回 404 错误。
Nginx 配置示例
使用 root
指令
server {
listen 80;
server_name example.com;
location /images/ {
root /var/www/html;
}
}
对于请求 /images/logo.png
,Nginx 会查找 /var/www/html/images/logo.png
。
使用 alias
指令
server {
listen 80;
server_name example.com;
location /images/ {
alias /data/pictures/;
}
}
对于请求 /images/logo.png
,Nginx 会查找 /data/pictures/logo.png
。
通过上述图示和示例,你可以更清晰地理解 root
和 alias
指令在 Nginx location
中的工作原理。
7.root、alias实践。
在 Nginx 中,root
和 alias
用于指定文件路径,但它们的行为不同,容易混淆。下面是详细的实践说明和示例。
root vs alias
指令 | 作用 |
---|---|
root |
设置根目录,路径会附加 location 之后的部分 |
alias |
直接指定目标路径,会替换 location |
示例 1:使用 root
server {
listen 80;
server_name localhost;
root /var/www/html; # 设置网站根目录
location /images/ {
root /var/www; # 目标路径 = /var/www + /images/xxx
}
}
请求 http://localhost/images/logo.png
,实际访问的路径是:
/var/www/images/logo.png
注意:root
会将 location
之后的路径拼接到 root
指定的目录后面。
示例 2:使用 alias
server {
listen 80;
server_name localhost;
location /images/ {
alias /var/www/static/; # 目标路径 = /var/www/static/xxx
}
}
请求 http://localhost/images/logo.png
,实际访问的路径是:
/var/www/static/logo.png
注意:alias
直接替换 location
,不会附加 location
的路径。
root vs alias对比
请求路径 | root 处理路径 |
alias 处理路径 |
---|---|---|
/images/logo.png |
/var/www/images/logo.png |
/var/www/static/logo.png |
示例 3:alias 必须以 /
结尾
如果 alias
省略 /
,可能会导致路径错误。例如:
location /static/ {
alias /var/www/static; # 错误用法
}
请求 /static/logo.png
实际路径变成 /var/www/staticlogo.png
(缺少 /
),正确写法是:
location /static/ {
alias /var/www/static/; # 需要以 `/` 结尾
}
总结
root
会拼接location
之后的部分路径,适用于/
目录的配置。alias
完全替换location
目录,适用于特定的目录映射。alias
指定的路径必须以/
结尾,以防止路径拼接错误。
你可以根据实际需求选择 root
或 alias
,避免路径解析错误。
8.图解root、alias
老铁们,我做的对吗?
十一、nginx rewrite跳转(高级)
官网
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
该ngx_http_rewrite_module模块用于使用 PCRE 正则表达式更改请求 URI、返回重定向和条件选择配置。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef rewrite fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef action fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C{是否有 rewrite 规则}:::decision
C -->|否| D(按原始请求处理):::nginx
C -->|是| E(匹配 rewrite 规则):::rewrite
E --> F{是否匹配成功}:::decision
F -->|否| D
F -->|是| G(执行 rewrite 动作):::action
G --> H{rewrite 类型}:::decision
H -->|临时重定向 302| I(返回 302 重定向响应):::nginx
H -->|永久重定向 301| J(返回 301 重定向响应):::nginx
H -->|内部重写 last| K(内部重新匹配 location):::nginx
H -->|内部重写 break| L(停止当前 location 块内后续 rewrite 检查):::nginx
I --> M(客户端接收 302 响应并跳转):::client
J --> N(客户端接收 301 响应并跳转):::client
K --> C
L --> D
D --> O(处理请求并返回响应):::nginx
O --> P(客户端接收响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器)向 Nginx 服务器发送 HTTP 请求。
2. Nginx 接收请求并检查规则
- 是否有 rewrite 规则:Nginx 接收到请求后,会先检查是否配置了
rewrite
规则。如果没有配置,就按原始请求进行处理。
3. 匹配 rewrite 规则
- 匹配成功:如果有
rewrite
规则,Nginx 会尝试将请求的 URI 与规则进行匹配。若匹配成功,则执行相应的rewrite
动作。 - 匹配失败:若匹配失败,则按原始请求处理。
4. 执行 rewrite 动作及不同类型处理
- 临时重定向 302:返回 302 状态码给客户端,客户端会根据响应中的新地址进行临时跳转。
- 永久重定向 301:返回 301 状态码给客户端,客户端会根据响应中的新地址进行永久跳转,通常用于 URL 变更等场景。
- 内部重写 last:Nginx 会在内部重新匹配
location
,再次从检查rewrite
规则开始处理新的 URI。 - 内部重写 break:停止当前
location
块内后续的rewrite
规则检查,继续按原始请求处理后续流程。
5. 请求处理与响应返回
- 经过上述流程后,Nginx 处理请求并将响应返回给客户端。
Nginx 配置示例
server {
listen 80;
server_name example.com;
# 永久重定向示例
rewrite ^/old-url$ /new-url permanent;
# 临时重定向示例
rewrite ^/temp-old-url$ /temp-new-url redirect;
location / {
# 内部重写 last 示例
rewrite ^/internal-old$ /internal-new last;
# 内部重写 break 示例
rewrite ^/break-old$ /break-new break;
# 其他配置
}
}
在上述配置中,分别展示了不同类型的 rewrite
规则应用。
rewrite案例
以下是几个 Nginx rewrite
指令的实际生产环境案例,涵盖 URL 重定向、去掉文件扩展名、跳转 HTTPS、流量分流 等场景。
1. 301 永久重定向(HTTP -> HTTPS)
场景:强制所有 HTTP 访问跳转到 HTTPS,符合 SEO 要求。
server {
listen 80;
server_name example.com;
rewrite ^/(.*)$ https://example.com/$1 permanent;
}
请求: http://example.com/test
跳转: https://example.com/test
(301 永久重定向)
2. 动态 URL 重写(伪静态)
场景:隐藏动态参数,将 /product/123
转换为 /product.php?id=123
。
location /product/ {
rewrite ^/product/([0-9]+)$ /product.php?id=$1 last;
}
请求: /product/123
实际访问: /product.php?id=123
3. 去掉 .php
后缀
场景:访问 /about
时实际加载 /about.php
。
location / {
rewrite ^/(.*)\$ /$1.php last;
}
请求: /about
实际访问: /about.php
4. URL 结构调整
场景:将 /old/path/xxx.html
重定向到 /new/path/xxx.html
。
rewrite ^/old/path/(.*)\.html$ /new/path/$1.html permanent;
请求: /old/path/page1.html
跳转: /new/path/page1.html
(301 永久重定向)
5. 拦截并引导到维护页面
场景:在维护期间,所有非管理员请求跳转到 maintenance.html
。
if ($remote_addr !~* "192.168.1.100") {
rewrite ^(.*)$ /maintenance.html last;
}
请求: /dashboard
非管理员跳转: /maintenance.html
6. 按 User-Agent 进行流量分流
场景:针对移动端和 PC 端提供不同的页面。
if ($http_user_agent ~* "(Android|iPhone|iPad)") {
rewrite ^/$ /mobile.html last;
}
请求: /
移动端跳转: /mobile.html
7. 强制 .html
访问
场景:让 /index
直接跳转到 /index.html
。
rewrite ^/(.*[^/])$ /$1.html break;
请求: /index
跳转: /index.html
总结
需求 | rewrite 规则 |
说明 | ||
---|---|---|---|---|
HTTP 跳 HTTPS | rewrite ^/(.*)$ https://example.com/$1 permanent; |
强制 HTTPS | ||
伪静态 | rewrite ^/product/([0-9]+)$ /product.php?id=$1 last; |
美化 URL | ||
去掉 .php |
rewrite ^/(.*)$ /$1.php last; |
让 /about 访问 /about.php |
||
结构调整 | rewrite ^/old/path/(.*)\.html$ /new/path/$1.html permanent; |
旧路径跳转到新路径 | ||
维护模式 | if ($remote_addr !~* "192.168.1.100") { rewrite ^(.*)$ /maintenance.html last; } |
非管理员跳转到维护页 | ||
按 UA 识别 | `if ($http_user_agent ~* "(Android | iPhone | iPad)") { rewrite ^/$ /mobile.html last; }` | 移动端跳转到 /mobile.html |
.html 强制访问 |
rewrite ^/(.*[^/])$ /$1.html break; |
/index -> /index.html |
这些 rewrite
规则可以灵活应用在生产环境中,根据业务需求进行调整。
1.介绍
实际工作需求中,我们经常要修改用户url的请求
1.例如客户端默认发送是http协议,我们的网站都支持了https部署,需要将用户的http请求强制跳转到https。
2.网站自适应移动端、或者PC端,将用户请求自动跳转到移动端服务器、或者PC端服务器
例如
http://yuchaoit.cn PC端
http://m.yuchaoit.cn
3.这个功能就得通过ngx_http_rewrite_module 这个模块实现
该模块提供了多个指令功能
break # 中断配置
if # 请求判断
set # 设置变量
return # 返回值
rewrite # 对用户请求URL重写
nginx if return
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef action fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C{是否有 if 语句}:::decision
C -->|否| D(正常处理请求):::nginx
C -->|是| E(执行 if 条件判断):::nginx
E --> F{条件是否满足}:::decision
F -->|否| D
F -->|是| G(执行 return 指令):::action
G --> H{return 类型}:::decision
H -->|返回状态码| I(返回对应状态码响应):::nginx
H -->|返回重定向| J(返回重定向响应):::nginx
H -->|返回文本内容| K(返回文本内容响应):::nginx
I --> L(客户端接收状态码响应):::client
J --> M(客户端接收重定向响应并跳转):::client
K --> N(客户端接收文本内容响应):::client
D --> O(正常处理并返回响应):::nginx
O --> P(客户端接收正常响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器等)向 Nginx 服务器发送 HTTP 请求。
2. Nginx 接收请求并检查 if
语句
- 无
if
语句:如果 Nginx 配置中针对该请求没有if
语句,Nginx 会正常处理该请求。 - 有
if
语句:Nginx 会执行if
语句中的条件判断。
3. if
条件判断
- 条件不满足:若
if
条件不满足,Nginx 会继续正常处理请求。 - 条件满足:当
if
条件满足时,Nginx 会执行if
块内的return
指令。
4. 处理 return
指令
- 返回状态码:
return
可以直接返回一个 HTTP 状态码,如return 403;
,Nginx 会向客户端返回对应的状态码响应。 - 返回重定向:
return
可以实现重定向,例如return 301 http://newdomain.com;
,客户端会收到重定向响应并跳转到新的地址。 - 返回文本内容:
return
也能返回一段文本内容,如return 200 "Hello, World!";
,客户端会接收到包含该文本内容的响应。
5. 客户端接收响应
客户端根据 Nginx 返回的不同类型响应进行相应处理,如接收状态码、跳转或显示文本内容等。如果没有经过 if
处理,客户端则接收正常处理后的响应。
Nginx 配置示例
server {
listen 80;
server_name example.com;
location / {
# 示例 1: 根据请求参数判断并返回状态码
if ($arg_deny = "true") {
return 403;
}
# 示例 2: 根据请求 URI 判断并返回重定向
if ($request_uri ~* "^/old-url") {
return 301 http://example.com/new-url;
}
# 示例 3: 根据用户代理判断并返回文本内容
if ($http_user_agent ~* "BadBot") {
return 200 "You are not allowed to access.";
}
# 正常处理
root /var/www/html;
index index.html;
}
}
以上配置展示了不同情况下 if
和 return
指令的使用方式。
2.指令语法(if)
1.if语句,用于条件判断,根据判断结果的不同,执行不同的动作,if写在server{}或者location{}标签里。
if (匹配条件) {
执行动作
}
2.1 匹配规则
if的匹配条件可以是如下任意一种。
条件符号
符号 | 作用 |
---|---|
= | 比较变量、字符串是否相等,相等为true、不等则为false |
!= | 比较变量、字符串是否不相等,不相等为true、相等为false |
~ | 区分大小写的正则匹配,匹配上为true,否则为false |
!~ | 区分大小写的正则匹配,不匹配上为true,否则为false |
~* | 不区分大小写的正则匹配,匹配上为true,否则为false |
!~* | 不区分大小写的正则匹配,不匹配上为true,否则为false |
条件参数
符号 | 作用 |
---|---|
-f 和 !-f | 请求的文件是否存在 |
-d 和 !-d | 判断的目录是否存在 |
-e 和 !-e | 判断的文件、目录、软连接是否存在 |
-x 和 !-x | 判断的请求文件是否有有执行权限 |
2.2 创建测试配置文件(if)
针对不同的情况进行判断,动作设置。
server {
# 客户端完全匹配到
listen 22555;
server_name localhost;
root html;
charset utf-8;
location /test-if {
# 客户端类型完全匹配到 huawei
if ($http_user_agent = huawei){
echo "agent is huawei";
}
# 客户端类型区分大小写
if ($http_user_agent ~ Iphone) {
echo "agent is Iphone";
}
# 客户端类型不区分大小写
if ($http_user_agent ~* Chrome) {
echo "agent is Chrome";
}
# 如果请求方法不是GET就提示 ”只能用GET方法,你这个烂玩家“
if ($request_method != GET) {
echo "必须是GET方法,你这个烂玩家";
}
# 如果是IE浏览器,直接提示 "不支持IE,请下载Chrome浏览器"
# 不区分大小写的正则匹配
if ($http_user_agent ~* IE){
echo "不支持IE,请下载Chrome浏览器";
}
# 如果上面没有任何匹配,执行如下语句
echo "if规则没有匹配到";
echo "agent is >>>>>> $http_user_agent";
echo "request_method is >>>>>>>> $request_method";
}
}
2.3 测试访问
默认访问,没有匹配到if规则
[root@master-61 ~]#curl 10.0.0.9:22555/test-if
if规则没有匹配到
agent is >>>>>> curl/7.29.0
request_method is >>>>>>>> GET
[root@master-61 ~]#
测试完全匹配
[root@master-61 ~]#curl -A 'huawei' 10.0.0.9:22555/test-if
agent is huawei
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'huaweiiiii' 10.0.0.9:22555/test-if
if规则没有匹配到
agent is >>>>>> huaweiiiii
request_method is >>>>>>>> GET
测试区分大小写的正则匹配
[root@master-61 ~]#curl -A 'Iphone' 10.0.0.9:22555/test-if
agent is Iphone
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'iphone' 10.0.0.9:22555/test-if
if规则没有匹配到
agent is >>>>>> iphone
request_method is >>>>>>>> GET
[root@master-61 ~]#curl -A 'aaaaaiphone' 10.0.0.9:22555/test-if
if规则没有匹配到
agent is >>>>>> aaaaaiphone
request_method is >>>>>>>> GET
[root@master-61 ~]#curl -A 'aaaaaIphone' 10.0.0.9:22555/test-if
agent is Iphone
[root@master-61 ~]#curl -A 'aaaaaIphonebbbbbb' 10.0.0.9:22555/test-if
agent is Iphone
测试不区分大小写的正则匹配
[root@master-61 ~]#curl -A 'Chrome' 10.0.0.9:22555/test-if
agent is Chrome
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'chrome' 10.0.0.9:22555/test-if
agent is Chrome
[root@master-61 ~]#curl -A 'aaaaaaaChrome' 10.0.0.9:22555/test-if
agent is Chrome
[root@master-61 ~]#curl -A 'BBBBBbaaaaaaaChrome' 10.0.0.9:22555/test-if
agent is Chrome
[root@master-61 ~]#curl -A 'BBBBBbaaaaaaaChromeCCCC' 10.0.0.9:22555/test-if
agent is Chrome
[root@master-61 ~]#curl -A 'BBBBBbaaaaaaaChrComeCCCC' 10.0.0.9:22555/test-if
if规则没有匹配到
agent is >>>>>> BBBBBbaaaaaaaChrComeCCCC
request_method is >>>>>>>> GET
测试请求方法POST
curl默认就是GET方法
curl -X method --data '数据'
[root@master-61 ~]#curl -X POST --data '{"name":"chaoge01"}' 10.0.0.9:22555/test-if
必须是GET方法,你这个烂玩家
测试浏览器、分别用IE浏览器、Chrome测试。
3.指令(return)
https://nginx.org/en/docs/stream/ngx_stream_return_module.html
The ngx_stream_return_module module (1.11.2) allows sending a specified value to the client and then closing the connection.
Example Configuration
server {
listen 12345;
return $time_iso8601;
}
Syntax: return value;
Default: —
Context: server
Specifies a value to send to the client. The value can contain text, variables, and their combination.
指定要发送到客户端的值。 该值可以包含文本、变量及其组合。
指令说明
return用于返回如状态码
或者重写url
或者响应状态码、以及文本等
return之后的命令不会再执行。
3.1 return用法
return 可以用于 server {} ; location {} ; if {};
return code [text];
return code url;
return url;
3.2 配置文件
[root@web-9 /etc/nginx/conf.d]#cat return.conf
server {
listen 22666;
server_name _;
root html;
# 精确匹配,客户端只访问了网页根目录
location = / {
echo "welcome to chaoge linux course.";
}
location /test-return {
# 客户端完全匹配
if ($http_user_agent = huawei){
return 200 "agent is $http_user_agent \n";
}
# 限制必须是GET方法
if ($request_method != GET){
return 405 "必须是GET方法!其他方法不允许\n";
}
# 如果是IE浏览器,就重定向
if ($http_user_agent ~* IE){
return 301 http://yuchaoit.cn/cai.jpg;
}
# 没有if条件匹配到
return 404 "sorry, nothing ....\n";
}
# 默认匹配,如果没有匹配到任意内容,跳转到首页 jd.com就是这个做法
location / {
return 301 http://yuchaoit.cn/cai.jpg;
}
location /ji {
return 500 "鸡你太美\n";
}
}
3.3 测试访问
精确匹配访问
随便输入url,访问错误的内容
10.0.0.9:22666/qweqweqweqweqwe
默认会跳转301,页面重定向
设置访问客户端
[root@master-61 ~]#curl 10.0.0.9:22666/test-return
sorry, nothing ....
精确完全匹配
[root@master-61 ~]#curl -A 'huawei' 10.0.0.9:22666/test-return
agent is huawei
[root@master-61 ~]#
[root@master-61 ~]#
[root@master-61 ~]#curl -A 'aaahuawei' 10.0.0.9:22666/test-return
sorry, nothing ....
不允许POST方法
[root@master-61 ~]#curl -X POST 10.0.0.9:22666/test-return
必须是GET方法!其他方法不允许
测试用ie浏览器访问
10.0.0.9:22666/test-return 请求都会被重定向
测试访问/ji 路径,返回500状态码,以及字符串
[root@master-61 ~]#curl 10.0.0.9:22666/ji -I
HTTP/1.1 500 Internal Server Error
Server: nginx/1.19.0
Date: Tue, 10 May 2022 07:57:42 GMT
Content-Type: application/octet-stream
Content-Length: 13
Connection: keep-alive
[root@master-61 ~]#
[root@master-61 ~]#curl 10.0.0.9:22666/ji
鸡你太美
4.set指令
1.语法
set就是用于设置一个nginx变量,这个值可以是文本、变量或者其组合。
set可以用于设置server{} location{} if{}
set 变量名 变量值;
2.配置文件
server {
listen 22777;
server_name _;
root html;
set $my_url http://yuchaoit.cn/cai.jpg;
location /test-set {
return 301 $my_url;
}
}
3.测试访问
浏览器访问10.0.0.9:22777/test-set 会自动被重定向
5.指令(break)
1.语法
break用于终止所在区域的后续指令,且只针对ngx_http_rewrite_module提供的模块指令;
也就是咱们目前所学的这几个rewrite相关的指令,在break后面不会执行了。
break可以用于
server{}
location{}
if{}
2.配置文件
server {
listen 22888;
server_name _;
root html;
location / {
set $my_website yuchaoit.cn;
echo "welcome to my website:" $my_website;
break;
set $my_name yuchao;
echo "my name is" $my_name;
}
}
3.执行结果
[root@master-61 ~]#curl 10.0.0.9:22888
welcome to my website: yuchaoit.cn
my name is
发现break后续的 set指令并未正确执行。
6.rewrite指令(工作必需品)
官网
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
句法: rewrite regex replacement [flag];
默认: —
语境: server, location,if
6.1 指令语法
1. rewrite指令可以基于用户的请求url,再通过正则表达式的匹配情况,进行地址重写;
2. rewrite指令可以写多条,按照顺序依次执行;
3. rewrite指令可以根据flag标记进行进一步处理(last、break、redirect、permanent)
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef rewrite fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef decision fill:#FFEBEE,stroke:#E57373,stroke-width:2px
classDef action fill:#C8E6C9,stroke:#4CAF50,stroke-width:2px
A(客户端发起请求):::client --> B(Nginx 接收请求):::nginx
B --> C(匹配 rewrite 规则):::rewrite
C --> D{是否匹配成功}:::decision
D -->|否| E(按原始请求处理):::nginx
D -->|是| F{rewrite 标志是 last 还是 break?}:::decision
F -->|last| G(停止当前 location 块内 rewrite 检查):::action
F -->|break| H(停止当前 location 块内后续 rewrite 检查):::action
G --> I(重新进行 location 匹配):::nginx
H --> J(继续当前 location 后续处理):::nginx
I --> C(再次匹配 rewrite 规则)
J --> K(处理请求并返回响应):::nginx
E --> K
K --> L(客户端接收响应):::client
图示解释
1. 客户端发起请求
客户端(如浏览器)向 Nginx 服务器发送 HTTP 请求。
2. Nginx 接收请求并匹配 rewrite
规则
Nginx 接收到请求后,开始尝试将请求的 URI 与配置中的 rewrite
规则进行匹配。
3. 判断匹配结果
- 匹配失败:若没有匹配到任何
rewrite
规则,Nginx 会按原始请求进行处理。 - 匹配成功:当匹配到
rewrite
规则后,Nginx 会根据规则后面的标志(last
或break
)来决定后续的处理流程。
4. 处理 last
标志
- 停止当前
location
块内rewrite
检查:如果rewrite
规则使用了last
标志,Nginx 会停止当前location
块内后续rewrite
规则的检查。 - 重新进行
location
匹配:Nginx 会使用重写后的 URI 重新进行location
匹配,匹配完成后再次从匹配rewrite
规则开始处理。
5. 处理 break
标志
- 停止当前
location
块内后续rewrite
检查:若rewrite
规则使用了break
标志,Nginx 会停止当前location
块内后续rewrite
规则的检查。 - 继续当前
location
后续处理:Nginx 会继续处理当前location
块内除rewrite
规则之外的其他配置,如root
、index
等,然后处理请求并返回响应。
6. 请求处理与响应返回
经过上述流程后,Nginx 处理请求并将响应返回给客户端。
Nginx 配置示例
server {
listen 80;
server_name example.com;
location / {
# 使用 last 标志
rewrite ^/old-url$ /new-url last;
# 使用 break 标志
rewrite ^/temp-old$ /temp-new break;
# 其他配置
root /var/www/html;
index index.html;
}
}
在上述配置中,当请求 /old-url
时,使用 last
标志会使 Nginx 重写 URI 后重新进行 location
匹配;当请求 /temp-old
时,使用 break
标志会使 Nginx 停止当前 location
块内后续 rewrite
规则检查,继续处理当前 location
的其他配置。
6.4 redirect和permanent实战
permanent和301永久重定向
HTTP协议规范里,301是永久重定向、302是临时重定向。
工作场景
- 公司的旧域名需要永久跳转到新域名。
↓
www.yuchaoit.cn
状态码为301.
旧网站配置文件
# 0.注意要做好本地dns解析
10.0.0.9 www.yuchaoit.cn
# 1.创建测试数据
mkdir -p /pythonav
echo "i am pythonav " > /pythonav/index.html
# 2.配置文件
cat /etc/nginx/conf.d/pythonav.conf
server {
listen 80;
server_name ;
location / {
root /pythonav/;
index index.html;
rewrite / http://www.yuchaoit.cn permanent;
}
}
# 3.重启
systemctl restart nginx
新网站配置文件
# 0.注意要做好本地dns解析
10.0.0.9 www.yuchaoit.cn
# 1.创建测试数据
mkdir -p /www.yuchaoit.cn/
echo 'i am www.yuchaoit.cn' > /www.yuchaoit.cn/index.html
# 2.配置文件
[root@web-9 /etc/nginx/conf.d]#cat www.yuchaoit.cn.conf
server {
listen 80;
server_name www.yuchaoit.cn;
location / {
root /www.yuchaoit.cn/;
index index.html;
}
}
3.重启
systemctl restart nginx
测试访问
做好dns解析
10.0.0.9 www.yuchaoit.cn
1.并且你会发现浏览器中提示的是 disk cache,表示这个域名做了dns缓存
2.新域名的请求提示是304,表示请求正确,但是这个文件没有任何变化
公司的旧网站 依然提供访问,但是用户访问后,自动跳转到了新网站
www.yuchaoit.cn
且浏览器状态码是301,显示永久重定向,就是这个旧网站已经被弃用了,自动跳转了新的。
使用场景又比如
1. 用户输入 非www的网址(yuchaoit.cn),自动重定向到www.yuchaoit.cn
2. http跳转https
3. 域名更换
6.5 redrict 302临时跳转
302临时跳转,用于因为某些原因,域名要临时跳转,旧的网站url还是会继续使用的,例如公司搞了一个活动页面等,活动结束后要取消这个跳转。
302临时跳转需求
用户访问www.yuchaoit.cn 需要临时跳转到party.yuchaoit.cn
旧配置文件
[root@web-9 /etc/nginx/conf.d]#cat www.yuchaoit.cn.conf
server {
listen 80;
server_name www.yuchaoit.cn;
location / {
root /www.yuchaoit.cn/;
index index.html;
rewrite / http://party.yuchaoit.cn redirect;
}
}
新配置文件
# 1.创建测试数据
mkdir -p /party.yuchaoit.cn/
echo 'i am party.yuchaoit.cn' > /party.yuchaoit.cn/index.html
# 2.配置文件
server {
listen 80;
server_name party.yuchaoit.cn;
location / {
root /party.yuchaoit.cn/;
index index.html;
}
}
# 3.重启服务
systemctl restart nginx
客户端测试302跳转
1.做好dns解析
10.0.0.9 www.yuchaoit.cn party.yuchaoit.cn
2.浏览器测试
发生了302跳转,表示临时重定向
并且没有看到disk cache,表示并未做dns缓存
6.7 生产rewrite实践(一)
公司的博客url连接,旧的如下
www.yuchaoit.cn/blog
现在业务变更,需要添加三级域名为 blog.yuchaoit.cn,需要将www.yuchaoit.cn/blog这个url的请求,转发给blog.yuchaoit.cn
例如
http://www.yuchaoit.cn/blog/login
http://www.yuchaoit.cn/blog/hello-world
都会跳转到
http://blog.yuchaoit.cn/login
http://blog.yuchaoit.cn/hello-world.html
配置文件(www官网配置)
# 1.配置文件
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
location / {
root /www/;
index index.html;
}
# 针对旧域名进行url重写
# 匹配/blog/路径,然后rewrite
location /blog/ {
# 使用正则表达式,提取url参数
rewrite ^/blog/(.*)$ http://blog.yuchaoit.cn/$1 redirect;
}
}
# 2.测试数据
echo 'hello ,i am www 官网 ~~~~~~~' > /www/index.html
# 3.重启服务
systemctl restart nginx
配置文件(blog业务配置)
# 1.配置文件
# 1.配置文件
server {
listen 80;
server_name blog.yuchaoit.cn;
charset utf-8;
location / {
root /blog/;
index index.html;
}
}
# 2.创建测试数据
mkdir -p /blog
echo 'hello ,i am blog 博客 ~~~~~~~' > /blog/index.html
# 3.重启服务
systemctl restart nginx
测试访问
1.做好dns解析
10.0.0.9 www.yuchaoit.cn blog.yuchaoit.cn
默认页面,location匹配返回官网页面。
访问blog路径
http://www.yuchaoit.cn/blog/index.html
查看是否会跳转
Nginx https
以下是使用 Mermaid 绘制的 Nginx 处理 HTTPS 请求的流程图,同时包含代码和详细解释。
graph LR
classDef client fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef nginx fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
classDef ssl fill:#E8F5E9,stroke:#81C784,stroke-width:2px
classDef process fill:#FFEBEE,stroke:#E57373,stroke-width:2px
A(客户端发起 HTTPS 请求):::client --> B(Nginx 监听 443 端口接收请求):::nginx
B --> C(SSL/TLS 握手过程):::ssl
C --> D{验证客户端支持的 SSL/TLS 版本和加密算法}:::process
D -->|支持| E(协商使用的 SSL/TLS 版本和加密算法):::ssl
D -->|不支持| F(返回错误信息给客户端):::nginx
E --> G(服务器发送证书给客户端):::nginx
G --> H(客户端验证证书有效性):::client
H -->|有效| I(客户端生成会话密钥):::client
H -->|无效| F
I --> J(客户端使用服务器公钥加密会话密钥并发送给服务器):::client
J --> K(服务器使用私钥解密会话密钥):::nginx
K --> L(双方使用会话密钥进行加密通信):::ssl
L --> M(客户端发送加密请求数据):::client
M --> N(Nginx 解密请求数据):::nginx
N --> O(Nginx 处理请求):::nginx
O --> P(Nginx 加密响应数据):::nginx
P --> Q(客户端接收并解密响应数据):::client
图示解释
1. 客户端发起 HTTPS 请求
客户端(如浏览器)向 Nginx 服务器的 443 端口(HTTPS 默认端口)发起 HTTPS 请求。
2. Nginx 接收请求并开始 SSL/TLS 握手
- 监听 443 端口:Nginx 配置为监听 443 端口,接收客户端的 HTTPS 请求。
- SSL/TLS 握手:握手过程是建立安全连接的关键步骤,主要包括版本和算法协商、证书验证和会话密钥交换。
3. 版本和算法协商
- 验证支持情况:Nginx 验证客户端支持的 SSL/TLS 版本和加密算法,判断是否有双方都支持的组合。
- 协商使用的版本和算法:如果支持,双方协商确定使用的 SSL/TLS 版本和加密算法。
4. 证书验证
- 服务器发送证书:Nginx 向客户端发送服务器证书,证书中包含服务器的公钥和相关信息。
- 客户端验证证书:客户端验证证书的有效性,包括证书的颁发机构、有效期、域名匹配等。如果证书无效,客户端会收到错误信息。
5. 会话密钥交换
- 客户端生成会话密钥:如果证书验证有效,客户端生成一个会话密钥,用于后续的加密通信。
- 加密并发送会话密钥:客户端使用服务器公钥对会话密钥进行加密,并发送给服务器。
- 服务器解密会话密钥:Nginx 使用私钥解密客户端发送的加密会话密钥。
6. 加密通信
- 双方使用会话密钥:客户端和 Nginx 服务器使用会话密钥进行加密通信,确保数据在传输过程中的保密性和完整性。
- 请求处理:客户端发送加密的请求数据,Nginx 解密后处理请求,并将响应数据加密后发送给客户端。
- 客户端接收并解密响应:客户端接收加密的响应数据,并使用会话密钥解密。
Nginx 配置示例
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /var/www/html;
index index.html;
}
}
listen 443 ssl
:监听 443 端口并启用 SSL。ssl_certificate
和ssl_certificate_key
:指定服务器证书和私钥的路径。ssl_protocols
:指定支持的 SSL/TLS 版本。ssl_ciphers
:指定支持的加密算法。
通过以上配置和流程,Nginx 可以安全地处理 HTTPS 请求。
6.8 生产rewrite实践(二)
用户访问
http://www.yuchaoit.cn:80
但是现在该网站添加了支付功能,为了保证http数据传输安全,添加上https证书对数据加密,
因此必须改为访问
https://www.yuchaoit.cn:443
但是你又不能强制性要求用户每次都访问
https://xxxxx
所以你服务端必须做好跳转。
1.创建证书
1.网站的证书应该是由权威企业颁发,这样浏览器才能信任,自建的证书,只是在内网环境下使用。
mkdir /etc/nginx/ssl_key
cd /etc/nginx/ssl_key
# 输入2次密码 chaoge666
# openssl创建私钥文件 server.key,基于rsa算法,生成的 私钥长度是2048
openssl genrsa -idea -out server.key 2048
# 自己颁发证书,crt是证书的后缀名称,以及设置证书的有效期是100年,以及证书的算法等
# 然后填入证书对应的网站信息,如国家,公司名,邮箱等
[root@web-9 /etc/nginx/ssl_key]#openssl req -days 36500 -x509 -sha256 -nodes -newkey rsa:2048 -keyout server.key -out server.crt
Generating a 2048 bit RSA private key
..........................................................+++
................+++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) [Default City]:BJ
Organization Name (eg, company) [Default Company Ltd]:yuchaoit
Organizational Unit Name (eg, section) []:yuchaoit
Common Name (eg, your name or your server's hostname) []:yuchaoit
Email Address []:yc_uuu@163.com
3. 确认生成了证书文件
[root@web-9 /etc/nginx/ssl_key]#ll -h
total 8.0K
-rw-r--r-- 1 root root 1.4K May 10 20:24 server.crt
-rw-r--r-- 1 root root 1.7K May 10 20:24 server.key
此时自建的一个证书就可以使用了
2.nginx配置文件支持https
# 配置文件
[root@web-9 /etc/nginx/ssl_key]#cat /etc/nginx/conf.d/ssl.conf
server {
listen 443 ssl;
server_name www.yuchaoit.cn;
ssl_certificate /etc/nginx/ssl_key/server.crt;
ssl_certificate_key /etc/nginx/ssl_key/server.key;
charset utf-8;
location / {
root /www;
index index.html;
}
}
# 创建测试数据
[root@web-9 /etc/nginx/ssl_key]#cat /www/index.html
hello ,i am www 官网 ~~~~~~~
3.重启nginx,访问https
http://www.yuchaoit.cn/
https://www.yuchaoit.cn/
点击高级继续访问
此时网站已经是支持https的了,但是浏览器并不信任,因此你需要去阿里云购买一个公网信任的证书即可。
4.配置https自动跳转
配置默认的80官网,跳转到https即可。
[root@web-9 /etc/nginx/conf.d]#cat www.conf
server {
listen 80;
server_name www.yuchaoit.cn;
charset utf-8;
rewrite ^(.*) https://$server_name$1 redirect;
}