Java 项目实战: 外卖平台优化-Nginx常用命令与环境变量配置

接入 Nginx: 版本检查、启停重载与环境变量配置

纲要

本篇对应课程 day02 的「Nginx 命令」,覆盖全部六类命令:

  • 查看版本 :nginx -v 与 nginx -V 的区别(后者能看到编译参数)
  • 检查配置 :nginx -t,改配置后的必做动作,如何读懂报错
  • 启动与停止 :nginx、nginx -s stop,以及 master/worker 双进程的确认方法
  • 停止命令补充 :stop 与 quit 的差异、nginx.pid 的生命周期
  • 重新加载 :nginx -s reload,改 worker_processes 后的平滑生效验证
  • 环境变量配置 :把 /usr/local/nginx/sbin 加入 PATH,实现任意目录执行

#mermaid-svg-7QrsfaBwKBreNPzT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7QrsfaBwKBreNPzT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7QrsfaBwKBreNPzT .error-icon{fill:#552222;}#mermaid-svg-7QrsfaBwKBreNPzT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7QrsfaBwKBreNPzT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7QrsfaBwKBreNPzT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT .marker.cross{stroke:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7QrsfaBwKBreNPzT p{margin:0;}#mermaid-svg-7QrsfaBwKBreNPzT defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-7QrsfaBwKBreNPzT g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-7QrsfaBwKBreNPzT g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-7QrsfaBwKBreNPzT g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-7QrsfaBwKBreNPzT g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-7QrsfaBwKBreNPzT .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-7QrsfaBwKBreNPzT .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-7QrsfaBwKBreNPzT .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-7QrsfaBwKBreNPzT .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-7QrsfaBwKBreNPzT .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-7QrsfaBwKBreNPzT .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-7QrsfaBwKBreNPzT .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-7QrsfaBwKBreNPzT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7QrsfaBwKBreNPzT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7QrsfaBwKBreNPzT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7QrsfaBwKBreNPzT .edgeLabel .label text{fill:#333;}#mermaid-svg-7QrsfaBwKBreNPzT .label div .edgeLabel{color:#333;}#mermaid-svg-7QrsfaBwKBreNPzT .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-7QrsfaBwKBreNPzT .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-7QrsfaBwKBreNPzT .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-7QrsfaBwKBreNPzT .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7QrsfaBwKBreNPzT .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7QrsfaBwKBreNPzT #statediagram-barbEnd{fill:#333333;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7QrsfaBwKBreNPzT .cluster-label,#mermaid-svg-7QrsfaBwKBreNPzT .nodeLabel{color:#131300;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-7QrsfaBwKBreNPzT .note-edge{stroke-dasharray:5;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-note text{fill:black;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram-note .nodeLabel{color:black;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagram .edgeLabel{color:red;}#mermaid-svg-7QrsfaBwKBreNPzT #dependencyStart,#mermaid-svg-7QrsfaBwKBreNPzT #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-7QrsfaBwKBreNPzT .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7QrsfaBwKBreNPzT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} nginx
nginx -s reopen

重开日志
nginx -s stop

立即终止
nginx -s quit

优雅退出
已停止
运行中

一、查看版本

nginx -v:查看版本号

bash 复制代码
cd /usr/local/nginx/sbin
./nginx -v

输出:

txt 复制代码
nginx version: nginx/1.16.1

小写 -v 只输出版本。

nginx -V:查看版本与编译参数

bash 复制代码
./nginx -V

输出:

txt 复制代码
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
configure arguments: --prefix=/usr/local/nginx --with-http_ssl_module

大写 -V 才是排查问题时真正有用的 。它输出 configure arguments,即当初编译时用的全部参数。这些信息决定了:

  • 装了哪些模块(有没有 ssl、有没有 http_v2)
  • --prefix 是多少(配置文件、日志在哪)
  • 各种路径(--conf-path、--pid-path 等)

实用场景 :接手一台别人装的 Nginx 时,第一件事就是 nginx -V,能立刻搞清楚它的能力和路径布局。

二、检查配置文件正确性

为什么必须先检查

Nginx 启动时会自动加载 conf/nginx.conf。如果配置有语法错误,启动时才会报错;更麻烦的是 -s reload 时配置错误,会导致重载失败,服务仍跑旧配置,而你可能以为改生效了。

所以约定俗成的流程是:改完配置 → nginx -t → 通过后 reload。

执行检查

bash 复制代码
./nginx -t

正常输出:

txt 复制代码
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

看到 syntax is ok 和 test is successful 才说明配置没问题。

注意第一行会明确告诉你检查的是哪个文件 ------/usr/local/nginx/conf/nginx.conf。如果实际用的是其他配置文件(用 -c 指定),这里也会相应变化:

bash 复制代码
./nginx -t -c /usr/local/nginx/conf/nginx.conf

故意写错看报错

在 conf/nginx.conf 里随便加一行 abc:

bash 复制代码
vim /usr/local/nginx/conf/nginx.conf
# 进入后按 i,在文件里输入 abc,ESC 后 :wq 保存退出

再检查:

bash 复制代码
./nginx -t

输出:

txt 复制代码
nginx: [emerg] unknown directive "abc" in /usr/local/nginx/conf/nginx.conf:3
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed

报错格式是 unknown directive "xxx" in <文件>:<行号>------文件、行号、原因三要素齐全,定位极快。

[emerg] 是日志级别前缀,表示 emergency(紧急)。

改回来(在 vim 中按两下 dd 删除当前行,:wq 保存),再检查即恢复 successful。

常见配置错误类型

报错 含义 常见原因
unknown directive "xxx" 未知指令 拼写错误、模块未编译进来
directive "xxx" is not terminated by ";" 指令未以分号结尾 漏写 ;
unexpected "}" 花括号不匹配 多写或少写 }
invalid number of arguments in "xxx" directive 参数个数不对 指令参数写多或写少
host not found in upstream "xxx" 上游主机名解析失败 proxy_pass 的地址写错
duplicate "xxx" 指令重复 同一作用域配了两次
[emerg] bind() to 0.0.0.0:80 failed 端口被占 其它进程占用了 80

注意区分 nginx -t 能检查什么、不能检查什么 :它只做语法检查 ,不检查语义。比如 proxy_pass http://192.168.1.999:8080; 语法没问题会通过,但实际转发会失败。

三、启动 Nginx

启动

bash 复制代码
cd /usr/local/nginx/sbin
./nginx

不带任何参数即启动。启动成功后没有任何输出------Unix 的惯例是"没有消息就是好消息"。

确认进程

bash 复制代码
ps -ef | grep nginx

输出:

txt 复制代码
root     116947      1  0 09:30 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody   116948 116947  0 09:30 ?        00:00:00 nginx: worker process
root     116950 116900  0 09:30 pts/0    00:00:00 grep --color=auto nginx

三行里第三行是 grep 命令自身,可以忽略。真正的是前两行:

  • master process :主进程,以 root 运行,负责读取配置、管理 worker
  • worker process :工作进程,以 nobody 运行(配置里的 user 指令指定),真正处理请求

为什么 master 是 root、worker 是 nobody :监听 80 端口需要 root 权限(1024 以下为特权端口),所以 master 必须 root。而处理用户请求不需要特权,用低权限的 nobody 可以在被攻击时限制危害范围------这是典型的权限分离设计。

默认进程数与修改

默认 worker_processes 1,即一个 master + 一个 worker。

修改 conf/nginx.conf:

nginx 复制代码
worker_processes  2;

推荐写法是设为 CPU 核数,或直接写 auto 让 Nginx 自动检测:

nginx 复制代码
worker_processes  auto;

改完后必须 reload 才生效(见后文第五节)。

浏览器验证

访问 http://192.168.138.100(80 端口可省略),看到:

txt 复制代码
Welcome to nginx!
...
Thank you for using nginx.

即启动成功。

访问不到怎么办

第一怀疑对象是防火墙 ,而不是 Nginx 本身:

bash 复制代码
# 查看防火墙状态
systemctl status firewalld

# 临时关闭(测试环境)
systemctl stop firewalld

# 生产推荐:只放行 80 端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload

刷新浏览器即可访问。

判断依据 :如果 ps 能看到进程、nginx -t 也通过,但浏览器访问不到,那 99% 是防火墙或安全组。云服务器(阿里云、ECS)还要检查安全组规则,这是比系统防火墙更外层的一道拦截。

四、停止 Nginx

nginx -s stop

bash 复制代码
/usr/local/nginx/sbin/nginx -s stop

-s 是 signal 的缩写,stop 表示立即停止。

执行后:

  • master 与 worker 进程全部消失
  • logs/nginx.pid 文件被自动删除
  • 浏览器刷新访问不到

验证:

bash 复制代码
ps -ef | grep nginx
# 只剩 grep 自身那一行

相对路径与绝对路径

./nginx 这种写法要求当前目录必须是 sbin 。在其他目录(如 html)下执行 ./nginx 会报:

txt 复制代码
-bash: ./nginx: No such file or directory

解决办法是用绝对路径:

bash 复制代码
/usr/local/nginx/sbin/nginx -s stop

这个写法在任何目录下都能用。

stop 与 quit 的区别

命令 信号 行为 适用场景
nginx -s stop TERM 立即终止,当前正在处理的请求直接断开 快速停止、测试环境
nginx -s quit QUIT 优雅退出,先停止接收新连接,处理完已有请求再退出 生产环境

生产环境务必用 quit 。stop 会让正在传输的响应被截断,用户看到的是加载一半的页面或连接重置错误。

quit 的完整流程:
客户端连接 worker 进程 master 进程 运维 客户端连接 worker 进程 master 进程 运维 #mermaid-svg-gj1WclAeR0dfFAWR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gj1WclAeR0dfFAWR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gj1WclAeR0dfFAWR .error-icon{fill:#552222;}#mermaid-svg-gj1WclAeR0dfFAWR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gj1WclAeR0dfFAWR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gj1WclAeR0dfFAWR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gj1WclAeR0dfFAWR .marker.cross{stroke:#333333;}#mermaid-svg-gj1WclAeR0dfFAWR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gj1WclAeR0dfFAWR p{margin:0;}#mermaid-svg-gj1WclAeR0dfFAWR .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gj1WclAeR0dfFAWR text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-gj1WclAeR0dfFAWR .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gj1WclAeR0dfFAWR .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-gj1WclAeR0dfFAWR .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-gj1WclAeR0dfFAWR .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-gj1WclAeR0dfFAWR #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-gj1WclAeR0dfFAWR .sequenceNumber{fill:white;}#mermaid-svg-gj1WclAeR0dfFAWR #sequencenumber{fill:#333;}#mermaid-svg-gj1WclAeR0dfFAWR #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-gj1WclAeR0dfFAWR .messageText{fill:#333;stroke:none;}#mermaid-svg-gj1WclAeR0dfFAWR .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gj1WclAeR0dfFAWR .labelText,#mermaid-svg-gj1WclAeR0dfFAWR .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-gj1WclAeR0dfFAWR .loopText,#mermaid-svg-gj1WclAeR0dfFAWR .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-gj1WclAeR0dfFAWR .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gj1WclAeR0dfFAWR .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-gj1WclAeR0dfFAWR .noteText,#mermaid-svg-gj1WclAeR0dfFAWR .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-gj1WclAeR0dfFAWR .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gj1WclAeR0dfFAWR .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gj1WclAeR0dfFAWR .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gj1WclAeR0dfFAWR .actorPopupMenu{position:absolute;}#mermaid-svg-gj1WclAeR0dfFAWR .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-gj1WclAeR0dfFAWR .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gj1WclAeR0dfFAWR .actor-man circle,#mermaid-svg-gj1WclAeR0dfFAWR line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-gj1WclAeR0dfFAWR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} kill -QUIT 关闭监听 socket 不再接受新连接 发送 QUIT 信号 继续处理已有请求 请求完成 所有连接处理完毕后退出 退出通知 删除 nginx.pid master 退出

如果 quit 长时间停不下来,说明有长连接(如 WebSocket)未结束,此时才考虑用 stop 强制。

其他信号

命令 信号 作用
nginx -s reload HUP 重新加载配置文件
nginx -s reopen USR1 重新打开日志文件(配合日志切割)

五、重新加载配置文件

为什么需要 reload

修改配置后,配置不会自动生效。最朴素的办法是"先停止再启动",但需要两条命令,且期间服务中断。

reload 只需一条命令,且不中断服务。

完整演示

当前状态 :worker_processes 1,一个 worker 进程。

修改配置:

bash 复制代码
vim /usr/local/nginx/conf/nginx.conf

把:

nginx 复制代码
worker_processes  1;

改成:

nginx 复制代码
worker_processes  2;

保存退出。此时配置未生效,进程数没变化。

执行 reload:

bash 复制代码
/usr/local/nginx/sbin/nginx -s reload

再看进程:

bash 复制代码
ps -ef | grep nginx
txt 复制代码
root     116947      1  0 09:30 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody   116948 116947  0 09:30 ?        00:00:00 nginx: worker process
nobody   116949 116947  0 09:35 ?        00:00:00 nginx: worker process

变成两个 worker------配置生效了。

reload 的实现原理

这是 Nginx 最优雅的设计之一:
新 worker 旧 worker master 运维 新 worker 旧 worker master 运维 #mermaid-svg-Q9X1CyUskSEBY114{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Q9X1CyUskSEBY114 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Q9X1CyUskSEBY114 .error-icon{fill:#552222;}#mermaid-svg-Q9X1CyUskSEBY114 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Q9X1CyUskSEBY114 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Q9X1CyUskSEBY114 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Q9X1CyUskSEBY114 .marker.cross{stroke:#333333;}#mermaid-svg-Q9X1CyUskSEBY114 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Q9X1CyUskSEBY114 p{margin:0;}#mermaid-svg-Q9X1CyUskSEBY114 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Q9X1CyUskSEBY114 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Q9X1CyUskSEBY114 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Q9X1CyUskSEBY114 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Q9X1CyUskSEBY114 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Q9X1CyUskSEBY114 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Q9X1CyUskSEBY114 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Q9X1CyUskSEBY114 .sequenceNumber{fill:white;}#mermaid-svg-Q9X1CyUskSEBY114 #sequencenumber{fill:#333;}#mermaid-svg-Q9X1CyUskSEBY114 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Q9X1CyUskSEBY114 .messageText{fill:#333;stroke:none;}#mermaid-svg-Q9X1CyUskSEBY114 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Q9X1CyUskSEBY114 .labelText,#mermaid-svg-Q9X1CyUskSEBY114 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Q9X1CyUskSEBY114 .loopText,#mermaid-svg-Q9X1CyUskSEBY114 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Q9X1CyUskSEBY114 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Q9X1CyUskSEBY114 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Q9X1CyUskSEBY114 .noteText,#mermaid-svg-Q9X1CyUskSEBY114 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Q9X1CyUskSEBY114 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Q9X1CyUskSEBY114 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Q9X1CyUskSEBY114 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Q9X1CyUskSEBY114 .actorPopupMenu{position:absolute;}#mermaid-svg-Q9X1CyUskSEBY114 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Q9X1CyUskSEBY114 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Q9X1CyUskSEBY114 .actor-man circle,#mermaid-svg-Q9X1CyUskSEBY114 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Q9X1CyUskSEBY114 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 新旧 worker 短暂共存 alt 配置有误 配置正确 nginx -s reload (HUP) 检查新配置语法 报错,继续使用旧配置 服务不受影响 用新配置启动新 worker 开始接收新连接 发送 QUIT 信号 处理完旧连接后退出

关键点:

  • master 进程不变 (PID 还是 116947),变的是 worker
  • 先启新 worker,再优雅退出旧 worker ,中间新旧共存,所以任何时刻都有进程在服务,零中断
  • 配置有错时 master 拒绝加载,继续用旧配置运行,服务完全不受影响

这就是为什么改配置前一定要 nginx -t------虽然 reload 自身有保护,但提前检查能让你明确知道是"配置没生效"还是"生效了但行为不对",避免误判。

reload 与 restart 的选择

场景 建议
改了 server、location、upstream reload
改了 worker_processes、worker_connections reload
更换了 nginx 二进制(升级、加模块) 必须 stop 后 start
改了 --prefix 级别的路径配置 必须 stop 后 start
不确定 先 nginx -t,再 reload

六、配置环境变量

问题

每次都要写 /usr/local/nginx/sbin/nginx 这么长一串,或者必须先 cd 到 sbin 目录,很麻烦:

bash 复制代码
cd /
nginx -s reload
# -bash: nginx: command not found

解决:把 sbin 加入 PATH

编辑系统环境变量文件:

bash 复制代码
vim /etc/profile

按 i 进入编辑模式,找到 export PATH=... 那一行,在末尾追加:

bash 复制代码
export PATH=$PATH:/usr/local/nginx/sbin

或者直接在原有值后面加冒号和路径:

bash 复制代码
export PATH=$JAVA_HOME/bin:/usr/local/nginx/sbin:$PATH

注意 :路径之间用冒号 : 分隔,不是分号。写错会导致整个 PATH 失效,所有命令都用不了。

保存退出(:wq),让配置立即生效:

bash 复制代码
source /etc/profile

验证

在任意目录执行:

bash 复制代码
cd /
nginx -v
# nginx version: nginx/1.16.1

现在可以任意目录使用:

bash 复制代码
nginx              # 启动
nginx -s reload    # 重载
nginx -s stop      # 停止
nginx -t           # 检查配置

/etc/profile 与 ~/.bash_profile 的区别

文件 作用范围 加载时机
/etc/profile 所有用户 登录时
~/.bash_profile 当前用户 该用户登录时
~/.bashrc 当前用户 每次打开 bash

配置在 /etc/profile 是全局生效 ,所有用户都能用 nginx 命令。若只想给某个用户配,写进该用户的 ~/.bash_profile。

source 不能忘

修改 /etc/profile 后如果不执行 source /etc/profile,当前终端不会生效,只有重新登录才会。这是最常见的"配了却没用"的原因。

bash 复制代码
source /etc/profile
# 或简写
. /etc/profile

七、命令速查表

命令 作用 备注
nginx -v 查看版本 小写
nginx -V 查看版本 + 编译参数 大写,含 configure arguments
nginx -t 检查配置文件语法 改配置后必做
nginx -t -c <file> 检查指定配置文件
nginx 启动服务 无输出即成功
nginx -s stop 立即停止 TERM 信号
nginx -s quit 优雅停止 QUIT 信号,生产推荐
nginx -s reload 重新加载配置 HUP 信号,零中断
nginx -s reopen 重新打开日志文件 USR1 信号,配合日志切割
`ps -ef grep nginx` 查看进程
cat logs/nginx.pid 查看 master 进程 ID 仅运行时存在

八、完整运维脚本示例

把常用操作封装成脚本,减少误操作:

bash 复制代码
#!/bin/bash
# /usr/local/nginx/sbin/nginxctl.sh
# Nginx 运维脚本:封装常用命令与前置检查

NGINX_HOME=/usr/local/nginx
NGINX_BIN=${NGINX_HOME}/sbin/nginx
CONF=${NGINX_HOME}/conf/nginx.conf
PID=${NGINX_HOME}/logs/nginx.pid

is_running() {
    [ -f "${PID}" ] && kill -0 $(cat "${PID}") 2>/dev/null
}

case "$1" in
    start)
        if is_running; then
            echo "Nginx 已在运行,PID=$(cat ${PID})"
            exit 0
        fi
        ${NGINX_BIN} -t && ${NGINX_BIN}
        echo "Nginx 已启动,PID=$(cat ${PID})"
        ;;
    stop)
        if ! is_running; then
            echo "Nginx 未运行"
            exit 0
        fi
        ${NGINX_BIN} -s quit
        echo "Nginx 已优雅停止"
        ;;
    reload)
        if ! is_running; then
            echo "Nginx 未运行,无法 reload"
            exit 1
        fi
        # 先检查配置,失败则不 reload
        if ${NGINX_BIN} -t; then
            ${NGINX_BIN} -s reload
            echo "配置已重载"
        else
            echo "配置检查未通过,已取消 reload(服务仍在运行旧配置)"
            exit 1
        fi
        ;;
    status)
        if is_running; then
            echo "Nginx 运行中,PID=$(cat ${PID})"
            ps -ef | grep nginx | grep -v grep
        else
            echo "Nginx 已停止"
        fi
        ;;
    test)
        ${NGINX_BIN} -t
        ;;
    *)
        echo "用法:$0 {start|stop|reload|status|test}"
        exit 1
        ;;
esac

使用:

bash 复制代码
chmod +x /usr/local/nginx/sbin/nginxctl.sh
/usr/local/nginx/sbin/nginxctl.sh start
/usr/local/nginx/sbin/nginxctl.sh status

脚本的两个要点:

  • reload 前先 -t,失败则不执行,避免"以为生效了实际没生效"
  • is_running 用 kill -0 探测 ,比只看 pid 文件是否存在更可靠(pid 文件可能是上次异常退出残留的)

API 速览

命令 / 信号 作用
nginx -v 查看版本号
nginx -V 查看版本与编译参数(configure arguments)
nginx -t 检查配置文件语法,输出 syntax is ok / test is successful
nginx -t -c <path> 检查指定路径的配置文件
nginx 启动服务
nginx -s stop 发送 TERM 信号,立即停止
nginx -s quit 发送 QUIT 信号,优雅停止
nginx -s reload 发送 HUP 信号,平滑重载配置
nginx -s reopen 发送 USR1 信号,重开日志文件
`ps -ef grep nginx`
kill -0 <pid> 探测进程是否存在(不真正发信号)
vim /etc/profile 编辑全局环境变量
source /etc/profile 让环境变量修改立即生效
export PATH=$PATH:/usr/local/nginx/sbin 把 Nginx 的 sbin 加入 PATH
systemctl stop firewalld 关闭防火墙(仅测试环境)
firewall-cmd --add-port=80/tcp --permanent 永久放行 80 端口

官方文档

总结

改配置的固定流程是 -t 然后 reload 。nginx -t 的输出里 syntax is ok 和 test is successful 缺一不可;报错格式 unknown directive "xxx" in <文件>:<行号> 三要素齐全,定位极快。虽然 reload 本身有语法保护(配置错了会拒绝加载并继续用旧配置),但提前 -t 能让你区分"没生效"和"生效了但行为不对"。

stop 与 quit 在生产上有本质区别 。stop 发 TERM 立即断开所有连接;quit 发 QUIT 先关监听、处理完现存请求再退出。生产一律用 quit。

reload 的零中断来自"先启新 worker,再优雅退出旧 worker" 。master 进程 PID 始终不变,新旧 worker 短暂共存,任何时刻都有进程在服务。这也是为什么 nginx.pid 记的是 master 的 PID------它是稳定的,而 worker 的 PID 每次 reload 都会变。

master 是 root、worker 是 nobody 是权限分离设计 。前者需要监听 80 特权端口,后者不需要,用低权限账号能限制被攻陷时的危害范围。

配置环境变量后记得 source 。写 /etc/profile 全局生效,~/.bash_profile 只对当前用户。忘了 source 是"配了却没用"的第一原因。路径分隔符是冒号 不是分号,写错会让整个 PATH 崩掉。

下一篇进入 Nginx 的具体应用:先看 nginx.conf 的整体结构(main/events/http/server/location 的层级关系),再用它部署外卖平台的静态资源。

相关推荐
sp42a1 小时前
Java 加解密组件再设计
java
FYKJ_20101 小时前
springboot家政服务平台66766-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·spark·课程设计
caoerzhong1 小时前
开源 WMS 合规交付实务:JeeWMS 仓库管理系统在 GPL-3.0 下的源码台账与交付清单
java·开源
2601_967212721 小时前
智能轨道插座系统技术选型逻辑与行业技术路线分析
网络·经验分享
x-Achan1 小时前
Redis实现方案:更新策略、穿透、雪崩、击穿、工具封装
java·spring boot·redis·spring·bootstrap·mybatis
勇往直前plus2 小时前
Nginx 原理与配置 —— 通用指南
运维·nginx
蜗牛互联网2 小时前
Java 17调用gpt-transcribe实现会议录音转写与术语提示
java·人工智能·后端
吠品2 小时前
DicomViewer24 的 CI 又红了:MPR 测试偶发失败排查记
java·服务器·前端
Wang's Blog2 小时前
Java 项目实战: 外卖平台优化-Nginx概述与源码编译安装
java·开发语言·nginx