SSH 是你管理 VPS 的唯一入口。如果 SSH 被攻破,服务器上的一切——你的代理配置、用户数据、密钥文件——都将暴露。好消息是,SSH 加固的步骤非常明确,五步操作就能把安全性提升一个量级。
一、生成 Ed25519 密钥对
SSH 密钥认证比密码认证安全得多:暴力破解密码需要几秒到几分钟,暴力破解 256 位的 Ed25519 密钥需要的时间超过宇宙年龄。
1.1 为什么选 Ed25519
| 密钥类型 | 安全性 | 密钥长度 | 性能 | 推荐 |
|---|---|---|---|---|
| Ed25519 | 极高 | 256 位 | 快 | 推荐首选 |
| RSA 4096 | 高 | 4096 位 | 较慢 | 兼容性好时可用 |
| RSA 2048 | 够用 | 2048 位 | 快 | 旧系统不得已 |
| ECDSA | 高 | 256/384/521 位 | 快 | 不推荐(实现易有随机数问题) |
| DSA | 已淘汰 | 1024 位 | — | 禁止使用 |
1.2 在本地电脑生成密钥
在你的本地电脑(不是 VPS)上执行:
# 生成 Ed25519 密钥对
ssh-keygen -t ed25519 -C "你的邮箱@example.com"
# 生成过程会提示:
# 1. 保存路径 → 直接回车用默认路径 (~/.ssh/id_ed25519)
# 2. 设置密码短语(passphrase)→ 强烈建议设置
# 3. 确认密码短语
ssh-agent 缓存密码短语,输入一次后在终端会话期间免重复输入。1.3 将公钥上传到 VPS
# 方法一:ssh-copy-id(最简单)
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@你的VPS_IP
# 方法二:手动追加
cat ~/.ssh/id_ed25519.pub | ssh root@你的VPS_IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
1.4 验证密钥登录
上传公钥后,开一个新的终端窗口测试密钥登录:
ssh -i ~/.ssh/id_ed25519 root@你的VPS_IP
如果能正常登录(输入密码短语后),说明密钥认证已生效。确认没问题后,再进行下一步。
二、禁用密码登录
密钥认证确认可用后,禁用密码登录。这一步堵死了暴力破解的入口。
# 在 VPS 上编辑 SSH 配置
vi /etc/ssh/sshd_config
修改或添加以下配置项:
# 禁用密码登录
PasswordAuthentication no
# 禁用空密码
PermitEmptyPasswords no
# 禁用 root 密码登录(可选但推荐)
PermitRootLogin prohibit-password
重启 SSH 服务使配置生效:
# Debian / Ubuntu
systemctl restart ssh
# CentOS / RHEL
systemctl restart sshd
三、更换 SSH 端口
默认端口 22 是全球扫描器的首要目标。换成非标准端口后,自动化扫描的命中率会大幅下降。
3.1 选择端口号
推荐选择 1024-65535 范围内的端口,避开常见服务端口:
| 推荐端口 | 说明 |
|---|---|
| 2222 | 最常用的 SSH 替代端口 |
| 2200 | 简洁好记 |
| 443 | 与 HTTPS 混淆(需确认不与代理冲突) |
| 10022 | 足够隐蔽 |
3.2 修改端口
# 编辑 SSH 配置
vi /etc/ssh/sshd_config
# 找到 Port 22,改为(以 2222 为例)
Port 2222
# 重启 SSH
systemctl restart ssh
3.3 防火墙同步
端口修改后,需要同步更新防火墙规则(以 iptables 为例):
# 放行新端口
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
# 删除旧端口规则(如果有)
iptables -D INPUT -p tcp --dport 22 -j ACCEPT
# 保存规则
netfilter-persistent save
ufw 用户:
ufw allow 2222/tcp
ufw delete allow 22/tcp
ufw status
3.4 验证新端口
开一个新终端窗口,用新端口连接:
ssh -p 2222 root@你的VPS_IP
确认正常后,再关闭旧终端。
四、安装 fail2ban 防暴力破解
即使禁用了密码登录、更换了端口,SSH 仍然可能受到连接风暴和端口扫描的骚扰。fail2ban 监控登录日志,自动封禁反复失败的 IP。
4.1 安装
# Debian / Ubuntu
apt install fail2ban -y
# CentOS / RHEL
yum install fail2ban -y
# 启动并设置开机自启
systemctl enable --now fail2ban
4.2 配置
fail2ban 不要直接修改 /etc/fail2ban/jail.conf,而是创建 jail.local 覆盖配置:
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 封禁时间(秒)
bantime = 3600
# 检测窗口(秒)
findtime = 600
# 最大失败次数
maxretry = 5
# 使用 iptables 封禁
banaction = iptables-multiport
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
EOF
logpath — Debian/Ubuntu 用
/var/log/auth.log,CentOS 用 /var/log/securemaxretry — 同一 IP 在检测窗口内失败多少次后封禁
bantime — 封禁时长,86400 = 24 小时
4.3 重启并验证
# 重启 fail2ban
systemctl restart fail2ban
# 查看 SSH jail 状态
fail2ban-client status sshd
# 查看被封禁的 IP 列表
fail2ban-client status sshd | grep "Banned IP"
4.4 手动封禁/解封 IP
# 手动封禁一个 IP
fail2ban-client set sshd banip 1.2.3.4
# 手动解封一个 IP
fail2ban-client set sshd unbanip 1.2.3.4
五、登录审计与日志监控
加固完成后,定期检查登录日志可以帮你发现异常行为。
5.1 查看登录日志
# 查看最近的 SSH 登录记录
journalctl -u ssh --since "7 days ago"
# 或直接查看日志文件
grep "sshd" /var/log/auth.log | tail -30
# 查看成功登录记录
grep "Accepted" /var/log/auth.log | tail -20
# 查看失败登录记录
grep "Failed" /var/log/auth.log | tail -20
5.2 检查异常登录
关注以下异常信号:
- 陌生 IP 登录:除了你的出口 IP,是否有其他 IP 成功登录过?
- 非工作时间登录:凌晨 2-5 点的登录记录需要关注。
- root 直接登录:如果你已经创建了普通用户,root 直接登录应该很少出现。
- 大量失败尝试:来自同一 IP 的多次失败可能意味着针对性攻击。
# 一键查看:按 IP 统计登录次数
grep "Accepted" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -10
# 查看指定时间段的登录记录
grep "sshd" /var/log/auth.log | grep "Jul 14"
5.3 创建普通用户(可选但推荐)
长期使用 root 直接登录有风险。创建一个普通用户,需要管理员权限时用 sudo:
# 创建用户
adduser deploy
# 加入 sudo 组
usermod -aG sudo deploy
# 将 SSH 公钥复制到新用户
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@你的VPS_IP
# 测试新用户登录
ssh -p 2222 deploy@你的VPS_IP
# 确认正常后,可选:禁止 root 直接 SSH 登录
# 在 /etc/ssh/sshd_config 中设置:
PermitRootLogin no
六、完整加固脚本
将以上步骤整合为一个一键脚本,在新 VPS 上直接执行:
#!/bin/bash
# SSH 安全加固脚本 — 在 VPS 上执行
# 执行前确认:已通过 ssh-copy-id 上传了公钥
set -e
echo "=== SSH 安全加固开始 ==="
# 1. 安装 fail2ban
apt update && apt install fail2ban -y
# 2. 配置 fail2ban
cat > /etc/fail2ban/jail.local << 'FAIL2BAN'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
banaction = iptables-multiport
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
FAIL2BAN
systemctl enable --now fail2ban
# 3. 修改 SSH 配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sed -i 's/^#\?Port .*/Port 2222/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication .*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitEmptyPasswords .*/PermitEmptyPasswords no/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin .*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
# 4. 重启 SSH
systemctl restart ssh
echo "=== 加固完成 ==="
echo "SSH 端口已改为 2222"
echo "密码登录已禁用"
echo "fail2ban 已安装并配置"
echo ""
echo "请用新终端测试:ssh -p 2222 root@你的VPS_IP"
七、常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 禁用密码后无法登录 | 公钥未正确上传 | 通过控制台检查 ~/.ssh/authorized_keys 内容 |
| 更换端口后连接超时 | 防火墙未放行新端口 | 通过控制台添加防火墙规则 |
| fail2ban 封禁了自己 | 多次输错密码短语 | fail2ban-client set sshd unbanip 你的IP |
| 密钥登录提示权限错误 | .ssh 目录权限不对 | chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys |
| 连接被拒绝(Connection refused) | SSH 服务未运行 | 通过控制台执行 systemctl start ssh |
| 公钥认证不生效 | sshd_config 中禁用了公钥认证 | 确认 PubkeyAuthentication yes(默认是开的) |
7.1 检查文件权限
SSH 对文件权限非常严格,权限不对会导致认证失败:
# 正确的权限设置
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/id_ed25519.pub
# 一键修复
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
7.2 紧急恢复
如果被锁在外面,通过 VPS 控制台登录后:
# 恢复 SSH 配置
cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
systemctl restart ssh
# 或临时启用密码登录
sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
systemctl restart ssh
八、加固检查清单
Ed25519 密钥对
在本地生成密钥对并上传公钥到 VPS,验证密钥登录可用。
禁用密码登录
设置 PasswordAuthentication no,确认密钥登录正常后重启 SSH。
更换端口
将 SSH 端口改为 2222 等非标准端口,同步更新防火墙规则。
安装 fail2ban
配置自动封禁规则,3 次失败封禁 24 小时。
登录审计
定期检查登录日志,关注异常 IP 和非工作时间登录。