Linux 优化SSH安全配置
下面是优化后的版本,支持:
- 自动备份 sshd_config
- 自动写入公钥,避免重复追加
- 修改 SSH 端口
- 禁用密码登录
- 启用公钥登录
- 配置防火墙
- 安装并启用 fail2ban
- 配置 fail2ban 保护新 SSH 端口
运行前建议保留当前 SSH 会话不要断开,新开一个终端测试 ssh -p 25701 user@server 成功后再关闭旧连接。
生成 SSH 密钥
1、 以管理员身份打开 Windows PowerShell
2、 使用以下命令生成 SSH 密钥对:
ssh-keygen -t ed25519 -C "your_email@example.com"如果 VPS 较老不支持 ed25519,使用 RSA 算法:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"3、 设置保存路径
Enter file in which to save the key (/c/Users/你的用户名/.ssh/id_ed25519):直接按回车使用默认路径:C:\Users\你的用户名\.ssh\
4、 设置密钥的密码(可选,可直接留空):
设置密码会增加安全性,但每次使用密钥时都需要输入密码。如果追求便利性,可以留空。
5、 密钥生成完成后,会在指定目录创建两个文件:
- 私钥文件 : id_ed25519
- 公钥文件 : id_ed25519.pub
需要公钥文件上传到 VPS 服务器
操作方法
SSH 登录
ssh root@你的服务器IP- 然后执行
nano harden-ssh.sh- 把完整脚本粘贴进去,把公钥:
ssh-ed25519...hotmail.com替换你的
#!/usr/bin/env bash
set -Eeuo pipefail
SSH_PORT="25701"
TARGET_USER="root"
PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAPvwkcejp5Ck088PyCTsRhJM+LEph1mhDAFQjx/r82/ guboysky@hotmail.com"
FAIL2BAN_MAXRETRY="3"
FAIL2BAN_FINDTIME="10m"
FAIL2BAN_BANTIME="24h"
if [[ "$EUID" -ne 0 ]]; then
echo "请使用 root 或 sudo 运行"
exit 1
fi
if ! [[ "$SSH_PORT" =~ ^[0-9]+$ ]] || (( SSH_PORT < 1 || SSH_PORT > 65535 )); then
echo "SSH_PORT 必须是 1-65535"
exit 1
fi
if [[ -z "$PUBLIC_KEY" ]]; then
echo "缺少 PUBLIC_KEY"
exit 1
fi
if ! getent passwd "$TARGET_USER" >/dev/null; then
echo "用户不存在:$TARGET_USER"
exit 1
fi
USER_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
USER_GROUP="$(id -gn "$TARGET_USER")"
echo "==> 写入 SSH 公钥到 $TARGET_USER"
install -d -m 700 -o "$TARGET_USER" -g "$USER_GROUP" "$USER_HOME/.ssh"
touch "$USER_HOME/.ssh/authorized_keys"
chown "$TARGET_USER:$USER_GROUP" "$USER_HOME/.ssh/authorized_keys"
chmod 600 "$USER_HOME/.ssh/authorized_keys"
if ! grep -qxF "$PUBLIC_KEY" "$USER_HOME/.ssh/authorized_keys"; then
echo "$PUBLIC_KEY" >> "$USER_HOME/.ssh/authorized_keys"
fi
echo "==> 备份并加固 sshd"
SSHD_CONFIG="/etc/ssh/sshd_config"
BACKUP_FILE="${SSHD_CONFIG}.bak.$(date +%F-%H%M%S)"
cp -a "$SSHD_CONFIG" "$BACKUP_FILE"
mkdir -p /etc/ssh/sshd_config.d
if ! grep -Eq '^[[:space:]]*Include[[:space:]]+/etc/ssh/sshd_config\.d/\*\.conf' "$SSHD_CONFIG"; then
sed -i '1i Include /etc/ssh/sshd_config.d/*.conf' "$SSHD_CONFIG"
fi
sed -i -E \
-e 's/^[[:space:]]*(Port[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(PasswordAuthentication[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(KbdInteractiveAuthentication[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(ChallengeResponseAuthentication[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(PermitRootLogin[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(PubkeyAuthentication[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(X11Forwarding[[:space:]]+)/# managed by harden-ssh: \1/' \
-e 's/^[[:space:]]*(MaxAuthTries[[:space:]]+)/# managed by harden-ssh: \1/' \
"$SSHD_CONFIG"
cat > /etc/ssh/sshd_config.d/99-hardening.conf <<EOF
Port ${SSH_PORT}
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin prohibit-password
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers ${TARGET_USER}
ClientAliveInterval 300
ClientAliveCountMax 2
UseDNS no
EOF
mkdir -p /run/sshd
if ! sshd -t -f "$SSHD_CONFIG"; then
echo "sshd 配置错误,已备份:$BACKUP_FILE"
exit 1
fi
echo "==> 配置防火墙"
if command -v ufw >/dev/null 2>&1; then
ufw allow "${SSH_PORT}/tcp"
ufw reload || true
elif command -v firewall-cmd >/dev/null 2>&1; then
firewall-cmd --permanent --add-port="${SSH_PORT}/tcp"
firewall-cmd --reload
else
echo "未检测到 ufw/firewalld,请手动放行端口 ${SSH_PORT}/tcp"
fi
echo "==> 安装 fail2ban"
if ! command -v fail2ban-client >/dev/null 2>&1; then
if command -v apt-get >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y fail2ban
elif command -v dnf >/dev/null 2>&1; then
dnf install -y fail2ban
elif command -v yum >/dev/null 2>&1; then
yum install -y epel-release || true
yum install -y fail2ban
else
echo "无法自动安装 fail2ban,请手动安装"
fi
fi
echo "==> 配置 fail2ban"
mkdir -p /etc/fail2ban/jail.d
if command -v journalctl >/dev/null 2>&1; then
FAIL2BAN_BACKEND="systemd"
else
FAIL2BAN_BACKEND="auto"
fi
cat > /etc/fail2ban/jail.d/sshd.local <<EOF
[sshd]
enabled = true
port = ${SSH_PORT}
filter = sshd
backend = ${FAIL2BAN_BACKEND}
maxretry = ${FAIL2BAN_MAXRETRY}
findtime = ${FAIL2BAN_FINDTIME}
bantime = ${FAIL2BAN_BANTIME}
ignoreip = 127.0.0.1/8 ::1
EOF
systemctl enable --now fail2ban || true
systemctl restart fail2ban || true
echo "==> 重启 SSH"
if systemctl list-unit-files | grep -q '^ssh.service'; then
systemctl restart ssh
elif systemctl list-unit-files | grep -q '^sshd.service'; then
systemctl restart sshd
else
service ssh restart || service sshd restart
fi
echo
echo "加固完成"
echo
echo "测试登录:"
echo "ssh -p ${SSH_PORT} ${TARGET_USER}@你的服务器IP"
echo
echo "查看 SSH 监听:"
echo "ss -lntp | grep ${SSH_PORT}"
echo
echo "查看 fail2ban:"
echo "fail2ban-client status sshd"
echo
echo "原配置备份:$BACKUP_FILE"- 保存后执行:
chmod +x harden-ssh.sh
./harden-ssh.sh