From 8900ef68fc8c42e5c568ad4ae690540b4cd8e2ba Mon Sep 17 00:00:00 2001 From: Muse Date: Thu, 22 Oct 2026 12:54:32 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(install-agent):=20=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD(15)+=E6=97=A0=E5=8F=82=E6=B2=BF=E7=94=A8agen?= =?UTF-8?q?t.json(16)+=E5=A4=B1=E8=B4=A5=E6=8A=A5=E9=94=99=E4=B8=8E?= =?UTF-8?q?=E6=94=B6=E5=B0=BE=E8=87=AA=E6=A3=80(17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 下载基址统一 RELEASE_BASE 指向 Gitea 发行 V1.0.0:agent 二进制(原在旧 tag v3.7.0-agent.1)、双架构 xray zip、geoip/geosite 全部走自建镜像, 不再依赖 GitHub CDN - 未传 --master/--token/--name 时逐字段沿用本机 /etc/x-ui/agent.json, 显式参数优先;日志打明沿用的节点名与主控,绝不打印 token;文件不可 解析且必填仍缺则明确报错退出 - 每步下载/解压显式判失败(拆掉旧 && 链的静默吞错),下载验非空,前置 检查 curl/unzip;收尾 self_check 真跑 xray version、验 geo 非空与 agent 可执行,任一不过报错退出且不写配置不起服务 - fake-root 模拟 9 场景 58 断言全 PASS(报告 NEXT-SCRIPTS-REPORT.md) --- install-agent.sh | 76 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/install-agent.sh b/install-agent.sh index a2b894e..081d318 100755 --- a/install-agent.sh +++ b/install-agent.sh @@ -3,6 +3,10 @@ # 用法: bash install-agent.sh --master http://MASTER_IP:2053 --token YOUR_AGENT_TOKEN [--name my-node] # 要求: Debian/Ubuntu/Alpine/CentOS (amd64/arm64), root 运行 # +# 无参沿用(第 16 条):已装过 agent 的机器重跑本脚本升级时,可省略全部参数—— +# 脚本会从本机 /etc/x-ui/agent.json 沿用 master_url/token/node_name;显式传入的 +# 参数逐字段覆盖沿用值。日志只打明沿用的节点名与主控地址,绝不打印 token。 +# # 测试用环境变量(一般无需设置): # XUI_ROOT 安装路径前缀(假根目录验证用),默认空 = 真实路径 # XUI_INIT_SYSTEM 强制 init 系统: systemd | openrc | none,默认 auto 探测 @@ -22,8 +26,10 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } [[ $EUID -ne 0 ]] && error "请用 root 运行" +command -v curl >/dev/null 2>&1 || error "缺少 curl,请先安装 curl 后重跑" +command -v unzip >/dev/null 2>&1 || error "缺少 unzip,请先安装 unzip 后重跑" -MASTER=""; TOKEN=""; NAME="agent-node" +MASTER=""; TOKEN=""; NAME="" while [[ $# -gt 0 ]]; do case $1 in --master) MASTER="$2"; shift 2;; @@ -33,8 +39,31 @@ while [[ $# -gt 0 ]]; do esac done -[[ -z "$MASTER" ]] && error "缺少 --master 参数" +# 无参沿用(第 16 条):参数缺项时,从本机已有 agent.json 逐字段补默认值, +# 显式参数优先。agent.json 由本脚本以固定格式写出,这里用 sed 提取字段, +# 不依赖 jq。文件不存在或解析不出可用字段、且必填值仍缺 → 下方校验明确报错。 +AGENT_JSON_PATH="${XUI_ROOT:-}/etc/x-ui/agent.json" +json_get() { # $1=文件 $2=键名 → 打印值(取不到则空) + sed -n "s/.*\"$2\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" "$1" 2>/dev/null | head -n 1 +} +if [[ -f "$AGENT_JSON_PATH" ]]; then + INHERITED=() + f_master=$(json_get "$AGENT_JSON_PATH" master_url) + f_token=$(json_get "$AGENT_JSON_PATH" token) + f_name=$(json_get "$AGENT_JSON_PATH" node_name) + if [[ -z "$MASTER" && -n "$f_master" ]]; then MASTER="$f_master"; INHERITED+=("主控地址"); fi + if [[ -z "$TOKEN" && -n "$f_token" ]]; then TOKEN="$f_token"; INHERITED+=("token"); fi + if [[ -z "$NAME" && -n "$f_name" ]]; then NAME="$f_name"; INHERITED+=("节点名"); fi + if [[ ${#INHERITED[@]} -gt 0 ]]; then + info "沿用本机已有配置 ${AGENT_JSON_PATH}(${INHERITED[*]}):节点名=${NAME},主控=${MASTER}(token 已沿用,不显示)" + elif [[ -z "$MASTER" || -z "$TOKEN" ]]; then + warn "发现已有配置 ${AGENT_JSON_PATH},但未能解析出可用字段" + fi +fi + +[[ -z "$MASTER" ]] && error "缺少 --master 参数(本机亦无可沿用的 agent.json)" [[ -z "$TOKEN" ]] && error "缺少 --token 参数 (从主控面板 API 获取)" +[[ -z "$NAME" ]] && NAME="agent-node" ARCH=$(uname -m) case "$ARCH" in @@ -43,8 +72,10 @@ case "$ARCH" in *) error "不支持的架构: $ARCH (仅支持 amd64/arm64)";; esac -# 二进制下载地址(本仓 Gitea Releases,tag 沿用 v3.7.0-agent.1) -XUI_URL="${XUI_URL:-https://git.881218.xyz/rogue/3x-ui-agent/releases/download/v3.7.0-agent.1/x-ui-linux-${BIN_ARCH}}" +# 发行下载基址(本仓 Gitea Releases,发行 tag V1.0.0):agent 二进制、xray、geo +# 全部走自建镜像,不再依赖 GitHub CDN(部分节点极慢甚至僵死,见第 15 条)。 +RELEASE_BASE="https://git.881218.xyz/rogue/3x-ui-agent/releases/download/V1.0.0" +XUI_URL="${XUI_URL:-${RELEASE_BASE}/x-ui-linux-${BIN_ARCH}}" XRAY_VER="26.6.27" ROOT="${XUI_ROOT:-}" @@ -58,7 +89,8 @@ mkdir -p "${XUI_HOME}/bin" "${CONF_DIR}" info "下载 agent 二进制..." # 先下到 .new 再改名覆盖:改名是原子替换,正在运行的旧 agent 进程不受影响, # 也不会因目标文件正被执行而报 Text file busy;全程只写 xui-agent,不碰主控的 x-ui。 -curl -fL -o "${AGENT_BIN}.new" "$XUI_URL" || error "agent 下载失败" +curl -fL -o "${AGENT_BIN}.new" "$XUI_URL" || error "agent 下载失败: $XUI_URL" +[[ -s "${AGENT_BIN}.new" ]] || error "agent 下载得到空文件: $XUI_URL" chmod +x "${AGENT_BIN}.new" mv -f "${AGENT_BIN}.new" "${AGENT_BIN}" @@ -68,15 +100,41 @@ case "$BIN_ARCH" in amd64) XRAY_ZIP="Xray-linux-64.zip";; arm64) XRAY_ZIP="Xray-linux-arm64-v8a.zip";; esac -curl -fL -o "$XRAY_ZIP" "https://github.com/XTLS/Xray-core/releases/download/v${XRAY_VER}/${XRAY_ZIP}" || error "xray 下载失败" -unzip -o -q "$XRAY_ZIP" xray && mv xray "xray-linux-${BIN_ARCH}" && chmod +x "xray-linux-${BIN_ARCH}" +# 每一步都显式判失败并报错退出(第 17 条):历史教训——下载/解压失败曾被 +# && 链条吞掉,脚本带病走完报成功,结果 bin 里没有 xray、入站全断而面板显在线。 +curl -fL -o "$XRAY_ZIP" "${RELEASE_BASE}/${XRAY_ZIP}" || error "xray 下载失败: ${RELEASE_BASE}/${XRAY_ZIP}" +[[ -s "$XRAY_ZIP" ]] || error "xray 下载得到空文件: ${RELEASE_BASE}/${XRAY_ZIP}" +unzip -o -q "$XRAY_ZIP" xray || error "xray 解压失败: $XRAY_ZIP" +mv xray "xray-linux-${BIN_ARCH}" || error "xray 落位失败(解压产物缺失)" +chmod +x "xray-linux-${BIN_ARCH}" rm -f "$XRAY_ZIP" info "下载 geo 文件..." -curl -fL -o geoip.dat "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" || error "geoip 下载失败" -curl -fL -o geosite.dat "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" || error "geosite 下载失败" +curl -fL -o geoip.dat "${RELEASE_BASE}/geoip.dat" || error "geoip 下载失败: ${RELEASE_BASE}/geoip.dat" +[[ -s geoip.dat ]] || error "geoip 下载得到空文件: ${RELEASE_BASE}/geoip.dat" +curl -fL -o geosite.dat "${RELEASE_BASE}/geosite.dat" || error "geosite 下载失败: ${RELEASE_BASE}/geosite.dat" +[[ -s geosite.dat ]] || error "geosite 下载得到空文件: ${RELEASE_BASE}/geosite.dat" cd - >/dev/null +# 安装收尾自检(第 17 条):文件在不等于能用——xray 本体须存在、可执行、 +# version 能真实跑通;geo 须存在且非空;agent 本体须可执行。任一不过即 +# 报错退出并指出缺什么,不许带病进入写配置/起服务阶段。 +self_check() { + local xray_bin="${XUI_HOME}/bin/xray-linux-${BIN_ARCH}" + [[ -f "$xray_bin" ]] || error "自检失败:缺少 xray 本体 ${xray_bin}" + [[ -x "$xray_bin" ]] || error "自检失败:xray 本体不可执行 ${xray_bin}" + local ver_out + if ! ver_out=$("$xray_bin" version 2>/dev/null); then + error "自检失败:xray 本体无法运行(${xray_bin} version 退出非零)" + fi + [[ -n "$ver_out" ]] || error "自检失败:xray version 无输出(${xray_bin})" + info "自检通过:$(printf '%s' "$ver_out" | head -n 1)" + [[ -s "${XUI_HOME}/bin/geoip.dat" ]] || error "自检失败:geoip.dat 缺失或为空(${XUI_HOME}/bin/geoip.dat)" + [[ -s "${XUI_HOME}/bin/geosite.dat" ]] || error "自检失败:geosite.dat 缺失或为空(${XUI_HOME}/bin/geosite.dat)" + [[ -x "$AGENT_BIN" ]] || error "自检失败:agent 二进制不可执行 ${AGENT_BIN}" +} +self_check + info "写入 agent 配置..." cat > "${CONF_DIR}/agent.json" < Date: Thu, 22 Oct 2026 13:12:57 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat(install-agent):=20=E7=AC=AC23=E6=9D=A1?= =?UTF-8?q?=20OpenRC=20=E9=9F=A7=E6=80=A7=E5=AF=B9=E9=BD=90=E2=80=94?= =?UTF-8?q?=E2=80=94supervise-daemon=20=E5=AE=88=E6=8A=A4=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=20command=5Fbackground?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenRC 支原用 command_background 后台化,进程崩溃不自动拉起,与 systemd 支 Restart=on-failure 语义不对齐。生成的 /etc/init.d/x-ui-agent 改用 supervisor=supervise-daemon + respawn_delay=5(对齐 RestartSec=5)+ respawn_max=0/respawn_period=0(不限次,对齐持续重试);pidfile 与 output/error_log 约定原样保留,command/command_args 不动,幂等重跑时 init 脚本整文件重写、旧式 command_background 布局自动迁移。 第 15/16/17 条对 OpenRC 路径复核:下载基址、无参沿用、失败报错、收尾 self_check 与 rc-service status 存活断言均在公共段/现有分支内已达标, 未作改动(由新增 OpenRC fake-root 套件实证)。 验证:既有 systemd fake-root 套件 58/58 零回归;新增 OpenRC 套件 (run-tests-openrc.sh,O1–O5)51/51。改动点仅此一处(+7/-1)。 --- install-agent.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/install-agent.sh b/install-agent.sh index 081d318..334a1a2 100755 --- a/install-agent.sh +++ b/install-agent.sh @@ -262,7 +262,13 @@ name="x-ui-agent" description="3x-ui lightweight node agent" command="/usr/local/x-ui/xui-agent" command_args="agent" -command_background="yes" +# supervise-daemon 守护(第 23 条):进程崩溃后按 respawn 参数自动拉起, +# 对齐 systemd 支的 Restart=on-failure + RestartSec=5;旧版 command_background +# 只负责后台化、崩溃不重启。respawn_max=0 = 不限次(同 systemd 的持续重试)。 +supervisor="supervise-daemon" +respawn_delay=5 +respawn_max=0 +respawn_period=0 pidfile="/run/x-ui-agent.pid" output_log="/var/log/x-ui-agent.log" error_log="/var/log/x-ui-agent.log"