SSH 密钥登录与安全加固
两类密钥不要混淆
- 用户密钥:私钥留在 WSL2;公钥追加到 VPS 用户的
~/.ssh/authorized_keys。它回答“谁在登录”。 - 主机密钥:私钥留在 VPS 的
/etc/ssh/;客户端在首次连接时保存公钥指纹。它回答“连到的是不是原来那台服务器”。
私钥没有 .pub 后缀,绝不能复制到 VPS、网站或聊天中。需要确认身份时输出公钥指纹:
[LOCAL: WSL2]
test -f "$LOCAL_SSH_PUBLIC_KEY"
ssh-keygen -lf "$LOCAL_SSH_PUBLIC_KEY"
安装用户公钥
[LOCAL: WSL2]
ssh-copy-id -i "$LOCAL_SSH_PUBLIC_KEY" "$VPS_USER@$VPS_PUBLIC_IPV4"
ssh-copy-id会追加公钥,不应覆盖已有的 authorized_keys。远端权限通常应为:
[REMOTE: VPS]
stat -c '%a %U:%G %n' ~/.ssh ~/.ssh/authorized_keys
# 期望:目录 700,文件 600
明确测试“只用公钥”
普通 ssh 成功可能仍是密码认证。用客户端选项排除密码:
[LOCAL: WSL2]
ssh \
-i "$HOME/.ssh/id_ed25519" \
-o IdentitiesOnly=yes \
-o PreferredAuthentications=publickey \
-o PasswordAuthentication=no \
"$VPS_USER@$VPS_PUBLIC_IPV4"
必须在第二个新会话中通过,同时保留原始已知可用会话。
用配置片段加固 sshd
Ubuntu 支持 /etc/ssh/sshd_config.d/*.conf。OpenSSH 对多数指令采用“获得的第一个值”,而通配符文件名按词法顺序读取。因此较晚的 99-...conf 不一定覆盖较早的 cloud-init 设置;必须检查实际 include 顺序和有效值。
[REMOTE: VPS]
grep -nE '^[[:space:]]*Include|^[[:space:]]*(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication)' \
/etc/ssh/sshd_config
sudo find /etc/ssh/sshd_config.d -maxdepth 1 -type f -print
在确认顺序后创建一个足够早、职责单一的片段,例如:
/etc/ssh/sshd_config.d/00-personal-infra.conf
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
这里关闭的是 SSH 密码认证和 root 直接登录,不是删除用户,也不是删除已有公钥。
验证、重载、再验证
[REMOTE: VPS]
sudo sshd -t
sudo sshd -T | grep -E \
'^(permitrootlogin|passwordauthentication|pubkeyauthentication) '
sudo systemctl reload ssh
预期有效值:
permitrootlogin no
passwordauthentication no
pubkeyauthentication yes
sshd -t无输出且退出码为 0 才算语法通过。使用 reload让服务重新读取配置,不需要为了这项修改重启整台 VPS。重载后,再从 WSL2 打开第三个全新公钥会话。
首次连接时的主机指纹
看到 “authenticity can't be established” 时,不要机械输入 yes。可以从已知可信的旧路径读取 VPS 公钥指纹:
[REMOTE: known-good session]
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
与客户端提示逐字一致后再接受。系统重装会合理地改变主机密钥;未计划的变化则可能是地址复用、中间人攻击或连错机器。
故障排查
[REMOTE: keep known-good session open]
sudo sshd -t
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication) '
sudo journalctl -fu ssh.service
客户端可增加 -vvv查看协商过程,但日志可能包含用户名、地址和路径,公开前要脱敏。任何新连接失败都应停止防火墙收口,并保留现有会话。