Files
BackupX/server/internal/installscript/templates/agent-install.sh.tmpl
Wu Qing 5827074334 feat: 优化集群部署与堡垒机接入 (#106)
支持受限网络、正向代理、私有 CA 与 SSH 堡垒机部署 Agent。

加固 Docker、systemd、Nginx、安装器、Release 校验与可信代理边界,并完善命令队列索引、前端安装向导及中英文运维文档。
2026-08-09 02:45:17 +08:00

211 lines
7.8 KiB
Bash
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/sh
# BackupX Agent 一键安装脚本(由 Master 动态渲染)
# Magic: BACKUPX_AGENT_INSTALL_V1 —— 若 `head -3 脚本` 看不到此行,说明反向代理或 CDN 改写了响应
# 模式: {{.Mode}} | 架构: {{.Arch}} | 版本: {{.AgentVersion}}
set -eu
umask 077
# 文件执行模式下优先使用 bash管道模式继续使用 POSIX sh。
if [ -z "${BASH_VERSION:-}" ] && command -v bash >/dev/null 2>&1 && [ -f "$0" ]; then
exec bash "$0" "$@"
fi
MASTER_URL="{{.MasterURL}}"
AGENT_TOKEN="{{.AgentToken}}"
AGENT_VERSION="{{.AgentVersion}}"
DOWNLOAD_BASE="{{.DownloadBase}}"
INSTALL_PREFIX="{{.InstallPrefix}}"
ARCH="{{.Arch}}"
PROXY_URL="{{.ProxyURL}}"
CA_CERT_FILE="{{.CACertFile}}"
CONFIG_DIR="/etc/backupx-agent"
CONFIG_FILE="${CONFIG_DIR}/config.yaml"
TOKEN_FILE="${CONFIG_DIR}/agent.token"
download_file() {
source_url="$1"
destination="$2"
if command -v curl >/dev/null 2>&1; then
if [ -n "$PROXY_URL" ]; then
curl -fsSL --retry 3 --retry-delay 2 --connect-timeout 15 --proxy "$PROXY_URL" "$source_url" -o "$destination"
else
curl -fsSL --retry 3 --retry-delay 2 --connect-timeout 15 "$source_url" -o "$destination"
fi
else
wget -q -T 30 -O "$destination" "$source_url"
fi
}
agent_is_online() {
if command -v curl >/dev/null 2>&1; then
if [ -n "$PROXY_URL" ] && [ -n "$CA_CERT_FILE" ]; then
response=$(curl -fsS --max-time 5 --proxy "$PROXY_URL" --cacert "$CA_CERT_FILE" -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null) || return 1
elif [ -n "$PROXY_URL" ]; then
response=$(curl -fsS --max-time 5 --proxy "$PROXY_URL" -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null) || return 1
elif [ -n "$CA_CERT_FILE" ]; then
response=$(curl -fsS --max-time 5 --cacert "$CA_CERT_FILE" -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null) || return 1
else
response=$(curl -fsS --max-time 5 -H "X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null) || return 1
fi
else
response=$(wget -q -T 5 --max-redirect=0 -O - --header="X-Agent-Token: ${AGENT_TOKEN}" "${MASTER_URL}/api/v1/agent/self" 2>/dev/null) || return 1
fi
printf '%s' "$response" | grep -q '"status":"online"'
}
# 1. 前置检查
[ "$(id -u)" -eq 0 ] || { echo "请使用 root 或 sudo 执行" >&2; exit 1; }
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 \
|| { echo "需要 curl 或 wget" >&2; exit 1; }
command -v grep >/dev/null 2>&1 || { echo "需要 grep" >&2; exit 1; }
if { [ -n "$PROXY_URL" ] || [ -n "$CA_CERT_FILE" ]; } && ! command -v curl >/dev/null 2>&1; then
echo "显式代理或自定义 CA 场景需要 curl" >&2
exit 1
fi
{{if eq .Mode "systemd"}}command -v systemctl >/dev/null 2>&1 || { echo "当前系统不支持 systemd" >&2; exit 1; }
{{end}}{{if eq .Mode "docker"}}command -v docker >/dev/null 2>&1 || { echo "需要先安装 Docker" >&2; exit 1; }
{{end}}
# 2. 架构检测
if [ "$ARCH" = "auto" ]; then
case "$(uname -m)" in
x86_64|amd64) ARCH=amd64 ;;
aarch64|arm64) ARCH=arm64 ;;
*) echo "不支持的架构: $(uname -m)" >&2; exit 1 ;;
esac
fi
# 3. 安全写入 Agent 配置。systemd unit 与容器元数据中不保存节点 Token。
install -d -m 0700 "$CONFIG_DIR" /var/lib/backupx-agent /var/lib/backupx-agent/tmp
printf '%s\n' "$AGENT_TOKEN" > "$TOKEN_FILE"
chmod 0600 "$TOKEN_FILE"
if [ -n "$CA_CERT_FILE" ]; then
[ -r "$CA_CERT_FILE" ] || { echo "无法读取 CA 证书: $CA_CERT_FILE" >&2; exit 1; }
if [ "$CA_CERT_FILE" != "$CONFIG_DIR/ca.pem" ]; then
install -m 0644 "$CA_CERT_FILE" "$CONFIG_DIR/ca.pem"
fi
CA_CERT_FILE="$CONFIG_DIR/ca.pem"
fi
cat > "$CONFIG_FILE" <<CONFIG
master: "${MASTER_URL}"
tokenFile: "${TOKEN_FILE}"
heartbeatInterval: "15s"
pollInterval: "5s"
tempDir: "/var/lib/backupx-agent/tmp"
proxyUrl: "${PROXY_URL}"
caCertFile: "${CA_CERT_FILE}"
CONFIG
chmod 0600 "$CONFIG_FILE"
{{if ne .Mode "docker"}}
# 4. 下载并安装二进制systemd / foreground 模式)
ARCHIVE="backupx-${AGENT_VERSION}-linux-${ARCH}.tar.gz"
URL="${DOWNLOAD_BASE}/${AGENT_VERSION}/${ARCHIVE}"
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT HUP INT TERM
echo "[1/4] 下载 ${URL}"
download_file "$URL" "$TMPDIR/$ARCHIVE"
if download_file "${URL}.sha256" "$TMPDIR/$ARCHIVE.sha256" 2>/dev/null; then
if command -v sha256sum >/dev/null 2>&1; then
(cd "$TMPDIR" && sha256sum -c "$ARCHIVE.sha256")
elif command -v shasum >/dev/null 2>&1; then
(cd "$TMPDIR" && shasum -a 256 -c "$ARCHIVE.sha256")
else
echo "已下载校验文件,但系统缺少 sha256sum 或 shasum拒绝未校验安装" >&2
exit 1
fi
else
echo "[WARN] 当前版本未提供 SHA-256 校验文件,继续兼容安装" >&2
fi
tar xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
echo "[2/4] 安装到 ${INSTALL_PREFIX}"
install -d -m 0755 "$INSTALL_PREFIX"
install -m 0755 "$TMPDIR/backupx-${AGENT_VERSION}-linux-${ARCH}/backupx" "$INSTALL_PREFIX/backupx.new"
mv -f "$INSTALL_PREFIX/backupx.new" "$INSTALL_PREFIX/backupx"
{{end}}
{{if eq .Mode "systemd"}}
# 5. systemd unit
echo "[3/4] 配置 systemd"
cat > /etc/systemd/system/backupx-agent.service <<UNIT
[Unit]
Description=BackupX Agent
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=10
[Service]
Type=simple
ExecStart=${INSTALL_PREFIX}/backupx agent --config ${CONFIG_FILE}
Restart=on-failure
RestartSec=10s
TimeoutStopSec=30s
UMask=0077
# Agent 以 root 运行,以便读取备份源及执行恢复;节点 Token 仅保存在 0600 文件中。
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
UNIT
chmod 0644 /etc/systemd/system/backupx-agent.service
systemctl daemon-reload
if ! systemctl enable backupx-agent || ! systemctl restart backupx-agent; then
echo "BackupX Agent 服务启动失败" >&2
systemctl status backupx-agent --no-pager >&2 || true
journalctl -u backupx-agent -n 100 --no-pager >&2 || true
exit 1
fi
# 6. 等待上线
echo "[4/4] 等待节点上线"
i=0
while [ "$i" -lt 15 ]; do
sleep 2
if agent_is_online; then
echo "[OK] 节点已上线"
exit 0
fi
i=$((i + 1))
done
echo "[WARN] 30 秒内未收到上线心跳,请检查网络、代理或 SSH 隧道" >&2
echo "排查命令: systemctl status backupx-agent" >&2
echo "排查命令: journalctl -u backupx-agent -n 100 --no-pager" >&2
exit 2
{{end}}
{{if eq .Mode "foreground"}}
# 5. 前台运行
echo "[3/3] 前台启动 AgentCtrl+C 退出)"
exec "${INSTALL_PREFIX}/backupx" agent --config "$CONFIG_FILE"
{{end}}
{{if eq .Mode "docker"}}
# Docker 模式:配置文件只读挂载,避免 Token 出现在 docker inspect 环境变量中。
echo "[1/2] 拉取镜像 awuqing/backupx:${AGENT_VERSION}"
docker pull "awuqing/backupx:${AGENT_VERSION}"
echo "[2/2] 启动容器 backupx-agent"
docker rm -f backupx-agent >/dev/null 2>&1 || true
docker run -d --name backupx-agent --restart=unless-stopped --user 0:0 \
--security-opt no-new-privileges:true \
-v /etc/backupx-agent:/etc/backupx-agent:ro \
-v /var/lib/backupx-agent:/var/lib/backupx-agent \
"awuqing/backupx:${AGENT_VERSION}" agent --config /etc/backupx-agent/config.yaml
echo "提示: Docker Agent 只能访问显式挂载的目录;备份宿主机路径前请按文档添加只读 -v 挂载。"
echo "容器已启动,等待节点上线"
i=0
while [ "$i" -lt 15 ]; do
sleep 2
if agent_is_online; then
echo "[OK] 节点已上线"
exit 0
fi
i=$((i + 1))
done
echo "[WARN] 30 秒内未收到上线心跳,请检查容器、代理、隧道与 Master 地址" >&2
echo "排查命令: docker ps -a --filter name=backupx-agent" >&2
echo "排查命令: docker logs --tail=100 backupx-agent" >&2
exit 2
{{end}}