Nginx平滑升级核心原理与location配置案例详解
作者:YC运维
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、静态压缩等),升级时需完整保留原参数,否则新程序会丢失原有功能。
操作命令:
[root@nginx ~]# nginx -V # 大写V,可显示编译参数;小写v仅显示版本
执行结果(含关键编译参数,需完整记录):
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 # 错误日志路径
3. 下载新模块(echo-nginx-module)
echo-nginx-module是OpenResty社区开发的Nginx模块,用于在响应中直接输出指定内容(如文本、变量等),常用于调试或简单接口返回。
操作步骤:
- 本地下载模块源码:访问echo-nginx-module GitHub地址,点击“Code”→“Download ZIP”,获取压缩包(如
echo-nginx-module-master.zip
)。 - 上传至Nginx服务器:通过FTP、SCP等工具,将压缩包上传到Nginx服务器的
/root
目录(或其他自定义目录,需记住路径)。
4. 重新编译Nginx(含新模块)
编译前需确保服务器已安装编译依赖(如gcc
、unzip
、pcre-devel
、openssl-devel
等),若缺少依赖会导致编译失败。
操作步骤:
(1)安装编译依赖工具
# 安装unzip(用于解压模块压缩包) [root@nginx ~]# yum -y install unzip # 安装Nginx编译必备依赖(若已安装可跳过) [root@nginx ~]# yum -y install gcc pcre-devel openssl-devel zlib-devel
(2)解压模块与Nginx源码包
- 解压新模块包:
[root@nginx ~]# unzip echo-nginx-module-master.zip # 解压后生成目录echo-nginx-module-master
- 解压Nginx源码包:
平滑升级需基于原版本的源码进行编译,需确保服务器存在Nginx 1.24.0的源码包(若已删除,需重新从Nginx官网下载nginx-1.24.0.tar.gz
并上传):[root@nginx ~]# tar -zxf nginx-1.24.0.tar.gz # 解压后生成目录nginx-1.24.0
(3)配置编译参数(含新模块)
进入Nginx源码目录,执行./configure
命令,完整保留原编译参数,并通过--add-module
指定新模块的解压路径:
[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 # 新增:新模块的解压路径(相对源码目录)
关键说明:--add-module
的路径需准确(此处../echo-nginx-module-master
表示“上一级目录下的echo-nginx-module-master”,因源码目录在/root/nginx-1.24.0
,模块目录在/root
),路径错误会导致模块加载失败。
(4)编译生成新Nginx程序
执行make
命令编译(不可执行make install
,否则会覆盖原安装目录,导致配置文件丢失):
# 执行编译(过程约1-3分钟,依赖服务器性能) [root@nginx nginx-1.24.0]# make
(5)验证编译结果
编译完成后,新的Nginx程序会生成在源码目录的objs
子目录下,需确认程序存在:
# 查看objs目录内容 [root@nginx nginx-1.24.0]# ls objs/
预期结果:目录中需包含nginx
可执行文件(即新编译的Nginx程序),其他文件如addon
(模块相关)、src
(源码编译文件)等为正常编译产物。
5. 备份旧程序、替换并重启服务
此步骤需严格按顺序执行,避免因操作失误导致服务中断或程序损坏。
(1)对比新旧程序的编译参数(验证新模块是否加载)
- 查看旧程序参数(原Nginx):
[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
- 查看新程序参数(编译后的程序):
[root@nginx nginx-1.24.0]# objs/nginx -V # 需包含--add-module=../echo-nginx-module-master 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 --add-module=…/echo-nginx-module-master
**关键验证**:新程序的`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
(3)备份旧程序
将原Nginx程序(/usr/local/nginx/sbin/nginx
)备份到安全目录(如/opt
),便于升级失败后回滚:
[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/
(4)替换旧程序为新程序
将objs
目录下的新程序覆盖到原安装路径:
[root@nginx nginx-1.24.0]# cp objs/nginx /usr/local/nginx/sbin/ # 系统会提示“是否覆盖”,输入y确认 cp:是否覆盖'/usr/local/nginx/sbin/nginx'? y
(5)启动新Nginx服务并验证
# 启动新服务 [root@nginx nginx-1.24.0]# /usr/local/nginx/sbin/nginx # 验证服务状态(80端口监听表示启动成功) [root@nginx nginx-1.24.0]# ss -anlt | grep 80
预期结果:输出类似LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
,表示Nginx已正常启动。
(6)最终验证新模块是否生效
查看Nginx版本与参数,确认新模块已加载:
[root@nginx ~]# nginx -V
预期结果:参数中包含--add-module=../echo-nginx-module-master
,表示平滑升级完成。
6. 测试echo模块功能
通过配置location
使用echo模块,验证其是否正常工作。
(1)修改Nginx配置文件
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
在server
块中添加如下location
配置(用于匹配根路径/
的请求):
server { listen 80; server_name localhost; # 新增:使用echo模块输出文本“ycy” location / { echo "ycy"; # echo模块的核心指令,直接输出指定内容 } }
(2)检查配置文件语法正确性
修改配置后需先检查语法,避免因错误导致服务启动失败:
[root@nginx ~]# nginx -t
预期结果:输出nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
和nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
,表示语法正确。
(3)重载Nginx配置(无需重启服务)
[root@nginx ~]# nginx -s reload
(4)验证echo模块功能
- 浏览器访问:直接在浏览器输入Nginx服务器IP(如
192.168.100.10
),会触发文件下载(因echo模块输出的文本无Content-Type
头,浏览器默认当作文件处理,属于正常现象)。 - 命令行访问(推荐,更准确):在本地Windows或其他Linux机器上执行
curl
命令:# Windows cmd中执行(需确保本地能ping通服务器IP) [root@ycy3 html]# curl http://192.168.100.10 ycy
**预期结果**:输出`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; }
- 修饰符:可选,用于定义匹配规则(如精确匹配、正则匹配等),决定匹配优先级。
- 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_files 、error_page 跳转),客户端无法直接访问 | 仅内部使用 | 内部跳转(如404页面、502错误页面) | location @error_404 { return 404 "Page Not Found"; } |
(三)location匹配顺序与优先级
Nginx处理location
匹配时,严格遵循以下优先级(从高到低),一旦匹配成功且满足“停止搜索”条件,即不再检查后续规则:
=
精确匹配:优先检查所有带=
的location
,若URI完全匹配,直接执行该配置块,停止后续搜索。^~
前缀匹配:检查带^~
的location
,若URI以pattern
开头,直接执行该配置块,停止后续搜索(包括正则匹配)。- 正则匹配(
~
/~*
):按location
在配置文件中的定义顺序检查正则匹配(~
和~*
优先级相同,谁在前先匹配谁),若匹配成功,执行该配置块,停止后续搜索。 - 无修饰符前缀匹配:最后检查无修饰符的
location
,匹配URI前缀最长的location
(若多个无修饰符location
的pattern
均为URI前缀,选择最长的那个),执行该配置块。
(四)实操案例(基于echo模块验证)
以下案例均基于“已安装echo模块”的Nginx环境,通过echo
输出文本验证匹配结果,所有案例的server
块基础配置如下(仅修改location
部分):
server { listen 80; server_name localhost; # 服务器IP为192.168.100.10 # 以下为不同案例的location配置 }
案例1:无修饰符的前缀匹配
配置内容:
location /abc { echo "cy"; # 匹配成功后输出“cy” }
匹配规则:URI以/abc
开头即匹配,不区分后续路径。
测试结果(通过curl
命令验证):
# 测试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>
案例2:=精确匹配(匹配固定URI)
子案例2.1:pattern
为/abc
(无末尾/
)
配置内容:
location = /abc { echo "ycy"; # 仅匹配/abc时输出 }
匹配规则:URI必须与/abc
完全一致,多一个/
或多字符均不匹配。
测试结果:
# 测试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>
子案例2.2:pattern
为/abc/
(有末尾/
)
配置内容:
location = /abc/ { echo "ycy"; # 仅匹配/abc/时输出 }
测试结果:
# 测试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>
关键结论:=
修饰符对/
敏感,配置时需严格匹配实际请求的URI格式(如客户端请求是/abc
还是/abc/
)。
案例3:~正则匹配(区分大小写)
配置内容:
location ~ /abc$ { # 正则表达式:匹配以“/abc”结尾的URI($表示结尾) echo "ycy"; }
匹配规则:URI必须以/abc
结尾,且区分大小写(/ABC
、/aBc
不匹配)。
测试结果:
# 测试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>
案例4:=与~的优先级对比
配置内容(=
和~
同时存在,=
在前):
# 正则匹配:以/abc结尾的URI location ~ /abc$ { echo "ycy"; } # 精确匹配:仅/abc location = /abc { echo "cy"; }
匹配规则:根据优先级,=
精确匹配高于~
正则匹配,因此/abc
会优先匹配=
的location
。
测试结果:
# 测试: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
关键结论:无论=
和~
在配置文件中的顺序如何,=
的优先级始终最高,优先匹配。
案例5:~*正则匹配(不区分大小写)
配置内容:
location ~* /abc$ { # 正则表达式:以/abc结尾,不区分大小写 echo "ycy"; }
匹配规则:URI以/abc
结尾,且不区分大小写(/ABC
、/aBc
均匹配)。
测试结果:
# 测试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
(五)location匹配优先级总结(从高到低)
#依次输出测试优先级 location = /abc { echo "ycy1"; } location ~ /abc { echo "ycy2"; } location ~*/abc { echo "ycy3"; } location ^~ /abc { echo "ycy4"; }
为便于记忆,将location
的匹配优先级整理为以下顺序,实际配置时需严格遵循:
=
精确匹配:完全匹配URI,优先级最高,匹配后立即执行,停止后续搜索。^~
前缀匹配:URI以pattern
开头,匹配后停止后续搜索(包括正则匹配)。~
/~*
正则匹配:按配置文件中location
的定义顺序匹配,先定义的优先,匹配后停止搜索(~
和~*
优先级相同,仅区分大小写)。- 无修饰符前缀匹配:URI以
pattern
开头,匹配最长前缀的location
,优先级最低。
配置建议:
- 固定URI(如
/
、/api/login
)用=
精确匹配,提高匹配效率。 - 静态资源目录(如
/static/
、/image/
)用^~
前缀匹配,避免被正则匹配干扰。 - 需区分大小写的URI(如API接口
/User/Info
)用~
正则匹配。 - 无需区分大小写的URI(如静态资源
/css
、/CSS
)用~*
正则匹配。 - 通用前缀URI(如
/blog/
下的所有文章)用无修饰符匹配,作为兜底规则。
到此这篇关于Nginx平滑升级核心原理与location配置案例详解的文章就介绍到这了,更多相关Nginx平滑升级原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!