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-ControlExpires 等头字段。

4. 安全配置

保障网站的安全性,防止各种安全威胁。

  • 访问控制:通过 allowdeny 指令限制特定 IP 地址或 IP 段的访问,只允许授权的用户访问网站。
  • SSL/TLS 配置:为网站启用 HTTPS 协议,使用 SSL/TLS 加密数据传输,保护用户信息的安全。
  • 防止 DDoS 攻击:通过配置 Nginx 的限流、限速等功能,抵御分布式拒绝服务攻击,确保网站的可用性。

5. 性能优化

提高 Nginx 服务器的性能和响应速度。

  • 连接优化:调整 Nginx 的连接参数,如 worker_connectionskeepalive_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 脚本。
  • postrotateendscript:定义了在日志切割后执行的脚本,这里是向 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.访问目录索引

image-20220508161036151

四、连接数监控

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.访问状态

image-20220508165638886

五、基于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 配置文件中没有针对该请求路径配置任何 allowdeny 规则,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;
    }
}

image-20220509142730289

但是虚拟机,走内网环境是可以通的。

image-20220509143126705

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可访问

image-20220509143416816

linux不可访问

image-20220509143455557

六、基于用户认证的访问限制

有时候,我们一些站点内容想要进行授权查看,只能输入账号密码之后才能访问,例如一些重要的内网平台,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站点被加了密码。

image-20220509162007430

其他未设置认证的可以直接访问。

image-20220509162024150

七、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/REJECTED
    • limit_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/

总结选型建议

  1. 常规防护limit_req + burst + nodelay
  2. 下载站/大文件limit_conn + limit_rate
  3. API 接口:多维度联合限流(IP + URL)
  4. 高安全场景:Lua + Redis 实现分布式限流

1.官网模块

https://nginx.org/en/docs/http/ngx_http_limit_req_module.html

2.配置语法

image-20220509164905381

限速规则语法
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

image-20220509173510601

超速访问情况

[root@master-61 ~]#for i in {1..20};do curl -I www.yuchaoit.cn;sleep 0.5 ;done

image-20220509173936426

八、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_formatif 语句、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),并设置一些必要的请求头,如 HostX-Real-IPX-Forwarded-For,以便后端服务器获取客户端的真实信息。
  • location /app:将以 /app 开头的请求转发到后端的 Python Flask 应用服务器(http://flask_server:5000),同时设置 HTTP 版本和 UpgradeConnection 头,适用于需要 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 locationrootalias 指令工作原理的图示,同时会给出相应代码和详细解释。

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 块可能使用了 rootalias 指令。

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

通过上述图示和示例,你可以更清晰地理解 rootalias 指令在 Nginx location 中的工作原理。

7.root、alias实践。

在 Nginx 中,rootalias 用于指定文件路径,但它们的行为不同,容易混淆。下面是详细的实践说明和示例。


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 指定的路径必须以 / 结尾,以防止路径拼接错误。

你可以根据实际需求选择 rootalias,避免路径解析错误。

8.图解root、alias

image-20220510142114882

老铁们,我做的对吗?

十一、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;
    }
}

以上配置展示了不同情况下 ifreturn 指令的使用方式。

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测试。

image-20220510145737680


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 测试访问

精确匹配访问

image-20220510155028733

随便输入url,访问错误的内容

10.0.0.9:22666/qweqweqweqweqwe

默认会跳转301,页面重定向

image-20220510155110571

设置访问客户端

[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 会根据规则后面的标志(lastbreak)来决定后续的处理流程。

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 规则之外的其他配置,如 rootindex 等,然后处理请求并返回响应。

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,表示请求正确,但是这个文件没有任何变化

image-20220510174454473

公司的旧网站  依然提供访问,但是用户访问后,自动跳转到了新网站
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.浏览器测试

image-20220510182106788

发生了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匹配返回官网页面。

image-20220510195620306

访问blog路径

http://www.yuchaoit.cn/blog/index.html
查看是否会跳转

image-20220510195916508

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_certificatessl_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/

image-20220510202758586


https://www.yuchaoit.cn/

image-20220510202921559

点击高级继续访问

image-20220510203013088

此时网站已经是支持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;
}

5.打开无痕浏览器,查看访问

image-20220510203456644

Copyright © www.yuchaoit.cn 2025 all right reserved,powered by Gitbook作者:于超 2025-02-12 22:06:03

results matching ""

    No results matching ""