fix: sync nginx with daemon file on hot-reload flows

- add idempotent nginx_sync to start, reload, or stop nginx based on the final config state
- start nginx automatically when adding WS + Argo protocols, removing the need for a manual systemctl restart
- regenerate the daemon file after the final nginx state is decided in change_protocols, keeping systemd ExecStartPre / OpenRC start_pre consistent and clearing stale OpenRC entries on Alpine after WS removal
- converge subscription toggle ON/OFF to daemon regeneration plus nginx_sync, replacing inline sed patches
- unify nginx management on CentOS7 with a tolerant ExecStartPre ("-" prefix) so nginx starts on reload and after reboot
- reload nginx after nginx.conf rewrites (port changes, Argo type changes, additional WS protocols)
- stop nginx during uninstall to cover processes started outside the service cgroup

fix: 热更流程下 nginx 与守护文件状态同步

- 新增幂等 nginx_sync,按最终配置状态自动启动 / 热重载 / 停止 nginx
- 添加 WS + Argo 协议时自动拉起 nginx,无需再手动 systemctl restart
- change_protocols 先确定最终 nginx 状态再生成守护文件,保证 systemd ExecStartPre / OpenRC start_pre 一致,并清除 Alpine 删除 WS 后残留的 start_pre
- 订阅开关 ON/OFF 收敛为守护文件重生成 + nginx_sync,移除内联 sed 补丁
- CentOS7 统一走带 "-" 容错的 ExecStartPre,reload 与重启后 nginx 均能拉起
- nginx.conf 被重写(改端口 / 换 Argo 隧道 / 追加 WS 协议)后自动 reload nginx
- 卸载时显式停止 nginx,覆盖服务 cgroup 外启动的进程
This commit is contained in:
fscarmen
2026-08-04 21:06:04 +08:00
committed by GitHub
parent 8d893d60cb
commit 4c9f6fbf06
+43 -41
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# 当前脚本版本号
VERSION='v1.3.19 (2026.08.02)'
VERSION='v1.3.19 (2026.08.04)'
# Github 反代加速代理
GITHUB_PROXY=('https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/')
@@ -764,6 +764,7 @@ change_config() {
done
fetch_nodes_value
[ -n "$PORT_NGINX" ] && export_nginx_conf_file
nginx_sync
cmd_systemctl reload sing-box
[ -n "$ARGO_DOMAIN" ] && export_argo_json_file
sync_firewall_rules
@@ -936,14 +937,14 @@ change_config() {
# 判断是否还需要 nginx:有 WS 协议且 Argo 反代
if { [ -n "$PORT_VMESS_WS" ] || [ -n "$PORT_VLESS_WS" ]; } && [ "$IS_ARGO" = 'is_argo' ]; then
export_nginx_conf_file
nginx -s reload -c ${WORK_DIR}/nginx.conf 2>/dev/null || nginx_run
else
nginx_stop
[ "$SYSTEM" != 'Alpine' ] && [ "$IS_CENTOS" != 'CentOS7' ] && \
sed -i '/ExecStartPre=.*nginx/d' ${SINGBOX_DAEMON_FILE} && systemctl daemon-reload
rm -f ${WORK_DIR}/nginx.conf
unset PORT_NGINX
fi
# 重新生成守护文件并同步 nginxsystemd ExecStartPre / OpenRC start_pre 与最终状态一致)
sing-box_systemd
nginx_sync
/bin/rm -f ${WORK_DIR}/subscribe/qr
export_list
info " $(text 112) "
@@ -964,18 +965,9 @@ change_config() {
fetch_nodes_value
[ -z "$PORT_NGINX" ] && input_nginx_port
export_nginx_conf_file
# 更新服务文件 ExecStartPre(非 CentOS7
if [ "$SYSTEM" != 'Alpine' ] && [ "$IS_CENTOS" != 'CentOS7' ] && \
! grep -q 'ExecStartPre=.*nginx' ${SINGBOX_DAEMON_FILE} 2>/dev/null; then
sed -i '/^ExecStart=/i ExecStartPre='$(command -v nginx)' -c '${WORK_DIR}'/nginx.conf' ${SINGBOX_DAEMON_FILE}
systemctl daemon-reload
fi
# 启动或 reload nginx
if ps -eo pid,args | grep -qE "[n]ginx.*${WORK_DIR}/nginx.conf" 2>/dev/null; then
nginx -s reload -c ${WORK_DIR}/nginx.conf 2>/dev/null || true
else
nginx_run
fi
# 重新生成守护文件并同步 nginx(含 Alpine / CentOS7,重启后 nginx 随服务拉起
sing-box_systemd
nginx_sync
export_list
info " $(text 112) "
fi
@@ -1909,6 +1901,7 @@ change_argo() {
# 更新节点信息和配置
fetch_nodes_value
export_nginx_conf_file
nginx_sync
export_list
}
@@ -2132,6 +2125,19 @@ nginx_stop() {
ss -nltp | sed -n "/pid=$NGINX_PID,/ s/,/ /gp" | grep -oP 'pid=\K\S+' | sort -u | xargs kill -9 >/dev/null 2>&1
}
# 让 nginx 进程与最终配置状态保持一致:需要则启动/热重载,不需要则停止
nginx_sync() {
if [ -s ${WORK_DIR}/nginx.conf ]; then
if ps -eo pid,args | grep -qE "[n]ginx.*${WORK_DIR}/nginx.conf" 2>/dev/null; then
nginx -s reload -c ${WORK_DIR}/nginx.conf 2>/dev/null || true
else
nginx_run
fi
else
nginx_stop
fi
}
# 为了适配 alpine,定义 cmd_systemctl 的函数
cmd_systemctl() {
@@ -2150,6 +2156,7 @@ cmd_systemctl() {
;;
reload )
rc-service "$2" reload >/dev/null 2>&1 || rc-service "$2" restart >/dev/null 2>&1
[ -s ${WORK_DIR}/nginx.conf ] && nginx_sync
local MAINPID=$(cat /var/run/sing-box.pid 2>/dev/null)
[ -n "$MAINPID" ] && info "\n $(text 95) \n"
;;
@@ -2162,21 +2169,13 @@ cmd_systemctl() {
case "$1" in
enable | disable )
systemctl "$1" --now "$2" >/dev/null 2>&1
if [ "$IS_CENTOS" = 'CentOS7' ] && [ "$2" = 'sing-box' ] && [ -s $WORK_DIR/nginx.conf ]; then
if [ "$1" = 'enable' ]; then
nginx_run
else
nginx_stop
fi
fi
;;
restart )
[ "$IS_CENTOS" = 'CentOS7' ] && [ "$2" = 'sing-box' ] && [ -s $WORK_DIR/nginx.conf ] && nginx_stop
systemctl restart "$2" >/dev/null 2>&1
[ "$IS_CENTOS" = 'CentOS7' ] && [ "$2" = 'sing-box' ] && [ -s $WORK_DIR/nginx.conf ] && nginx_run
;;
reload )
systemctl reload sing-box >/dev/null 2>&1 || systemctl restart sing-box >/dev/null 2>&1
[ -s ${WORK_DIR}/nginx.conf ] && nginx_sync
local MAINPID=$(systemctl show -p MainPID sing-box 2>/dev/null | awk -F= '{print $2}')
[ -n "$MAINPID" ] && [ "$MAINPID" -gt 0 ] 2>/dev/null && info "\n $(text 95) \n"
;;
@@ -4307,9 +4306,9 @@ start_pre() {
mkdir -p /var/run
chmod 755 /var/run"
# 如果配置了 Nginx,启动 Nginx
# 如果配置了 Nginx,启动 Nginx(nginx 已在运行时不阻塞服务启动)
[ -n "$PORT_NGINX" ] && OPENRC_SERVICE+="
$(command -v nginx) -c ${WORK_DIR}/nginx.conf"
$(command -v nginx) -c ${WORK_DIR}/nginx.conf || true"
OPENRC_SERVICE+="
# 确保 PID 文件不存在,避免启动失败
@@ -4358,7 +4357,8 @@ NoNewPrivileges=yes
TimeoutStartSec=0
WorkingDirectory=${WORK_DIR}
"
[[ -n "$PORT_NGINX" && "$IS_CENTOS" != 'CentOS7' ]] && SING_BOX_SERVICE+="ExecStartPre=$(command -v nginx) -c ${WORK_DIR}/nginx.conf
# 统一在 systemd 里用 ExecStartPre 管理 nginx(含 CentOS7);"-" 前缀容忍 nginx 已在运行等情况,避免阻塞服务启动
[[ -n "$PORT_NGINX" ]] && SING_BOX_SERVICE+="ExecStartPre=-$(command -v nginx) -c ${WORK_DIR}/nginx.conf
"
SING_BOX_SERVICE+="ExecStart=${WORK_DIR}/sing-box run -C ${WORK_DIR}/conf
ExecReload=/bin/kill -HUP \$MAINPID
@@ -5705,15 +5705,22 @@ change_protocols() {
unset PORT_NAIVE
fi
# 生成 Nginx 配置文件
# 生成各协议的 json 文件
sing-box_json change
# 无 ws 协议且无订阅时清理 nginx:先于守护文件生成,确保 ExecStartPre / start_pre 与最终状态一致
if ! ls ${WORK_DIR}/conf/*-ws*inbounds.json >/dev/null 2>&1 && [[ -s ${WORK_DIR}/nginx.conf && "$IS_SUB" = 'no_sub' ]]; then
nginx_stop
rm -f ${WORK_DIR}/nginx.conf
unset PORT_NGINX
fi
# 生成 Nginx 配置文件(按最终状态)
[ -n "$PORT_NGINX" ] && export_nginx_conf_file
# 重新生成 Sing-box 守护进程文件
sing-box_systemd
# 生成各协议的 json 文件
sing-box_json change
# 如有需要,安装和删除 Argo 服务
if ls ${WORK_DIR}/conf/*-ws*inbounds.json >/dev/null 2>&1; then
if [[ "$ARGO_OR_ORIGIN_RULES" != '2' && "$ARGO_ORIGIN_RULES_STATUS" != 'is_origin' && ! -s ${ARGO_DAEMON_FILE} ]]; then
@@ -5729,18 +5736,12 @@ change_protocols() {
fi
fi
# 无 ws 协议且无订阅时删除 nginx 配置并停止进程;有订阅保留(订阅服务需要 nginx)
if ! ls ${WORK_DIR}/conf/*-ws*inbounds.json >/dev/null 2>&1 && [[ -s ${WORK_DIR}/nginx.conf && "$IS_SUB" = 'no_sub' ]]; then
nginx_stop
[ "$SYSTEM" != 'Alpine' ] && [ "$IS_CENTOS" != 'CentOS7' ] && \
sed -i '/ExecStartPre=.*nginx/d' ${SINGBOX_DAEMON_FILE} && systemctl daemon-reload
rm -f ${WORK_DIR}/nginx.conf
unset PORT_NGINX
fi
# 热更 sing-boxSIGHUP 重新加载配置,PID 不变)
cmd_systemctl reload sing-box
# 同步 nginx 进程:需要则启动/热重载,不需要则停止
nginx_sync
# 打开防火墙相关端口
sync_firewall_rules
@@ -5759,6 +5760,7 @@ uninstall() {
if [ -d ${WORK_DIR} ]; then
[ -s ${ARGO_DAEMON_FILE} ] && cmd_systemctl disable argo &>/dev/null
[ -s ${SINGBOX_DAEMON_FILE} ] && cmd_systemctl disable sing-box &>/dev/null
nginx_stop
sleep 1
[[ -s ${WORK_DIR}/nginx.conf && "$(ps -ef | grep -c '[n]ginx')" = 0 ]] && reading "\n $(text 83) " REMOVE_NGINX
[ "${REMOVE_NGINX,,}" = 'y' ] && ${PACKAGE_UNINSTALL[int]} nginx >/dev/null 2>&1