接入 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运行,负责读取配置、管理workerworker 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 端口 |
官方文档
Nginx命令行参数:https://nginx.org/en/docs/switches.htmlNginx控制(信号说明):https://nginx.org/en/docs/control.htmlNginx核心模块(worker_processes、user、pid):https://nginx.org/en/docs/ngx_core_module.htmlNginxBeginner's Guide:https://nginx.org/en/docs/beginners_guide.htmlGNU Bash启动文件:https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html
总结
改配置的固定流程是 -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 的层级关系),再用它部署外卖平台的静态资源。