Nginx平滑升级与location配置案例详解

Nginx平滑升级与location配置案例详解

一、Nginx平滑升级

Nginx平滑升级指在不中断服务的前提下,为Nginx添加新模块或更新版本,保障业务持续运行。以下是基于"为Nginx 1.24.0添加echo-nginx-module模块"的完整平滑升级流程,包含详细操作步骤、命令解释及注意事项。

(一)平滑升级核心原理

平滑升级的关键在于保留原配置与进程信息,通过重新编译包含新模块的Nginx程序,替换旧程序后重启服务,避免因服务中断导致的业务损失。核心逻辑为:获取原编译参数→添加新模块重新编译→备份旧程序→替换并重启。

(二)详细操作步骤

1. 部署基础Nginx环境(前提准备)

若已部署Nginx可跳过此步,新环境需先完成[Nginx安装](此处默认已安装Nginx 1.24.0,且运行正常)。

2. 获取原有Nginx编译参数

Nginx的编译参数决定了其功能模块(如SSL、静态压缩等),升级时需完整保留原参数 ,否则新程序会丢失原有功能。
操作命令

csharp 复制代码
[root@nginx ~]# nginx -V  # 大写V,可显示编译参数;小写v仅显示版本

AI写代码bash
1

执行结果(含关键编译参数,需完整记录):

csharp 复制代码
nginx version: nginx/1.24.0
built by gcc 8.5.0 24210514 (Red Hat 8.5.0-4) (GCC) 
built with OpenSSL 1.1.1k  FIPS 25 Mar 2421
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx \  # 安装目录
                     --user=nginx \  # 运行用户
                     --group=nginx \  # 运行用户组
                     --with-debug \  # 启用调试模式
                     --with-http_ssl_module \  # 启用SSL模块(HTTPS必备)
                     --with-http_realip_module \  # 启用真实IP获取模块
                     --with-http_image_filter_module \  # 启用图片处理模块
                     --with-http_gunzip_module \  # 启用Gunzip解压模块
                     --with-http_gzip_static_module \  # 启用静态文件Gzip压缩模块
                     --with-http_stub_status_module \  # 启用Nginx状态监控模块
                     --http-log-path=/var/log/nginx/access.log \  # 访问日志路径
                     --error-log-path=/var/log/nginx/error.log  # 错误日志路径

AI写代码
12345678910111213141516
3. 下载新模块(echo-nginx-module)

echo-nginx-module是OpenResty社区开发的Nginx模块,用于在响应中直接输出指定内容(如文本、变量等),常用于调试或简单接口返回。
操作步骤

  1. 本地下载模块源码:访问[echo-nginx-module GitHub地址],点击"Code"→"Download ZIP",获取压缩包(如echo-nginx-module-master.zip)。
  2. 上传至Nginx服务器:通过FTP、SCP等工具,将压缩包上传到Nginx服务器的/root目录(或其他自定义目录,需记住路径)。
4. 重新编译Nginx(含新模块)

编译前需确保[服务器]已安装编译依赖(如gccunzippcre-developenssl-devel等),若缺少依赖会导致编译失败。
操作步骤

(1)安装编译依赖工具
ini 复制代码
# 安装unzip(用于解压模块压缩包)
[root@nginx ~]# yum -y install unzip
# 安装Nginx编译必备依赖(若已安装可跳过)
[root@nginx ~]# yum -y install gcc pcre-devel openssl-devel zlib-devel

AI写代码bash
1234
(2)解压模块与Nginx源码包
  • 解压新模块包:

    java 复制代码
    [root@nginx ~]# unzip echo-nginx-module-master.zip  # 解压后生成目录echo-nginx-module-master
    
    AI写代码bash
    1
  • 解压Nginx源码包:

    平滑升级需基于原版本的源码进行编译,需确保服务器存在Nginx 1.24.0的源码包(若已删除,需重新从[Nginx官网]下载nginx-1.24.0.tar.gz并上传):

    csharp 复制代码
    [root@nginx ~]# tar -zxf nginx-1.24.0.tar.gz  # 解压后生成目录nginx-1.24.0
    
    AI写代码bash
    1
(3)配置编译参数(含新模块)

进入Nginx源码目录,执行./configure命令,完整保留原编译参数 ,并通过--add-module指定新模块的解压路径:

ini 复制代码
[root@nginx ~]# cd nginx-1.24.0/  # 进入源码目录
[root@nginx nginx-1.24.0]# ./configure \
--prefix=/usr/local/nginx \  # 原参数:安装目录
--user=nginx \  # 原参数:运行用户
--group=nginx \  # 原参数:运行用户组
--with-debug \  # 原参数:调试模式
--with-http_ssl_module \  # 原参数:SSL模块
--with-http_realip_module \  # 原参数:真实IP模块
--with-http_image_filter_module \  # 原参数:图片处理模块
--with-http_gunzip_module \  # 原参数:Gunzip模块
--with-http_gzip_static_module \  # 原参数:静态Gzip模块
--with-http_stub_status_module \  # 原参数:状态监控模块
--http-log-path=/var/log/nginx/access.log \  # 原参数:访问日志
--error-log-path=/var/log/nginx/error.log \  # 原参数:错误日志
--add-module=../echo-nginx-module-master  # 新增:新模块的解压路径(相对源码目录)

AI写代码bash
123456789101112131415

关键说明--add-module的路径需准确(此处../echo-nginx-module-master表示"上一级目录下的echo-nginx-module-master",因源码目录在/root/nginx-1.24.0,模块目录在/root),路径错误会导致模块加载失败。

(4)编译生成新Nginx程序

执行make命令编译(不可执行make install,否则会覆盖原安装目录,导致配置文件丢失):

csharp 复制代码
# 执行编译(过程约1-3分钟,依赖服务器性能)
[root@nginx nginx-1.24.0]# make

AI写代码bash
12
(5)验证编译结果

编译完成后,新的Nginx程序会生成在源码目录的objs子目录下,需确认程序存在:

csharp 复制代码
# 查看objs目录内容
[root@nginx nginx-1.24.0]# ls objs/

AI写代码bash
12

预期结果 :目录中需包含nginx可执行文件(即新编译的Nginx程序),其他文件如addon(模块相关)、src(源码编译文件)等为正常编译产物。

5. 备份旧程序、替换并重启服务

此步骤需严格按顺序执行,避免因操作失误导致服务中断或程序损坏。

(1)对比新旧程序的编译参数(验证新模块是否加载)
  • 查看旧程序参数(原Nginx):

    typescript 复制代码
    [root@nginx nginx-1.24.0]# nginx -V  # 无--add-module参数
    nginx version: nginx/1.24.0
    built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
    built with OpenSSL 1.0.2k-fips  26 Jan 2017
    TLS SNI support enabled
    configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log
    
    
    AI写代码bash
    1234567
  • 查看新程序参数(编译后的程序):

    java 复制代码
    [root@nginx nginx-1.24.0]# objs/nginx -V  # 需包含--add-module=../echo-nginx-module-master
    nginx version: nginx/1.24.0
    
    AI写代码bash
    12

built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

built with OpenSSL 1.0.2k-fips 26 Jan 2017

TLS SNI support enabled

configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --add-module=.../echo-nginx-module-master

csharp 复制代码
**关键验证**:新程序的`configure arguments`末尾需出现新模块的路径,确认模块已成功集成。

##### (2)停止原Nginx服务
```bash
# 优雅停止服务(发送停止信号,等待现有连接处理完成后退出)
[root@nginx nginx-1.24.0]# nginx -s stop
# 验证服务是否已停止(无80端口监听即表示停止成功)
[root@nginx nginx-1.24.0]# ss -anlt | grep 80

AI写代码
12345678
(3)备份旧程序

将原Nginx程序(/usr/local/nginx/sbin/nginx)备份到安全目录(如/opt),便于升级失败后回滚:

csharp 复制代码
[root@nginx nginx-1.24.0]# cp /usr/local/nginx/sbin/nginx /opt/nginx_old_$(date +%Y%m%d)
# 验证备份结果(查看/opt目录下是否有备份文件)
[root@nginx nginx-1.24.0]# ls /opt/

AI写代码bash
123
(4)替换旧程序为新程序

objs目录下的新程序覆盖到原安装路径:

bash 复制代码
[root@nginx nginx-1.24.0]# cp objs/nginx /usr/local/nginx/sbin/
# 系统会提示"是否覆盖",输入y确认
cp:是否覆盖'/usr/local/nginx/sbin/nginx'? y

AI写代码bash
123
(5)启动新Nginx服务并验证
csharp 复制代码
# 启动新服务
[root@nginx nginx-1.24.0]# /usr/local/nginx/sbin/nginx
# 验证服务状态(80端口监听表示启动成功)
[root@nginx nginx-1.24.0]# ss -anlt | grep 80

AI写代码bash
1234

预期结果 :输出类似LISTEN 0 128 0.0.0.0:80 0.0.0.0:*,表示Nginx已正常启动。

(6)最终验证新模块是否生效

查看Nginx版本与参数,确认新模块已加载:

csharp 复制代码
[root@nginx ~]# nginx -V

AI写代码bash
1

预期结果 :参数中包含--add-module=../echo-nginx-module-master,表示平滑升级完成。

6. 测试echo模块功能

通过配置location使用echo模块,验证其是否正常工作。

(1)修改Nginx配置文件
csharp 复制代码
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf

AI写代码bash
1

server块中添加如下location配置(用于匹配根路径/的请求):

bash 复制代码
server {
    listen       80;
    server_name  localhost;

    # 新增:使用echo模块输出文本"ycy"
    location / {
        echo "ycy";  # echo模块的核心指令,直接输出指定内容
    }
}

AI写代码nginx
123456789
(2)检查配置文件语法正确性

修改配置后需先检查语法,避免因错误导致服务启动失败:

csharp 复制代码
[root@nginx ~]# nginx -t

AI写代码bash
1

预期结果 :输出nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is oknginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful,表示语法正确。

(3)重载Nginx配置(无需重启服务)
csharp 复制代码
[root@nginx ~]# nginx -s reload

AI写代码bash
1
(4)验证echo模块功能
  • 浏览器访问:直接在浏览器输入Nginx服务器IP(如192.168.100.10),会触发文件下载(因echo模块输出的文本无Content-Type头,浏览器默认当作文件处理,属于正常现象)。

  • 命令行访问(推荐,更准确):在本地Windows或其他Linux机器上执行curl命令:

    csharp 复制代码
    # Windows cmd中执行(需确保本地能ping通服务器IP)
    [root@ycy3 html]# curl http://192.168.100.10
    ycy
    
    AI写代码bash
    123
perl 复制代码
  **预期结果**:输出`ycy`,表示echo模块已正常生效,平滑升级成功。


## 二、Nginx location配置案例
`location`是Nginx的核心配置指令,用于根据客户端请求的**URI(统一资源标识符,如`/abc`、`/image/1.jpg`)** 匹配不同的配置块,实现访问控制、内容转发、页面返回等功能。以下详细说明`location`的语法、修饰符、匹配规则及实操案例。


### (一)location核心概念
#### 1. 功能定位
`location`属于`server`块的子配置,每个`server`可包含多个`location`,Nginx会根据请求的URI匹配对应的`location`,并执行该块中的配置(如`echo`输出、`proxy_pass`转发、`deny`拒绝访问等)。

#### 2. 基本语法
```nginx
location [修饰符] pattern {
    # 配置指令(如echo、proxy_pass、root等)
    指令1;
    指令2;
}

AI写代码
123456789101112131415161718
  • 修饰符:可选,用于定义匹配规则(如精确匹配、正则匹配等),决定匹配优先级。
  • pattern :匹配模式,即URI的匹配规则(如/abc~^/image/.*.jpg$等)。
  • 配置块:匹配成功后执行的指令集合。

(二)location修饰符详解

不同修饰符对应不同的匹配规则和优先级,是location配置的核心。以下为常用修饰符的对比:

修饰符 匹配规则 优先级 适用场景 示例
= 精确匹配:URI必须与pattern完全一致(包括字符、长度、路径分隔符/ 最高 匹配固定URI(如首页/、接口/api/login location = /abc { ... }(仅匹配/abc,不匹配/abc//abc/123
~ 正则表达式匹配:区分大小写,pattern为正则表达式 中高(按配置顺序) 需区分大小写的URI匹配(如/ABC/abc不同处理) location ~ /abc$ { ... }(匹配以/abc结尾的URI,如/test/abc,不匹配/test/ABC
^~ 前缀匹配:URI以pattern开头即匹配,匹配成功后停止后续搜索(不支持正则) 中(高于~/~*,低于= 匹配某一类前缀URI(如/static/下的所有静态资源) location ^~ /static/ { ... }(匹配/static/css/static/js/1.js等,且不再检查后续正则匹配)
~* 正则表达式匹配:不区分大小写,pattern为正则表达式 中高(按配置顺序) 无需区分大小写的URI匹配(如静态资源/image/IMAGE同处理) location ~* /abc$ { ... }(匹配/abc/ABC/aBc等)
无修饰符 前缀匹配:URI以pattern开头即匹配,但匹配成功后仍会继续搜索正则匹配(不支持正则) 最低 通用前缀匹配(如/abc匹配/abc/abc/123等) location /abc { ... }(匹配/abc/abc//abc/dsa等)
@ 命名location:仅用于内部请求(如try_fileserror_page跳转),客户端无法直接访问 仅内部使用 内部跳转(如404页面、502错误页面) location @error_404 { return 404 "Page Not Found"; }

(三)location匹配顺序与优先级

Nginx处理location匹配时,严格遵循以下优先级(从高到低),一旦匹配成功且满足"停止搜索"条件,即不再检查后续规则

  1. =精确匹配 :优先检查所有带=location,若URI完全匹配,直接执行该配置块,停止后续搜索。
  2. ^~前缀匹配 :检查带^~location,若URI以pattern开头,直接执行该配置块,停止后续搜索(包括正则匹配)。
  3. 正则匹配(~/~* :按location在配置文件中的定义顺序 检查正则匹配(~~*优先级相同,谁在前先匹配谁),若匹配成功,执行该配置块,停止后续搜索。
  4. 无修饰符前缀匹配 :最后检查无修饰符的location,匹配URI前缀最长的location(若多个无修饰符locationpattern均为URI前缀,选择最长的那个),执行该配置块。

(四)实操案例(基于echo模块验证)

以下案例均基于"已安装echo模块"的Nginx环境,通过echo输出文本验证匹配结果,所有案例的server块基础配置如下(仅修改location部分):

ini 复制代码
server {
    listen       80;
    server_name  localhost;  # 服务器IP为192.168.100.10
    # 以下为不同案例的location配置
}

AI写代码nginx
12345
案例1:无修饰符的前缀匹配

配置内容

bash 复制代码
location /abc {
    echo "cy";  # 匹配成功后输出"cy"
}

AI写代码nginx
123

匹配规则 :URI以/abc开头即匹配,不区分后续路径。
测试结果 (通过curl命令验证):

typescript 复制代码
# 测试1:URI=/abc → 匹配成功
[root@ycy3 ~]#curl 192.168.100.10/abc
cy

# 测试2:URI=/abc/ → 匹配成功(以/abc开头)
[root@ycy3 ~]#curl 192.168.100.10/abc/
cy

# 测试3:URI=/abc/dsa → 匹配成功(以/abc开头)
[root@ycy3 ~]#curl 192.168.100.10/abc/dsa
cy

# 测试4:URI=/ab → 不匹配(不以/abc开头)
[root@ycy3 ~]#curl 192.168.100.10/ab
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

AI写代码bash
123456789101112131415161718192021
案例2:=精确匹配(匹配固定URI)
子案例2.1:pattern/abc(无末尾/

配置内容

bash 复制代码
location = /abc {
    echo "ycy";  # 仅匹配/abc时输出
}

AI写代码nginx
123

匹配规则 :URI必须与/abc完全一致,多一个/或多字符均不匹配。
测试结果

typescript 复制代码
# 测试1:URI=/abc → 完全匹配,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/abc
ycy

# 测试2:URI=/abc/ → 末尾多"/",不匹配,返回404
[root@ycy3 ~]#curl 192.168.100.10/abc/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

AI写代码bash
12345678910111213
子案例2.2:pattern/abc/(有末尾/

配置内容

bash 复制代码
location = /abc/ {
    echo "ycy";  # 仅匹配/abc/时输出
}

AI写代码nginx
123

测试结果

typescript 复制代码
# 测试1:URI=/abc/ → 完全匹配,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/abc/
ycy

# 测试2:URI=/abc → 末尾少"/",不匹配,返回404
[root@ycy3 ~]#curl 192.168.100.10/abc
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

AI写代码bash
12345678910111213

关键结论=修饰符对/敏感,配置时需严格匹配实际请求的URI格式(如客户端请求是/abc还是/abc/)。

案例3:~正则匹配(区分大小写)

配置内容

bash 复制代码
location ~ /abc$ {  # 正则表达式:匹配以"/abc"结尾的URI($表示结尾)
    echo "ycy";
}

AI写代码nginx
123

匹配规则 :URI必须以/abc结尾,且区分大小写(/ABC/aBc不匹配)。
测试结果

xml 复制代码
# 测试1:URI=/abc → 以/abc结尾,匹配成功,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/abc
ycy

# 测试2:URI=/test/abc → 以/abc结尾,匹配成功,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/test/abc
ycy

# 测试3:URI=/abc/ → 以/abc/结尾(非/abc),不匹配,返回404
[root@ycy3 ~]#curl 192.168.100.10/abc/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

# 测试4:URI=/ABC → 大小写不匹配,不匹配,返回404
[root@ycy3 ~]#curl 192.168.100.10/ABC
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

AI写代码bash
123456789101112131415161718192021222324252627
案例4:=~的优先级对比

配置内容=~同时存在,=在前):

bash 复制代码
# 正则匹配:以/abc结尾的URI
location ~ /abc$ {
    echo "ycy";
}
# 精确匹配:仅/abc
location = /abc {
    echo "cy";
}

AI写代码nginx
12345678

匹配规则 :根据优先级,=精确匹配高于~正则匹配,因此/abc会优先匹配=location
测试结果

csharp 复制代码
# 测试:URI=/abc → 优先匹配=的location,输出"cy"(而非正则的"ycy")
[root@ycy3 ~]#curl 192.168.100.10/abc
cy

# 测试:URI=/test/abc → 不匹配=的location,匹配~的正则,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/test/abc
ycy

AI写代码bash
1234567

关键结论 :无论=~在配置文件中的顺序如何,=的优先级始终最高,优先匹配。

案例5:~*正则匹配(不区分大小写)

配置内容

bash 复制代码
location ~* /abc$ {  # 正则表达式:以/abc结尾,不区分大小写
    echo "ycy";
}

AI写代码nginx
123

匹配规则 :URI以/abc结尾,且不区分大小写(/ABC/aBc均匹配)。
测试结果

csharp 复制代码
# 测试1:URI=/abc → 匹配成功,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/abc
ycy

# 测试2:URI=/ABC → 大小写不同,但~*不区分,匹配成功,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/ABC
ycy

# 测试3:URI=/aBc → 混合大小写,匹配成功,输出"ycy"
[root@ycy3 ~]#curl 192.168.100.10/aBc
ycy

AI写代码bash
1234567891011

(五)location匹配优先级总结(从高到低)

bash 复制代码
#依次输出测试优先级
location = /abc {
            echo "ycy1";
        }
        location ~ /abc {
            echo "ycy2";
        }
       location ~*/abc {
            echo "ycy3";
        }
        location ^~ /abc {
            echo "ycy4";
        }

AI写代码bash
12345678910111213

为便于记忆,将location的匹配优先级整理为以下顺序,实际配置时需严格遵循:

  1. =精确匹配:完全匹配URI,优先级最高,匹配后立即执行,停止后续搜索。
  2. ^~前缀匹配 :URI以pattern开头,匹配后停止后续搜索(包括正则匹配)。
  3. ~/~*正则匹配 :按配置文件中location的定义顺序匹配,先定义的优先,匹配后停止搜索(~~*优先级相同,仅区分大小写)。
  4. 无修饰符前缀匹配 :URI以pattern开头,匹配最长前缀的location,优先级最低。

配置建议

  • 固定URI(如//api/login)用=精确匹配,提高匹配效率。
  • 静态资源目录(如/static//image/)用^~前缀匹配,避免被正则匹配干扰。
  • 需区分大小写的URI(如API接口/User/Info)用~正则匹配。
  • 无需区分大小写的URI(如静态资源/css/CSS)用~*正则匹配。
  • 通用前缀URI(如/blog/下的所有文章)用无修饰符匹配,作为兜底规则。
相关推荐
三七互娱后端团队4 小时前
Serena语义检索在AI CodeReview中的应用
后端
渣哥4 小时前
从 READ_UNCOMMITTED 到 SERIALIZABLE:Spring 事务隔离级别全解析
javascript·后端·面试
Codelinghu4 小时前
【bug】大模型微调bug:OSError: Failed to load tokenizer.| Lora
后端
Frank_zhou5 小时前
虚拟线程池
后端
aiopencode5 小时前
iOS混淆与IPA加固实战手记,如何构建苹果应用防反编译体系
后端
cxyxiaokui0015 小时前
JDK 动态代理 vs CGLIB:原理、区别与 Spring AOP 底层揭秘
java·后端·spring
00后程序员张5 小时前
Swoole HTTPS 实战,在生产环境部署、性能权衡与排查流程
后端·ios·小程序·https·uni-app·iphone·swoole
我命由我123455 小时前
PDFBox - PDDocument 与 byte 数组、PDF 加密
java·服务器·前端·后端·学习·java-ee·pdf
考虑考虑5 小时前
go格式化时间
后端·go