前段时间服务器上的 Nginx 总出幺蛾子:主进程时不时就崩,每次都得手动重启才能恢复服务。虽说临时重启能解决问题,但总不能一直盯着,趁着今天有空,干脆彻底把这个隐患解决掉。
先查了 Nginx 崩溃的原因,看日志和系统监控,大概率是内存溢出导致的 —— 于是先调整了 Nginx 的配置(比如优化 worker 进程数、调整连接数限制),至于能不能根治还得再观察。但光靠改配置不够,万一再崩了还是得手动处理,索性决定装个 Supervisor 做监控,让它接管 Nginx 的启停:只要 Nginx 进程退出,Supervisor 就自动重启,彻底解放双手。
不过折腾的过程比预想中曲折。我的 Nginx 和 Supervisor 都是通过服务器面板装的,第一步就踩了坑 —— 得先把 Nginx 自带的自启动关掉,再把 Supervisor 的自启动打开,不然两者会 “抢着管” Nginx,导致进程混乱。
接下来的问题更具体:清理旧进程时,总有残留的 Nginx 进程杀不干净;端口也时不时被占用,导致新的 Nginx 进程启动失败;一开始想通过中间脚本(比如 nginx_manage.sh)来处理清场和启动,结果又遇到各种报错…… 前前后后试了好几种方案,比如把多行命令压缩成单行、彻底删除 Supervisor 残留的配置文件、注释掉多余的 [include] 加载项,才算把所有问题理顺。
最终看着两种崩溃场景(主进程单独崩、全进程被杀死)都能被 Supervisor 自动恢复,才算松了口气。把整个过程记下来,既是给自己留个笔记,也希望能给遇到类似问题的朋友做个参考 —— 毕竟折腾过的坑,能少一个是一个。
Supervisor 守护 Nginx 全流程总结
一、环境信息
组件 | 路径 / 版本 | 说明 |
---|---|---|
Supervisor | 配置路径:/xp/server/supervisor/supervisord.conf | 面板安装(非 systemd 管理,通过进程检测状态) |
Nginx | 启动路径:/xp/server/nginx/sbin/nginx | 需守护的 Web 服务,依赖 80/443/888 端口 |
关键端口 | 80(HTTP)、443(HTTPS)、888(面板) | 需避免残留进程占用,否则 Nginx 启动失败 |
日志路径 | /xp/server/supervisor/log/ | 存放 Supervisor 主日志(supervisord.log)和 Nginx 运行日志(nginx.out.log) |
二、核心问题与排查思路
1. 问题 1:Supervisor 配置解析报错
- 现象:启动 Supervisor 时提示语法错误,指向 [program:nginx] 的 command 行
- 原因:command 用多行写法,未正确闭合引号,Supervisor 无法识别换行符
- 解决:将多行命令用 ; 压缩为单行,确保引号完整
2. 问题 2:Nginx 启动报 FATAL Exited too quickly
- 现象:Supervisor 显示 Nginx 启动后立即退出,日志提示 bind() to 0.0.0.0:80 failed (98: Address already in use)
- 原因:80/443/888 端口被残留进程(旧 Nginx 或其他服务)占用,清理不彻底
- 解决:用 netstat 杀端口占用 + killall -9 nginx 补杀残留
3. 问题 3:提示 can't find command '/usr/local/bin/nginx_manage.sh'
- 现象:Supervisor 启动后 Nginx 状态为 FATAL,日志找不到旧脚本
- 原因:[include] 目录(/xp/server/supervisor/conf.d/)有残留配置,仍调用已删除的旧脚本
- 解决:删除 conf.d/ 下所有文件,或注释主配置中的 [include] 指令
4. 问题 4:systemctl status supervisord 检测不到进程
- 现象:systemd 命令显示 Supervisor 为 inactive (dead),但 Nginx 能正常运行
- 原因:Supervisor 由面板安装,用自定义进程管理(非 systemd 服务)
- 解决:用 pgrep -f "supervisord" 直接检测进程,或 supervisorctl status 验证管理状态
三、完整操作步骤(含命令)
步骤 1:清理旧环境(避免残留干扰)
pkill -9 supervisord
pkill -9 nginx
killall -9 nginx 2>/dev/null # 屏蔽“无进程可杀”的报错
# 2. 清理 80/443/888 端口占用(即使非 Nginx 占用也强制杀)
netstat -tunlp | grep -E ':80|:443|:888' | awk '{print $7}' | cut -d'/' -f1 | sort -u | xargs -I {} kill -9 {} 2>/dev/null
# 3. 验证清理结果(无输出即成功)
echo "=== 清理验证 ==="
pgrep supervisord && echo "❌ 残留 Supervisor 进程" || echo "✅ Supervisor 已清理"
pgrep nginx && echo "❌ 残留 Nginx 进程" || echo "✅ Nginx 已清理"
netstat -tunlp | grep -E ':80|:443|:888' && echo "❌ 端口仍被占用" || echo "✅ 端口已释放"
步骤 2:编辑 Supervisor 核心配置
2.1 打开配置文件
2.2 完整配置
按 i 进入 vim 编辑模式,粘贴以下内容,按 Esc 退出编辑:
port=127.0.0.1:9001 # 仅本地访问,安全优先
[supervisord]
logfile=/xp/server/supervisor/log/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/xp/server/supervisor/supervisord.pid
nodaemon=false # 后台运行(默认正确)
minfds=1024
minprocs=200
user=root # root 权限确保杀进程/启动无问题
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///xp/server/supervisor/supervisor.sock
# 核心:Nginx 监控配置(单行命令,清场+启动一体化)
[program:nginx]
command=/bin/bash -c "netstat -tunlp | grep -E ':80|:443|:888' | awk '{print $7}' | cut -d'/' -f1 | sort -u | xargs -I {} kill -9 {} 2>/dev/null; sleep 2; ps -ef | grep -i nginx | grep -v grep | awk '{print $2}' | xargs -I {} kill -9 {} 2>/dev/null; sleep 2; /xp/server/nginx/sbin/nginx -g 'daemon off;'"
autostart=true # Supervisor 启动时自动启动 Nginx
autorestart=true # Nginx 崩溃时自动重启(核心守护)
startretries=3 # 启动失败重试 3 次
startsecs=10 # 稳定运行 10 秒算启动成功
stopwaitsecs=10 # 停止时等待 10 秒再强制杀
user=root
redirect_stderr=true # 错误日志重定向到 stdout_logfile
stdout_logfile=/xp/server/supervisor/log/nginx.out.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stopasgroup=true # 停止时连带杀子进程(worker)
killasgroup=true # 强制杀整个进程组
# 注释 include(避免加载残留配置)
;[include]
;files = /xp/server/supervisor/conf.d/*.conf
2.3 保存退出 vim
按 Esc 后,输入 :wq 并回车(wq = 保存并退出;若放弃修改输入 :q! 强制退出)
步骤 3:启动 Supervisor 并验证初始状态
/xp/server/supervisor/supervisord -c /xp/server/supervisor/supervisord.conf
# 2. 等待 15 秒(给“清场+启动”命令执行时间)
sleep 15
# 3. 验证 Supervisor 进程
pgrep -f "supervisord" && echo "✅ Supervisor 启动成功" || echo "❌ Supervisor 启动失败"
# 4. 验证 Nginx 状态(需显示 RUNNING)
sudo /xp/server/supervisor/supervisorctl status nginx
步骤 4:验证两种崩溃场景(核心测试)
场景 1:Nginx 主进程单独崩溃
INITIAL_MASTER_PID=$(pgrep -f "nginx: master process")
echo "当前 Nginx 主 PID:$INITIAL_MASTER_PID"
# 2. 杀死主进程(模拟崩溃)
kill -9 $INITIAL_MASTER_PID
echo "已杀死主进程(PID:$INITIAL_MASTER_PID)"
# 3. 等待 15 秒(Supervisor 自动重启)
sleep 15
# 4. 验证结果
NEW_MASTER_PID1=$(pgrep -f "nginx: master process")
SUP_STATUS1=$(sudo /xp/server/supervisor/supervisorctl status nginx | awk '{print $2}')
echo -e "\n=== 场景1结果 ==="
[ -n "$NEW_MASTER_PID1" ] && [ "$NEW_MASTER_PID1" != "$INITIAL_MASTER_PID" ] && echo "✅ 主进程自动重启成功(新 PID:$NEW_MASTER_PID1)" || echo "❌ 失败"
[ "$SUP_STATUS1" = "RUNNING" ] && echo "✅ Supervisor 守护正常" || echo "❌ 异常"
场景 2:Nginx 所有进程被杀死
pkill -9 nginx
killall -9 nginx 2>/dev/null
echo "已杀死所有 Nginx 进程"
# 2. 等待 15 秒
sleep 15
# 3. 验证结果
NEW_MASTER_PID2=$(pgrep -f "nginx: master process")
SUP_STATUS2=$(sudo /xp/server/supervisor/supervisorctl status nginx | awk '{print $2}')
PORT_CHECK=$(netstat -tunlp | grep -E ':80|:443|:888' | grep nginx | wc -l)
echo -e "\n=== 场景2结果 ==="
[ -n "$NEW_MASTER_PID2" ] && [ "$NEW_MASTER_PID2" != "$NEW_MASTER_PID1" ] && echo "✅ 所有进程自动重启成功(新 PID:$NEW_MASTER_PID2)" || echo "❌ 失败"
[ "$SUP_STATUS2" = "RUNNING" ] && echo "✅ Supervisor 守护正常" || echo "❌ 异常"
[ "$PORT_CHECK" -ge 1 ] && echo "✅ 端口重新绑定成功" || echo "❌ 端口未绑定"
步骤 5:服务器重启后验证(确保开机自启)
reboot
# 2. 重启后登录,验证 Supervisor 进程
pgrep -f "supervisord" && echo "✅ Supervisor 开机自启成功" || echo "❌ 需检查面板自启配置"
# 3. 验证 Nginx 状态
sudo /xp/server/supervisor/supervisorctl status nginx | grep "RUNNING" && echo "✅ Nginx 被自动管理" || echo "❌ 需重新配置"
四、常用管理命令(后续维护)
功能 | 命令 |
---|---|
查看 Nginx 状态 | sudo /xp/server/supervisor/supervisorctl status nginx |
手动重启 Nginx | sudo /xp/server/supervisor/supervisorctl restart nginx |
停止 Nginx | sudo /xp/server/supervisor/supervisorctl stop nginx |
启动 Nginx | sudo /xp/server/supervisor/supervisorctl start nginx |
查看 Supervisor 日志 | tail -n 50 /xp/server/supervisor/log/supervisord.log |
查看 Nginx 运行日志 | tail -n 50 /xp/server/supervisor/log/nginx.out.log |
重启 Supervisor | pkill -9 supervisord && /xp/server/supervisor/supervisord -c /xp/server/supervisor/supervisord.conf |
五、最终效果
- 主进程崩溃:15 秒内自动重启,新进程接管服务
- 全进程被杀:自动清场端口 + 重启,端口重新绑定
- 服务器重启:Supervisor 随面板自启,Nginx 自动启动
- 无需手动干预:全程无人值守,确保网站稳定运行