玩转Nginx 09 --- 运维排障:三场"火灾"实战演练
一、本课目标(最后一课)
前 8 课学会了"怎么建",本课教你"坏了怎么修"。人为制造三场最常见的生产事故(火灾),用同一套排障四步法亲手扑灭,把"会看日志、会找证据"练成肌肉记忆。
二、排障四步法(本课主心骨)
① 看证据 → ② 查现场 → ③ 看日志 → ④ 定位修复
遇到任何异常,永远先问"证据是什么",不要瞎猜、不要乱改配置。
三、火灾 1:语法错误(缺分号)--- 配置文件写错了
完整命令流程
bash
# ── 注入(制造事故):写 site3 配置时漏掉分号 ──
# 错误写法:server 127.0.0.1:8090 ← 漏了结尾的 ;
# 正确写法:server 127.0.0.1:8090; ← 每个指令必须以 ; 收尾
# ── ① 看证据:reload 被拒 / 站点异常 ──
# curl 显示 502 Bad Gateway(upstream 配置语法错误导致整块 server 失效)
# ── ③ 看日志 / ② 查现场 ──
sudo nginx -t
# 输出:nginx: [emerg] directive "server" is not terminated by ";" in
# /etc/nginx/sites-available/site3:XX(红字指明文件+行号)
cat /etc/nginx/sites-available/site3 # 打开配置肉眼找漏分号
# ── ④ 修复:补上分号 → 体检 → 重载 ──
sudo tee /etc/nginx/sites-available/site3 > /dev/null << 'EOF'
...(完整正确配置,upstream 里 server 127.0.0.1:8090; 带分号)...
EOF
sudo nginx -t && sudo systemctl reload nginx
# ── 验证:负载均衡轮询恢复 ──
curl -s http://127.0.0.1:8082/
# 输出交替出现 backend 与 backend-B,恢复正常
| 四步 | 操作 | 现象 |
|---|---|---|
| 注入 | site3 配置里 server 127.0.0.1:8090 漏写 ; |
reload 后站点 502 |
| ① 看证据 | nginx -t |
missing ";" / not terminated by ";",红字报错并指明文件+行号 |
| ② 查现场 | cat 配置 |
一眼看出漏分号 |
| ④ 修复 | 补上 ; → nginx -t → reload |
负载均衡轮询恢复正常 |
核心认知:nginx -t 是配置的"体检",语法错会直接红字报行号,不合格绝不放行(reload 会被拒绝)。
四、火灾 2:端口冲突 --- "门牌号"被人占了
完整命令流程
bash
# ── 注入(制造事故):在 site1 目录里起一个野 python 服务占住 8085 ──
nohup python3 -m http.server 8085 --bind 0.0.0.0 > /tmp/port8085.log 2>&1 &
# 注意:它从"当前启动目录"发文件,所以 ~/桌面/work/Nginx-lab/site1 下的
# 草稿页"我的第一个站点"被它拿走了
# ── ① 看证据:配好 site5(listen 8085)后 reload"静默失败"、curl 页面不对 ──
curl -s http://127.0.0.1:8085/
# 输出是"我的第一个站点"草稿页(python 的),不是 nginx 的站点
# ── ③ 看日志:bind 失败铁证 ──
sudo tail /var/log/nginx/error.log
# [emerg] bind() to 0.0.0.0:8085 failed (98: Unknown error)
# [emerg] still could not bind()
# ── ② 查现场:端口主人现形 ──
ss -tlnp | grep 8085
# LISTEN 0 511 0.0.0.0:8085 ... users:(("python3",pid=4060819,...))
# ── ④ 修复:杀占位者 → reload → 复验(一条组合拳) ──
kill 4060819 && sleep 1 && sudo systemctl reload nginx && ss -tlnp | grep 8085 && curl -s http://127.0.0.1:8085/ | head -3
# ── 验证:验明正身,确认是 nginx 的站点在营业 ──
curl -s http://127.0.0.1:8085/ | grep -i title
# 输出:<title>我的实战综合站</title> ← 8085 改朝换代成功
| 四步 | 操作 | 现象 |
|---|---|---|
| 注入 | 野 python 服务(http.server 8085)占住 8085 |
nginx 配好 site5 却接不上 |
| ① 看证据 | curl http://127.0.0.1:8085/ |
页面返回"我的第一个站点"(python 从启动目录发的),不是 nginx 的站点 |
| ③ 看日志 | tail /var/log/nginx/error.log |
bind() to 0.0.0.0:8085 failed (98) + still could not bind() |
| ② 查现场 | `ss -tlnp | grep 8085` |
| ④ 修复 | kill 4060819 → reload → 再 ss / curl |
nginx 接管 8085,页面变"我的实战综合站" |
三个关键认知:
nginx -t只查语法,不抢端口 ------它体检通过不代表服务能起来;真正抢端口发生在 reload 那一刻。- reload 失败不会弄死现有服务 ------nginx 抢端口失败会放弃新配置、回滚保持旧配置继续营业(这次是例外:8085 还有 python 活着,所以 curl 到了 python,但其它端口的老配置毫发无损)。所以 reload 失败"还有救":先修好病因,再 reload 一次。
- 端口的主人用
ss -tlnp查------看到 PID 就能顺藤摸瓜找到进程并处置。
杀进程用
kill PID;观察端口ss -tlnp | grep 端口号。后端开发被"端口被占"卡住,这套组合拳是家常便饭。
五、火灾 3:权限问题(404/403)--- 门锁了
完整命令流程
bash
# ── 注入(制造事故):给站点目录上锁,只有 root 能进 ──
sudo chmod 700 /var/www/mysite-front && ls -ld /var/www/mysite-front
# drwx------ ← 700 权限:www-data 连门都进不去
# ── ① 看证据:站点 403 ──
curl -sI http://127.0.0.1:8085/ | head -3
# HTTP/1.1 403 Forbidden
# Server: nginx/1.18.0 (Ubuntu)
# ── ③ 看日志:Permission denied 铁证 ──
sudo tail -3 /var/log/nginx/error.log
# "/var/www/mysite-front/index.html" is forbidden (13: Permission denied)
# ── ④ 修复:开锁(755 = 目录可进可读) ──
sudo chmod 755 /var/www/mysite-front && ls -ld /var/www/mysite-front
# drwxr-xr-x ← 恢复
# ── 验证:立即可用,无需 reload! ──
curl -s http://127.0.0.1:8085/ | grep -i title
# 输出:<title>我的实战综合站</title> ← 满血回归
| 四步 | 操作 | 现象 |
|---|---|---|
| 注入 | chmod 700 /var/www/mysite-front(只有 root 能进) |
站点 403 |
| ① 看证据 | curl -sI |
HTTP/1.1 403 Forbidden |
| ③ 看日志 | tail /var/log/nginx/error.log |
"/var/www/mysite-front/index.html" is forbidden (13: Permission denied) |
| ④ 修复 | chmod 755 /var/www/mysite-front |
立即恢复 200,无需 reload |
403 vs 404 判读(本课最值钱的知识点):
| 响应 | 含义 | 日志里的差别 |
|---|---|---|
| 404 Not Found | "地址不存在"------nginx 连路径都摸不到(上级目录都进不去,stat 失败) | stat() failed (13: Permission denied) |
| 403 Forbidden | "人在但门锁了"------nginx 看得见文件,打开被拒绝 | is forbidden (13: Permission denied) |
核心认知:危险信号永远是同一个单词 Permission denied。 权限链上任何一环断掉(/home/yfh 是 750、目录变成 700......),www-data 进不去就报错。
另一个关键认知:权限是文件系统的事,不是 nginx 配置的事------chmod 改完立即生效,不需要 reload!
六、三场火灾横向对比(背下来)
| 火灾 | 根因 | 危险信号 | 修复 | 要 reload 吗 |
|---|---|---|---|---|
| 语法错误 | 配置写错(缺 ;) |
nginx -t 红字 |
改配置 | ✅ 必须 |
| 端口冲突 | 端口被别的进程占 | bind() failed (98) + ss 现形 |
kill 占位者 | ✅ 必须 |
| 权限问题 | 目录/文件权限不够 | Permission denied |
chmod 改权限 | ❌ 不需要 |
共同套路:永远先看证据和日志定位根因,再动手。"改配置前先 nginx -t,动端口先 ss,权限问题先看 Permission denied。"
七、排障急救命令清单(复制即用)
bash
# 1. 配置体检(改配置后必做)
sudo nginx -t
# 2. 重载配置(让新配置生效)
sudo systemctl reload nginx
# 3. 看错误日志(排障主战场)
sudo tail -50 /var/log/nginx/error.log
# 4. 看端口被谁占了
ss -tlnp | grep 端口号
# 5. 杀占位进程
kill PID
# 6. 验证服务真的活着(-sI 看响应头,-s 看正文,grep title 验明正身)
curl -sI http://127.0.0.1:端口/
curl -s http://127.0.0.1:端口/ | grep -i title
# 7. 修权限(755 = 目录可进,644 = 文件可读)
sudo chmod 755 目录
sudo chmod 644 文件
# 8. 看文件权限(-d 看目录本身,一目了然)
ls -ld 目录
八、课程毕业总结
9 课打通 nginx 全链路:解剖架构 → 静态服务 → location 规则 → 反向代理 → 负载均衡 → HTTPS → 性能缓存 → 综合实战 → 排障急救。
一个站点 = 一个配置文件里的多个 server 块(门);端口是门牌号;nginx -t 是体检、reload 是换班、error.log 是案发现场、ss 是找茬神器------以后任何服务"坏了",先证据,后日志,再动手。