Supervisor+Nginx 配置迭代总结报告

2026-02-0616:20:22 评论 17

一、项目背景与核心诉求

适配环境:小皮面板 + 低版本 Supervisor + Linux 服务器(最终适配 Ubuntu 22.04)
核心问题:Nginx 端口占用、手动 stop 不重启、面板显示“运行中”但网站实际挂掉(僵尸主进程)
最终目标:实现 Nginx 稳定运行,精准检测网站可用性,自动处理异常场景

二、配置迭代时间线与分析思路

版本1:最初版
分析思路:聚焦核心问题,先解决端口占用,保留基础启动逻辑
核心实现:保留强杀端口命令、Nginx启动命令和基础参数
存在缺陷:仅监控 bash 进程,无法检测 Nginx 实际状态,管理权归属混乱

版本2:功能扩展版
分析思路:拆分功能模块,增强鲁棒性,将配置拆分为主配置+脚本文件
核心实现:新增启动前置清理脚本、健康检查脚本、一键管理脚本
优化点:实现进程清理、端口检测、日志记录的分离管理

版本3:Ubuntu 22.04适配版
分析思路:解决系统兼容性问题,替换Ubuntu 22.04缺失/失效的命令
核心修改:netstat→ss、pkill→pgrep+xargs、单引号→双引号
适配点:确保在目标系统中所有命令正常执行,无解析错误

版本4:888端口适配版
分析思路:补充端口覆盖范围,解决888端口占用导致的启动失败问题
核心修改:在端口清理、检测逻辑中新增888端口,排查命令同步更新
扩展点:覆盖业务所需的所有端口(80/443/888),避免遗漏场景

版本5:边界修复版
分析思路:优化极端场景处理,提升配置鲁棒性和运维体验
核心修改:新增PID合法性校验、端口检测逻辑优化、9001端口冲突检测
修复点:解决非数字PID导致脚本异常、单一端口通即误判等边界问题

版本6:URL检测版
分析思路:切换检测维度,从“端口监听”转为“实际业务可用性”
核心修改:用curl检测URL返回码替代端口监听检测,按返回码执行不同逻辑
核心优化:更贴近实际业务场景,避免“端口通但网站挂”的误判

版本7:最终版
分析思路:极简优化,保留核心功能,删除冗余逻辑,精准匹配需求
核心修改:仅保留URL返回码判定+端口强杀兜底,删除所有无用监控项
最终优化:逻辑清晰、执行高效、维护成本低,完全满足核心诉求

三、关键版本核心差异对比

<<<<

对比维度</ 最初版</ 中间优化版</ 最终版</
检测逻辑 监控bash进程 端口监听检测 → URL返回码检测 仅URL返回码检测(http://182.106.136.56)
端口处理 80/443/888强杀 端口清理+监听检测+冲突检测 仅80/443/888强杀(兜底启动)
功能模块 单行命令配置 主配置+4个脚本+日志轮转 主配置+2个核心脚本(极简)
异常处理 仅解决端口占用 多场景异常处理+失败计数+超时控制 按返回码精准处理(200/404/500/其他)
管理权 小皮面板为主 Supervisor完全接管 Supervisor完全接管(无冗余依赖)

四、核心修改点详细说明

1. 检测逻辑演进(最关键修改)

从“监控bash进程”→“端口监听检测”→“URL返回码检测”
原因:端口监听正常不代表网站可用(如僵尸主进程、应用层异常),URL返回码能直接反映业务状态
# 最终版核心检测逻辑
curl_check() {
local code=$(curl $CHECK_URL -m $CURL_TIMEOUT -s -w "%{http_code}" -o /dev/null)
echo "$code"
}

2. 系统兼容性适配

netstat → ss:Ubuntu 22.04默认无netstat,ss命令功能一致且更高效
pkill → pgrep+xargs:解决pkill在低版本Supervisor中匹配失效问题
单引号 → 双引号:解决Supervisor解析命令时的语法错误

3. 端口管理优化

新增888端口:覆盖业务所需端口,避免因888端口占用导致启动失败
删除端口监听检测:仅保留端口强杀功能,作为启动兜底(解决端口占用坑)
原因:端口监听状态无实际业务意义,仅端口占用会影响启动

4. 异常处理规则优化

返回码200:静默运行,重置失败计数(正常业务状态)
返回码404/500:记录日志,不重启(业务异常需手动处理)
其他返回码:连续2次失败→强杀端口+重启Nginx(系统层面异常)
原因:区分业务异常和系统异常,避免无效重启和数据丢失

五、采用最终方案的原因

1. 精准匹配核心诉求

最终方案仅聚焦“网站可用”这一核心目标,所有逻辑围绕URL返回码展开,解决了最初的所有问题(端口占用、自动重启、防僵尸进程)

2. 逻辑极简,维护成本低

删除了中间版本中冗余的端口监听检测、PID校验、9001端口冲突检测等功能,仅保留核心必要逻辑,后期维护无需关注过多细节

3. 执行高效,资源占用少

检测间隔15秒,curl超时2秒,无复杂循环和多重判断,对服务器资源占用极低,适合长期稳定运行

4. 异常处理精准

按返回码区分不同异常场景,避免了“一刀切”的重启策略,减少因不必要的重启导致的业务中断

5. 完全适配目标环境

解决了Ubuntu 22.04的兼容性问题,同时适配低版本Supervisor,无依赖冲突,部署后可直接稳定运行

六、最终方案核心配置(备查)

1. Supervisor主配置文件(supervisord.conf)

[inet_http_server]
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
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=http://127.0.0.1:9001
[program:nginx]
command=/xp/server/nginx/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
startretries=5
startsecs=10
stopwaitsecs=15
user=root
redirect_stderr=true
stdout_logfile=/xp/server/supervisor/log/nginx_main.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stopasgroup=true
killasgroup=true
stopsignal=TERM
process_name=%(program_name)s
numprocs=1
[program:nginx_health]
command=/bin/bash /xp/server/nginx/nginx_health.sh
autostart=true
autorestart=true
startretries=3
startsecs=5
user=root
redirect_stderr=true
stdout_logfile=/xp/server/supervisor/log/nginx_health.log
stdout_logfile_maxbytes=5MB
stdout_logfile_backups=5
stopasgroup=false
killasgroup=false
process_name=%(program_name)s
numprocs=1

2. 健康检查脚本(nginx_health.sh)

#!/bin/bash
# ========== 核心配置 ==========
CHECK_URL="http://182.106.136.56" # 唯一检测目标
CHECK_INTERVAL=15 # 每15秒检测1次
CURL_TIMEOUT=2 # curl超时2秒
LOG_FILE="/xp/server/supervisor/log/nginx_health.log"
MAX_FAIL_TIMES=2 # 连续2次失败触发重启
FAIL_COUNT=0 # 失败计数初始化
# ========== 初始化 ==========
[ ! -d "$(dirname $LOG_FILE)" ] && mkdir -p "$(dirname $LOG_FILE)" && chmod 755 "$(dirname $LOG_FILE)"
# ========== 函数:执行curl检测 ==========
curl_check() {
local code=$(curl $CHECK_URL -m $CURL_TIMEOUT -s -w "%{http_code}" -o /dev/null)
echo "$code"
}
# ========== 函数:强杀80/443/888端口+Nginx进程(兜底) ==========
force_clean() {
echo "[$(date)] 开始强制清理80/443/888端口+Nginx进程" >> "$LOG_FILE"
for PORT in 80 443 888; do
PID=$(ss -tunlp 2>/dev/null | grep -E ":$PORT\s" | awk '{print $7}' | cut -d'/' -f1 | head -1)
if [ -n "$PID" ] && [[ "$PID" =~ ^[0-9]+$ ]]; then
kill -9 "$PID" 2>/dev/null
echo "[$(date)] 强制杀死端口$PORT占用进程:$PID" >> "$LOG_FILE"
fi
done
pgrep -f "nginx: master process" | xargs -r kill -9 2>/dev/null
pgrep -f "nginx: worker process" | xargs -r kill -9 2>/dev/null
echo "[$(date)] 强制清理完成:80/443/888端口+Nginx进程已杀死" >> "$LOG_FILE"
}
# ========== 函数:重启Nginx(通过Supervisor) ==========
restart_nginx() {
echo "[$(date)] 触发Nginx重启(通过Supervisor)" >> "$LOG_FILE"
/xp/server/supervisor/supervisorctl -c /xp/server/supervisor/supervisord.conf restart nginx 2>> "$LOG_FILE"
echo "[$(date)] Nginx重启命令已执行" >> "$LOG_FILE"
}
# ========== 启动提示 ==========
echo "[$(date)] Nginx健康检查启动,仅检测URL:$CHECK_URL 返回码,每${CHECK_INTERVAL}秒检测1次" >> "$LOG_FILE"
# ========== 主循环(核心逻辑) ==========
while true; do
CODE=$(curl_check)
if [ "$CODE" = "200" ]; then
FAIL_COUNT=0
elif [ "$CODE" = "404" ] || [ "$CODE" = "500" ]; then
echo "[$(date)] 业务异常:URL返回码$CODE,需手动处理(不触发重启)" >> "$LOG_FILE"
FAIL_COUNT=0
else
FAIL_COUNT=$((FAIL_COUNT + 1))
echo "[$(date)] 检测失败:URL返回码$CODE,失败计数+1(当前:$FAIL_COUNT)" >> "$LOG_FILE"
if [ $FAIL_COUNT -eq $MAX_FAIL_TIMES ]; then
echo "[$(date)] 连续${MAX_FAIL_TIMES}次检测失败,触发修复逻辑" >> "$LOG_FILE"
force_clean
restart_nginx
FAIL_COUNT=0
echo "[$(date)] 修复逻辑执行完成,重置失败计数为0" >> "$LOG_FILE"
fi
fi
sleep $CHECK_INTERVAL
done

3. 一键管理脚本(nginx_manage.sh)

#!/bin/bash
LOG_DIR="/xp/server/supervisor/log"
[ ! -d "$LOG_DIR" ] && mkdir -p "$LOG_DIR" && chmod 755 "$LOG_DIR"
SUPERVISORCTL_BIN="/xp/server/supervisor/supervisorctl"
SUPERVISOR_CONF="/xp/server/supervisor/supervisord.conf"
# 基础依赖检查
check_dependencies() {
local error=0
if [ ! -x "$SUPERVISORCTL_BIN" ]; then
echo "[$(date)] 错误:$SUPERVISORCTL_BIN 不存在或无执行权限" >> "$LOG_DIR/nginx_manage.log"
error=1
fi
if [ ! -f "$SUPERVISOR_CONF" ]; then
echo "[$(date)] 错误:$SUPERVISOR_CONF 配置文件不存在" >> "$LOG_DIR/nginx_manage.log"
error=1
fi
if [ $error -ne 0 ]; then
exit 1
fi
}
check_dependencies
case "$1" in
start)
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF start nginx nginx_health 2>> "$LOG_DIR/nginx_manage.log"
echo "[$(date)] Nginx启动完成,状态如下:" >> "$LOG_DIR/nginx_manage.log"
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF status >> "$LOG_DIR/nginx_manage.log" 2>&1
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF status
;;
restart)
for PORT in 80 443 888; do
PID=$(ss -tunlp 2>/dev/null | grep -E ":$PORT\s" | awk '{print $7}' | cut -d'/' -f1 | head -1)
if [ -n "$PID" ] && [[ "$PID" =~ ^[0-9]+$ ]]; then
kill -9 "$PID" 2>/dev/null
fi
done
pgrep -f "nginx: master process" | xargs -r kill -9 2>/dev/null
pgrep -f "nginx: worker process" | xargs -r kill -9 2>/dev/null$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF restart nginx nginx_health 2>> "$LOG_DIR/nginx_manage.log"
echo "[$(date)] Nginx重启完成,状态如下:" >> "$LOG_DIR/nginx_manage.log"
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF status >> "$LOG_DIR/nginx_manage.log" 2>&1
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF status
;;
status)
$SUPERVISORCTL_BIN -c $SUPERVISOR_CONF status nginx nginx_health
;;
*)
echo "使用方法:$0 {start|restart|status}"
exit 1
;;
esac
exit 0

七、部署与验证命令(最终版)

# 1. 给脚本赋执行权限
chmod +x /xp/server/nginx/nginx_health.sh
chmod +x /xp/server/nginx/nginx_manage.sh# 2. 停止旧进程(如有)
/xp/server/supervisor/supervisorctl -c /xp/server/supervisor/supervisord.conf stop all# 3. 重启Supervisor加载新配置
pkill -9 supervisord
/xp/server/supervisor/supervisord -c /xp/server/supervisor/supervisord.conf# 4. 启动Nginx+健康检查
/xp/server/nginx/nginx_manage.sh start# 5. 验证检测是否生效(手动执行curl)
curl http://182.106.136.56 -m 2 -s -w "%{http_code}" -o /dev/null# 6. 常用排查命令
tail -f /xp/server/supervisor/log/nginx_health.log # 实时查看健康检查日志
/xp/server/nginx/nginx_manage.sh status # 查看Nginx状态
/xp/server/nginx/nginx_manage.sh restart # 一键重启Nginx
继续阅读
岁岁安稳,心底遥望。 刘志强

岁岁安稳,心底遥望。

半生辗转,未携锋芒,只在烟火寻常处,做个躬身前行的赶路人。人间喧嚣扰攘,终是看透:浮名薄利皆虚妄,唯愿守着至亲,把岁岁年年过成细水长流的安稳。偶有一念,想探那彼岸微光,却困于尘缘,寻不到渡我的舟,只在...
元宵寄思 刘志强

元宵寄思

  寒雪纷飞落异乡,元宵佳节独凭窗。 烟花璀璨添愁绪,灯火阑珊惹断肠。 妻女音容常入梦,椿萱身影每盈眶。 谋生苦累归期杳,唯盼团圆岁月长。
切莫酒后一时快语悔恨终生 重温2013年随笔…… 刘志强

切莫酒后一时快语悔恨终生 重温2013年随笔……

今天翻看邮箱无意发现一篇随笔,对比现在发现变化不大,也许岁月磨平了棱角,可内心依旧冲动烦躁,事业没进步是对的,几十年的性格不能说变就变,也许是“出淤泥而不染”。 咱已过不惑之年,何为不惑,意为不在疑惑...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: