Files
3x-ui-agent/install-agent.sh
T

247 lines
9.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 3x-ui-agent 节点一键安装脚本
# 用法: bash install-agent.sh --master http://MASTER_IP:2053 --token YOUR_AGENT_TOKEN [--name my-node]
# 要求: Debian/Ubuntu/Alpine/CentOS (amd64/arm64), root 运行
#
# 测试用环境变量(一般无需设置):
# XUI_ROOT 安装路径前缀(假根目录验证用),默认空 = 真实路径
# XUI_INIT_SYSTEM 强制 init 系统: systemd | openrc | none,默认 auto 探测
# XUI_URL agent 二进制下载地址覆盖
set -e
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
[[ $EUID -ne 0 ]] && error "请用 root 运行"
MASTER=""; TOKEN=""; NAME="agent-node"
while [[ $# -gt 0 ]]; do
case $1 in
--master) MASTER="$2"; shift 2;;
--token) TOKEN="$2"; shift 2;;
--name) NAME="$2"; shift 2;;
*) error "未知参数: $1";;
esac
done
[[ -z "$MASTER" ]] && error "缺少 --master 参数"
[[ -z "$TOKEN" ]] && error "缺少 --token 参数 (从主控面板 API 获取)"
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64) BIN_ARCH="amd64";;
aarch64|arm64) BIN_ARCH="arm64";;
*) 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}}"
XRAY_VER="26.6.27"
ROOT="${XUI_ROOT:-}"
XUI_HOME="${ROOT}/usr/local/x-ui"
CONF_DIR="${ROOT}/etc/x-ui"
AGENT_BIN="${XUI_HOME}/x-ui"
info "创建目录..."
mkdir -p "${XUI_HOME}/bin" "${CONF_DIR}"
info "下载 agent 二进制..."
curl -fL -o "${AGENT_BIN}" "$XUI_URL" || error "agent 下载失败"
chmod +x "${AGENT_BIN}"
info "下载 xray v${XRAY_VER}..."
cd "${XUI_HOME}/bin"
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}"
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 下载失败"
cd - >/dev/null
info "写入 agent 配置..."
cat > "${CONF_DIR}/agent.json" <<EOF
{
"master_url": "$MASTER",
"token": "$TOKEN",
"node_name": "$NAME"
}
EOF
chmod 600 "${CONF_DIR}/agent.json"
# 探测主控可达性:拿假 token 打一次注册接口,在启动前把地址问题拦下来,
# 别让 agent 带着必死的配置装完再无声无息地死掉(主控上一直显示"未知")。
# 404 → 注册路由不存在,主控地址大概率少了面板基础路径
# 连不上 → 网络/域名/TLS 问题
# 其他(401等) → 路由存在(假 token 被拒正是预期),路径正确
probe_master() {
local url="${MASTER%/}/panel/api/agent/register"
info "探测主控注册接口: $url"
local code
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 -X POST "$url" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer install-probe-invalid-token' \
-d '{"token":"install-probe-invalid-token","name":"install-probe"}' 2>/dev/null) || code="000"
case "$code" in
404)
echo ""
echo -e "${RED}============================================================${NC}"
echo -e "${RED} 主控返回 404:注册接口不存在,安装中止。${NC}"
echo -e "${RED} 主控地址大概率少了面板基础路径(如 /rogue)。${NC}"
echo -e "${RED} 当前地址: ${MASTER}${NC}"
echo -e "${RED} 若面板实际地址带基础路径,请改用 --master ${MASTER%/}/rogue${NC}"
echo -e "${RED} 之类的完整地址(以面板真实基础路径为准)改对后重跑本脚本。${NC}"
echo -e "${RED}============================================================${NC}"
exit 1
;;
000)
echo ""
echo -e "${RED}============================================================${NC}"
echo -e "${RED} 连不上主控,安装中止。${NC}"
echo -e "${RED} 请检查:网络是否通、域名解析是否正常、主控地址与端口是否写对、${NC}"
echo -e "${RED} 以及主控 HTTPS 证书是否有效(agent 不接受自签证书)。${NC}"
echo -e "${RED} 目标: $url${NC}"
echo -e "${RED}============================================================${NC}"
exit 1
;;
*)
info "主控探测通过 (HTTP $code,注册路由存在)"
;;
esac
}
probe_master
detect_init_system() {
case "${XUI_INIT_SYSTEM:-auto}" in
systemd|openrc|none) echo "${XUI_INIT_SYSTEM}"; return;;
esac
if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then
echo systemd; return
fi
if command -v rc-update >/dev/null 2>&1 && command -v rc-service >/dev/null 2>&1; then
echo openrc; return
fi
echo none
}
# 以 systemd 服务方式安装并启动(开机自启)
start_via_systemd() {
local unit_dir="${ROOT}/etc/systemd/system"
mkdir -p "$unit_dir"
cat > "${unit_dir}/x-ui-agent.service" <<'EOF'
[Unit]
Description=3x-ui agent
After=network.target
[Service]
ExecStart=/usr/local/x-ui/x-ui agent
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
info "已生成 systemd 服务文件: ${unit_dir}/x-ui-agent.service"
if [ -n "$ROOT" ]; then
info "(XUI_ROOT 模式:跳过 systemctl 实际操作)"
return 0
fi
systemctl stop x-ui-agent 2>/dev/null || true
pkill -f "${AGENT_BIN} agent" 2>/dev/null || true; sleep 1
systemctl daemon-reload
systemctl enable x-ui-agent
systemctl restart x-ui-agent
sleep 2
if systemctl is-active --quiet x-ui-agent; then
info "agent 已由 systemd 托管启动(开机自启)"
echo ""
echo " 主控: $MASTER"
echo " 节点名: $NAME"
echo " 日志: journalctl -u x-ui-agent -f"
echo " agent 会在 30 秒内从主控拉取配置"
else
error "agent 服务启动失败,查看: systemctl status x-ui-agent"
fi
}
# 以 OpenRC 服务方式安装并启动(开机自启,Alpine 等)
start_via_openrc() {
local init_dir="${ROOT}/etc/init.d"
mkdir -p "$init_dir"
cat > "${init_dir}/x-ui-agent" <<'EOF'
#!/sbin/openrc-run
name="x-ui-agent"
description="3x-ui lightweight node agent"
command="/usr/local/x-ui/x-ui"
command_args="agent"
command_background="yes"
pidfile="/run/x-ui-agent.pid"
output_log="/var/log/x-ui-agent.log"
error_log="/var/log/x-ui-agent.log"
depend() {
need net
}
EOF
chmod +x "${init_dir}/x-ui-agent"
info "已生成 OpenRC 服务文件: ${init_dir}/x-ui-agent"
if [ -n "$ROOT" ]; then
info "(XUI_ROOT 模式:跳过 rc-update/rc-service 实际操作)"
return 0
fi
rc-service x-ui-agent stop 2>/dev/null || true
pkill -f "${AGENT_BIN} agent" 2>/dev/null || true; sleep 1
rc-update add x-ui-agent default
rc-service x-ui-agent restart
sleep 2
if rc-service x-ui-agent status >/dev/null 2>&1; then
info "agent 已由 OpenRC 托管启动(开机自启)"
echo ""
echo " 主控: $MASTER"
echo " 节点名: $NAME"
echo " 日志: tail -f /var/log/x-ui-agent.log"
echo " agent 会在 30 秒内从主控拉取配置"
else
error "agent 服务启动失败,查看: rc-service x-ui-agent status"
fi
}
# 无服务管理器时回落 nohup(无开机自启,明确警告)
start_via_nohup() {
warn "未检测到 systemd / OpenRC,退回 nohup 方式启动"
warn "注意:nohup 方式没有开机自启,机器重启后 agent 不会自动恢复,需手动重跑本脚本!"
pkill -f "${AGENT_BIN} agent" 2>/dev/null || true; sleep 1
# -config 显式给出(生产环境即其默认路径 /etc/x-ui/agent.json,行为不变),
# 这样 XUI_ROOT 假根验证时 agent 也能找到刚写下的配置。
nohup "${AGENT_BIN}" agent -config "${CONF_DIR}/agent.json" > /tmp/agent.log 2>&1 &
sleep 8
if grep -q "Starting 3x-ui agent" /tmp/agent.log 2>/dev/null; then
info "agent 启动成功!"
echo ""
echo " 主控: $MASTER"
echo " 节点名: $NAME"
echo " 日志: tail -f /tmp/agent.log"
echo " agent 会在 30 秒内从主控拉取配置"
else
error "启动失败,查看日志: cat /tmp/agent.log"
fi
}
info "启动 agent..."
case "$(detect_init_system)" in
systemd) start_via_systemd;;
openrc) start_via_openrc;;
*) start_via_nohup;;
esac