问题分析

当您重装Linux系统时,新的操作系统会生成全新的SSH主机密钥。客户端SSH会检测到远程主机的密钥与本地 known_hosts 文件中的记录不匹配,因此拒绝连接。

警告原因:

  • 新系统的 ED25519 密钥与旧系统的 ECDSA 密钥不同
  • SSH 严格验证模式(StrictHostKeyChecking)被启用
  • 这是一项安全特性,防止中间人攻击(MITM)

解决方案

方案 1:逐次移除旧密钥(推荐 - 手动控制)

优点: 安全,需要明确意识到密钥变化
缺点: 每次重装都需要手动处理

步骤 1:移除旧密钥

# 使用SSH提示中给出的命令
ssh-keygen -f ~/.ssh/known_hosts -R "192.168.114.12"

步骤 2:接受新密钥

ssh 192.168.114.12
# 首次连接时会提示:
# The authenticity of host '192.168.114.12 (192.168.114.12)' can't be established.
# 输入 'yes' 接受新密钥

方案 2:自动忽略主机密钥验证(快速 - 仅用于测试环境)

⚠️ 安全警告: 仅用于可信的内网测试环境。不要在生产环境或不信任的网络中使用。

方法 A:单次连接忽略验证

ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 192.168.114.12

方法 B:为特定主机配置 SSH config

编辑 ~/.ssh/config:

Host 192.168.114.12
    StrictHostKeyChecking no
    UserKnownHostsFile=/dev/null
    User root
    Port 22

然后直接连接:

ssh 192.168.114.12

方法 C:创建带自动接受的脚本

#!/bin/bash
# auto-ssh.sh

HOST="192.168.114.12"
USER="root"

# 删除旧密钥并自动接受新密钥
ssh-keygen -f ~/.ssh/known_hosts -R "$HOST" 2>/dev/null || true
echo "| ssh-keyscan $HOST 2>/dev/null >> ~/.ssh/known_hosts"
ssh-keyscan "$HOST" 2>/dev/null >> ~/.ssh/known_hosts

# 连接
ssh "$USER@$HOST"

使用:

chmod +x auto-ssh.sh
./auto-ssh.sh

方案 3:使用 expect 脚本自动化(推荐 - 完全自动化)

创建 connect-test-host.sh:

#!/bin/bash
# 完全自动化的SSH连接脚本

HOST="${1:-192.168.114.12}"
USER="${2:-root}"
PASSWORD="${3:-your_password}"

# 清理旧密钥
echo "[*] 移除旧的主机密钥..."
ssh-keygen -f ~/.ssh/known_hosts -R "$HOST" 2>/dev/null || true

# 使用ssh-keyscan添加新密钥
echo "[*] 扫描并添加新的主机密钥..."
ssh-keyscan -H "$HOST" 2>/dev/null >> ~/.ssh/known_hosts

# 连接
echo "[*] 正在连接到 $HOST ..."
ssh "$USER@$HOST"

使用:

chmod +x connect-test-host.sh
./connect-test-host.sh 192.168.114.12 root

方案 4:批量测试主机的高效方法

如果您有多个测试主机,创建 ssh-batch-connect.sh:

#!/bin/bash
# 批量管理多个测试主机的密钥和连接

declare -A HOSTS=(
    ["host1"]="192.168.114.12:root"
    ["host2"]="192.168.114.13:root"
    ["host3"]="192.168.114.14:admin"
)

function clean_host_keys() {
    local ip="${1%:*}"
    echo "[*] 清理主机 $ip 的密钥..."
    ssh-keygen -f ~/.ssh/known_hosts -R "$ip" 2>/dev/null || true
}

function add_host_keys() {
    local ip="${1%:*}"
    echo "[*] 扫描主机 $ip 的新密钥..."
    ssh-keyscan -H "$ip" 2>/dev/null >> ~/.ssh/known_hosts 2>/dev/null
}

function connect_host() {
    local entry="$1"
    local ip="${entry%:*}"
    local user="${entry#*:}"
    echo "[*] 连接到 $user@$ip ..."
    ssh "$user@$ip"
}

case "$1" in
    clean-all)
        echo "=== 清理所有主机密钥 ==="
        for key in "${!HOSTS[@]}"; do
            clean_host_keys "${HOSTS[$key]}"
        done
        ;;
    refresh-all)
        echo "=== 刷新所有主机密钥 ==="
        for key in "${!HOSTS[@]}"; do
            clean_host_keys "${HOSTS[$key]}"
            add_host_keys "${HOSTS[$key]}"
        done
        ;;
    connect)
        echo "=== 可用主机 ==="
        for key in "${!HOSTS[@]}"; do
            echo "  $key: ${HOSTS[$key]}"
        done
        read -p "选择主机名: " host_name
        if [ -n "${HOSTS[$host_name]}" ]; then
            clean_host_keys "${HOSTS[$host_name]}"
            add_host_keys "${HOSTS[$host_name]}"
            connect_host "${HOSTS[$host_name]}"
        else
            echo "主机不存在!"
        fi
        ;;
    *)
        echo "用法: $0 {clean-all|refresh-all|connect}"
        ;;
esac

使用:

chmod +x ssh-batch-connect.sh

# 刷新所有主机的密钥
./ssh-batch-connect.sh refresh-all

# 交互式连接
./ssh-batch-connect.sh connect

SSH Config 完整配置示例

编辑 ~/.ssh/config,为测试主机统一配置:

# 测试主机组
Host test-*
    StrictHostKeyChecking accept-new
    UserKnownHostsFile ~/.ssh/known_hosts
    ConnectTimeout 5
    ServerAliveInterval 60
    User root

# 特定主机配置
Host test-192.168.114.12
    HostName 192.168.114.12
    Port 22
    IdentityFile ~/.ssh/id_rsa

Host test-192.168.114.13
    HostName 192.168.114.13
    Port 2222
    IdentityFile ~/.ssh/id_rsa

使用方式:

# 首次连接会自动接受新密钥
ssh test-192.168.114.12

# 切换新系统后可直接连接(不会报错)
ssh test-192.168.114.12

安全最佳实践

场景推荐方案说明
生产环境方案 1手动验证每个密钥变化
内网测试环境方案 3/4使用脚本自动化,结合 SSH config
开发/学习方案 2可忽略验证,但仅用于可信网络
CI/CD 测试方案 4 + 无密码认证结合SSH密钥对实现完全自动化

排除故障

问题:脚本执行权限不足

chmod +x script.sh

问题:ssh-keyscan 超时

# 增加超时时间
ssh-keyscan -T 5 192.168.114.12 >> ~/.ssh/known_hosts

问题:known_hosts 文件损坏

# 备份并重建
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.bak
> ~/.ssh/known_hosts

# 重新添加必要的主机
ssh-keyscan -H 192.168.114.12 >> ~/.ssh/known_hosts

问题:Permission denied 而非密钥警告

这不是密钥问题,而是认证问题。检查:

  • SSH用户名是否正确
  • 是否配置了公钥认证(如使用密码需要在config中加 PasswordAuthentication yes)
  • 远程主机的SSH配置

总结

对于经常重装系统的测试场景,我的建议是:

✅ 最佳方案: 使用 方案 4(批量脚本)+ SSH Config 组合

  • 自动化程度高,减少手动操作
  • 安全和效率的平衡
  • 易于扩展多个测试主机

这样每次系统重装后,只需运行一个脚本就能完成密钥更新和连接。