diff --git a/vps-snapshot.sh b/vps-snapshot.sh index 501c8c3..e83b133 100755 --- a/vps-snapshot.sh +++ b/vps-snapshot.sh @@ -54,7 +54,7 @@ install_deps() { check_deps() { local missing="" command -v rsync &>/dev/null || missing+=" rsync" - command -v sshpass &>/dev/null || missing+=" sshpass" + # sshpass is optional when using key auth command -v jq &>/dev/null || missing+=" jq" if [ -n "$missing" ]; then @@ -631,7 +631,7 @@ cleanup_remote() { local remote_path="${REMOTE_DIR:-/backup}/${VPS_NAME:-$(hostname)}" log "🧹 清理远程旧快照 (保留${days}天)..." - sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \ + _ssh_wrap ssh -o StrictHostKeyChecking=no \ -p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \ "find $remote_path -name '*.tar.gz' -mtime +$days -delete 2>/dev/null" || true } @@ -883,7 +883,7 @@ do_restore_config_remote() { echo "" # 获取远程快照列表 - local snap_list=$(sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \ + local snap_list=$(_ssh_wrap ssh -o StrictHostKeyChecking=no \ -p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \ "ls -t $remote_path/*.tar.gz 2>/dev/null") @@ -895,7 +895,7 @@ do_restore_config_remote() { local snaps=() while read -r snap; do local name=$(basename "$snap") - local size=$(sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \ + local size=$(_ssh_wrap ssh -o StrictHostKeyChecking=no \ -p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \ "ls -lh '$snap' 2>/dev/null | awk '{print \$5}'" 2>/dev/null) echo " $i) $name ($size)" @@ -916,7 +916,7 @@ do_restore_config_remote() { log "下载快照: $(basename "$selected")" local local_file="/tmp/remote_snapshot_$$.tar.gz" - sshpass -p "$REMOTE_PASS" scp -o StrictHostKeyChecking=no \ + _ssh_wrap scp -o StrictHostKeyChecking=no \ -P "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP:$selected" "$local_file" [ ! -f "$local_file" ] && { error "下载失败"; return 1; } @@ -1012,12 +1012,12 @@ do_sync_remote() { log "📤 同步到远程: $REMOTE_IP:$remote_path" # 创建远程目录(以VPS名称命名) - sshpass -p "$REMOTE_PASS" ssh -o StrictHostKeyChecking=no \ + _ssh_wrap ssh -o StrictHostKeyChecking=no \ -p "${REMOTE_PORT:-22}" "${REMOTE_USER:-root}@$REMOTE_IP" \ "mkdir -p $remote_path" # 同步到VPS专属目录 - sshpass -p "$REMOTE_PASS" rsync -avz --progress \ + _ssh_wrap rsync -avz --progress \ -e "ssh -o StrictHostKeyChecking=no -p ${REMOTE_PORT:-22}" \ "$latest" "${REMOTE_USER:-root}@$REMOTE_IP:$remote_path/" @@ -1140,6 +1140,31 @@ load_config() { [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE" } +# SSH/SCP/rsync 前缀:有key用key,有密码用sshpass,都没有走默认 +_ssh_wrap() { + local mode="$1"; shift + local key="${REMOTE_KEY:-}" pass="${REMOTE_PASS:-}" + if [ -n "$key" ] && [ -f "$key" ]; then + case "$mode" in + ssh) ssh -i "$key" "$@" ;; + scp) scp -i "$key" "$@" ;; + rsync) rsync -e "ssh -i $key" "$@" ;; + esac + elif [ -n "$pass" ]; then + case "$mode" in + ssh) sshpass -p "$pass" ssh "$@" ;; + scp) sshpass -p "$pass" scp "$@" ;; + rsync) sshpass -p "$pass" rsync "$@" ;; + esac + else + case "$mode" in + ssh) ssh "$@" ;; + scp) scp "$@" ;; + rsync) rsync "$@" ;; + esac + fi +} + save_config() { cat > "$CONFIG_FILE" << EOF VPS_NAME="$VPS_NAME" @@ -1149,6 +1174,7 @@ REMOTE_IP="$REMOTE_IP" REMOTE_PORT="$REMOTE_PORT" REMOTE_USER="$REMOTE_USER" REMOTE_PASS="$REMOTE_PASS" +REMOTE_KEY="$REMOTE_KEY" REMOTE_DIR="$REMOTE_DIR" REMOTE_KEEP_DAYS="$REMOTE_KEEP_DAYS" TG_BOT_TOKEN="$TG_BOT_TOKEN" @@ -1179,8 +1205,9 @@ do_setup() { REMOTE_PORT=${REMOTE_PORT:-22} read -p "远程用户 [root]: " REMOTE_USER REMOTE_USER=${REMOTE_USER:-root} - read -s -p "远程密码: " REMOTE_PASS + read -s -p "远程密码 (key认证留空): " REMOTE_PASS echo "" + read -p "远程密钥路径 (密码认证留空): " REMOTE_KEY read -p "远程目录 [/backup]: " REMOTE_DIR REMOTE_DIR=${REMOTE_DIR:-/backup} read -p "远程保留天数 [30]: " REMOTE_KEEP_DAYS