VPS 安全加固完全指南:从 SSH 到 Fail2ban 的实战配置
2023 年 3 月,一起波及数千台云服务器的 SSH 暴力破解攻击在安全社区引发震动——攻击者在短短 72 小时内,利用密码字典对全球范围内使用默认 22 端口、弱密码的 VPS 发起扫荡式攻击,超过 6,000 台 Debian/Ubuntu 实例被植入挖矿木马。事后溯源发现,这些沦陷的服务器有一个共同特征:从开通的那一刻起,从未做过任何安全配置。拿到 root 密码就直接用,甚至连系统日志都没人看。
这个案例不是孤例。Shodan 搜索引擎的实时数据显示,互联网上同时有超过 1,800 万台设备暴露了 SSH 22 端口。如果有一台崭新的 VPS 刚上线,平均 12 分钟内就会收到第一波扫描探测。这不是危言耸听——这是安全研究机构一致观测到的「互联网背景辐射」。对于每一位自建站点的开发者、独立博主、运维入门者来说,安全感不是买出来的,是一步步配出来的。
本文将从零开始,带你系统性地完成一台新 VPS 的安全加固。硬核但不枯燥:每一条配置都附有完整的命令和配置文件示例,你可以直接复制、粘贴、执行。读完这篇,你手里的 VPS 将从「裸奔」状态变成一堵至少需要 SSH 密钥才能敲门的墙。
一、SSH 安全配置:改端口、禁 Root、密钥认证
SSH 是你和服务器之间的唯一大门。所有安全加固都应该从这扇门开始——加固它的锁芯、换掉门牌号、取消万能钥匙。下面三步,按照顺序执行,不跳步。
1.1 创建一个普通用户(在关掉 root 之前)
如果你把 root 登录关了却没建好普通用户,等于自己把自己锁在门外。先建用户,再关门。
# 新建用户(将 "youruser" 替换为你的用户名)
adduser youruser
# 将用户加入 sudo 组
usermod -aG sudo youruser
# 切换到新用户,测试 sudo 是否正常
su - youruser
sudo whoami
# 输出应为 "root"
确认 sudo 正常工作后,接下来配制 SSH 密钥认证——这意味着你需要在自己本地的电脑上生成一对密钥,并把公钥上传到服务器。这样之后就可以彻底告别密码登录。
1.2 配置 SSH 密钥认证
在你本地电脑上(不是服务器),执行以下命令生成 ED25519 密钥对(比 RSA 更快更安全):
# 本地电脑执行(Windows/Mac/Linux 均可)
ssh-keygen -t ed25519 -C "your-email@example.com"
一路回车即可。默认会在 ~/.ssh/id_ed25519 生成私钥,~/.ssh/id_ed25519.pub 生成公钥。然后把公钥上传到服务器:
# 本地电脑执行——把公钥复制到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub youruser@你的服务器IP
# 如果没有 ssh-copy-id,可以手动操作:
# cat ~/.ssh/id_ed25519.pub | ssh youruser@服务器IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
现在你应该可以不用密码登录服务器了。测试一下:
ssh youruser@你的服务器IP
# 如果直接进入系统而不需要输入密码,说明密钥认证成功
确认密钥登录正常后,不要急着关密码登录——先改 SSH 端口,因为改端口过程中如果断连,你还能用原端口回来。
1.3 修改 SSH 监听端口
默认 22 端口是自动化扫描的重灾区。把它换成一个高位端口(10000–65535 之间的任意值),能过滤掉 90% 以上的无差别扫描流量。注意选择未被系统服务占用的端口,建议范围 2222–9999。
# 编辑 SSH 配置文件
sudo nano /etc/ssh/sshd_config
# 找到 #Port 22 这一行,取消注释并修改为:
Port 2222 # 示例端口,建议用你自己的高位端口
改完端口之后,千万不要立刻重启 SSH 服务。你需要先确保防火墙允许新端口通过,否则一封端口自己就连不上了。防火墙部分详见第二节。这里先继续完成 SSH 主配置。
1.4 禁用 root 登录与密码认证
继续编辑 /etc/ssh/sshd_config,修改以下关键参数:
# === 必改安全参数 ===
PermitRootLogin no # 禁止 root 直接 SSH 登录
PasswordAuthentication no # 禁止密码登录(只用密钥)
PubkeyAuthentication yes # 启用公钥认证
AuthorizedKeysFile .ssh/authorized_keys
# === 加固型推荐参数 ===
Protocol 2 # 强制使用 SSH 协议版本 2
MaxAuthTries 3 # 每次连接最多尝试 3 次认证
MaxSessions 2 # 单 IP 最大并发连接数
ClientAliveInterval 300 # 每 300 秒发一次心跳包
ClientAliveCountMax 2 # 心跳失败 2 次即断开
AllowUsers youruser # 仅允许指定用户登录(白名单!)
⚠️ 关键提醒:在重启 sshd 之前,打开一个新的终端窗口测试能否用新用户+密钥+新端口登录。确保新会话成功建立之后,再关闭旧会话并重启服务。一条失败的 SSH 配置足以让你的服务器变成砖——除非你有 VNC 控制台。
确认所有配置无误后,验证配置文件语法并重启 SSH 服务:
# 验证配置语法
sudo sshd -t
# 若无输出,说明语法正确
# 重启 SSH 服务
sudo systemctl restart sshd
# 确认新端口已监听
sudo ss -tlnp | grep 2222
至此,SSH 层面的三道防线已经就位:非标准端口过滤盲扫流量、密钥认证取代弱密码、禁用 root 消除最高权限的爆破目标。
二、防火墙:UFW / iptables 基础规则
防火墙是 VPS 的第二道防线。SSH 配置决定「谁」能进门,防火墙决定「哪些门」对外开放。对于大多数 Linux 新手,UFW(Uncomplicated Firewall)是最友好的选择——它是 iptables 的前端,语法简单且不容易出错。
在此之前要特别提醒:如果你使用了 Docker 或其他容器技术,容器默认会绕过 UFW 规则直接暴露端口。这种情况在你运行 docker run -p 8080:8080 时尤为常见——端口 8080 会出现在公网上,哪怕你的 UFW 规则明确拒绝了它,这是一个容易被忽略且后果严重的坑。解决方案可以参考本站另一篇详解:Docker 端口映射后防火墙失效?6 种方案彻底解决端口暴露问题。
2.1 UFW 安装与基础规则
# 安装 UFW(通常已预装)
sudo apt update && sudo apt install ufw -y
# === 默认策略:拒绝所有入站,允许所有出站 ===
sudo ufw default deny incoming
sudo ufw default allow outgoing
# === 仅开放必要端口 ===
sudo ufw allow 2222/tcp comment 'SSH' # 按你改的端口来
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
# 如果运行 Web 应用或 API,按需开放:
# sudo ufw allow 8080/tcp comment 'App'
# === 启用防火墙 ===
sudo ufw --force enable
# 查看规则
sudo ufw status verbose
UFW 的默认入站拒绝策略意味着:除非你明确 allow,否则任何外部请求都到不了你的服务。这是一个「白名单」模型——对服务器来说是最安全的姿态。
2.2 IPv6 防火墙(如果你有 IPv6 地址)
很多新手只配置了 IPv4 防火墙,完全忽略了 IPv6 的暴露面。如果你的 VPS 分配了 IPv6 地址,攻击者可以通过 IPv6 绕过所有 IPv4 规则直接访问你的服务。
# 确保 UFW 同时管理 IPv6
sudo nano /etc/default/ufw
# 确认 IPV6=yes
# 重载配置
sudo ufw reload
2.3 iptables 视角下的等效规则(进阶理解)
如果你不用 UFW 而想直接操作 iptables,等效规则如下。建议初学者仍使用 UFW——直接写 iptables 的手误成本很高:
# iptables 等效规则(理解用,不要求执行)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 持久化(需安装 iptables-persistent)
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
💡 经验之谈:UFW 底层就是 iptables。当你 ufw allow 2222/tcp 时,它实际在 iptables 的 INPUT 链里加了一条 ACCEPT 规则。两者的最终效果完全一致,但 UFW 的命令行容错率高得多——至少你不太可能手滑把 OUTPUT 链设成 DROP 然后连不上任何外部服务。
三、Fail2ban:防暴力破解的自动化守卫
SSH 改端口和密钥认证已经挡住了 95% 的攻击尝试,但剩下的 5% 会带着更精准的字典、更慢的节奏来撞你的门。Fail2ban 的角色就是那个守夜人——盯着日志,发现某个 IP 在短时间内失败太多次,就临时把它关进 iptables 小黑屋。
3.1 安装与基础配置
# 安装
sudo apt update && sudo apt install fail2ban -y
# 复制默认配置为本地配置(不要直接改 jail.conf)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# 编辑本地配置
sudo nano /etc/fail2ban/jail.local
在 jail.local 中找到 [DEFAULT] 区块,配置全局参数:
[DEFAULT]
# 封禁时间:600 秒(10 分钟)
bantime = 600
# 10 分钟内,允许的最大失败次数
findtime = 600
maxretry = 5
# 封禁动作:使用 iptables 来 ban IP(兼容 IPv4/IPv6)
banaction = iptables-multiport
# 忽略本机
ignoreip = 127.0.0.1/8 ::1
# 如果某 IP 反复被封,可阶梯式增加时长(需要在 action.d 中配置,此处略)
# 你自己的 IP / 白名单 IP(可选)
# ignoreip = 127.0.0.1/8 ::1 你的固定IP/32
3.2 配置 SSH jail
Fail2ban 预置了 SSH 监狱(jail)。由于我们改了 SSH 端口,需要告诉它新端口号:
[sshd]
enabled = true
port = 2222 # 改为你的 SSH 端口
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3 # SSH 更激进——3 次失败就封
bantime = 3600 # 封 1 小时
3.3 启动与验证
# 重启服务
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
# 查看当前 jail 状态
sudo fail2ban-client status
# 查看 sshd jail 的具体封禁情况
sudo fail2ban-client status sshd
部署后几分钟内,你就可以用这条命令看到已被封禁的 IP 列表:
# 查看所有被 ban 的 IP
sudo fail2ban-client banned
对于一台公开暴露的 VPS,即便 SSH 端口设在了高位且启用了密钥认证,Fail2ban 依然不是多余的——它还能保护 Nginx、Apache 等服务免受 HTTP 暴力扫描的侵扰。只需在 jail.local 中为对应服务启用 jail 即可:
[nginx-http-auth]
enabled = true
port = http,https
maxretry = 3
bantime = 1800
如果你对安全有更高要求,Fail2ban 只是第一层自动化防御。后续可以考虑通过 Cloudflare Access 为服务加上企业级身份鉴权,具体可以阅读本站的深入教程:Cloudflare Access + Tunnel 双保险:为内网穿透增加企业级安全鉴权。
四、自动安全更新:unattended-upgrades
安全漏洞不是「发布那天」最危险,而是「CVE 公开后你没打补丁的那几天」最危险。自动化的安全更新是最后一道兜底防线——你的 VPS 不应该因为忘了跑 apt upgrade 而被已知漏洞击穿。
4.1 安装并启用
# 安装
sudo apt update && sudo apt install unattended-upgrades -y
# 启用自动更新(选择 "Yes")
sudo dpkg-reconfigure -plow unattended-upgrades
4.2 精细配置
编辑 /etc/apt/apt.conf.d/50unattended-upgrades,按需调整以下重点参数:
// 仅自动安装安全更新(推荐!)
// 取消注释 security 源,保持 updates/proposed/backports 注释掉
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
// "${distro_id}:${distro_codename}-updates"; // 非安全补丁,手动更新更稳
};
// 自动清理旧内核和软件包
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// 更新后自动重启(仅内核更新需要重启时)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00"; // 凌晨 3 点,业务低峰
// 发邮件通知(需要配置 mailx/sendmail)
// Unattended-Upgrade::Mail "admin@example.com";
另一项容易被忽略的配置是 /etc/apt/apt.conf.d/20auto-upgrades,它控制着 apt update 的频率:
APT::Periodic::Update-Package-Lists "1"; // 每天检查更新
APT::Periodic::Unattended-Upgrade "1"; // 每天执行自动升级
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7"; // 每 7 天清理一次
4.3 手动测试自动更新是否正常
# 模拟运行——不实际安装,只看会更新什么
sudo unattended-upgrades --dry-run --debug
至此,你的 VPS 在「漏洞公开 → 补丁可用 → 自动安装」这条链路上的延迟最多不超过 24 小时。对于绝大多数非关键基础设施场景,这个速度已经足够快。
五、进阶加固:禁用多余服务、普通用户与定期备份
5.1 禁用不必要的网络服务
每多一个监听端口的服务,就多一个攻击面。用下面的命令审视一下你的 VPS 到底在听哪些端口:
# 查看所有监听中的 TCP/UDP 端口
sudo ss -tulnp
常见可以关闭的服务和对应命令:
| 服务 | 监听端口 | 关闭命令 | 说明 |
|---|---|---|---|
| rpcbind | 111 | sudo systemctl disable --now rpcbind.socket rpcbind |
VPS 通常不需要 NFS |
| avahi-daemon | 5353 | sudo systemctl disable --now avahi-daemon |
零配置网络发现,服务器上不需要 |
| cups | 631 | sudo systemctl disable --now cups |
打印服务,VPS 更用不着 |
| smbd/nmbd | 139, 445 | sudo systemctl disable --now smbd nmbd |
Samba 文件共享,公网暴露极危险 |
5.2 sudo 的安全增强
即便你的普通用户已经是 sudo 组成员,也应该对 sudo 的行为做一些约束:
# 编辑 sudoers 文件(务必用 visudo,不要直接改)
sudo visudo
# 添加或取消注释以下行:
Defaults env_reset # 重置环境变量,防止注入
Defaults mail_badpass # 有人输错密码时通知 root
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults logfile="/var/log/sudo.log" # 记录所有 sudo 命令
Defaults insults # 每次输错密码嘲讽你(可选,但不妨碍加点幽默感)
5.3 限制共享内存访问
加固 /etc/fstab 以减少某些类型的本地提权攻击面:
# 编辑 fstab
sudo nano /etc/fstab
# 添加以下行(在已有的挂载点之外)
tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0
完成后执行 sudo mount -a 使配置生效。
5.4 定期备份策略
安全配置做得再好,也防不住硬盘故障、误删数据库、或者被勒索软件加密数据后的决策难题。备份是安全体系中的「终极保障」——它不是阻止攻击,而是确保攻击发生后你有能力恢复。
最简单的日常备份方案是用 rsync 把关键目录同步到另一台机器或云端存储。以下是一个最小化的每日备份脚本:
#!/bin/bash
# /usr/local/bin/daily-backup.sh
# 每天凌晨 2 点通过 cron 执行
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 备份关键目录
rsync -avz /etc/ "$BACKUP_DIR/etc/"
rsync -avz /var/log/ "$BACKUP_DIR/var-log/"
rsync -avz /home/youruser/ "$BACKUP_DIR/home/"
# 备份数据库(以 MySQL 为例)
# mysqldump -u root --all-databases > "$BACKUP_DIR/all-databases.sql"
# 压缩
tar -czf "$BACKUP_DIR.tar.gz" -C /backup "$(date +%Y%m%d)"
rm -rf "$BACKUP_DIR"
# 保留最近 7 天的备份
find /backup -name "*.tar.gz" -mtime +7 -delete
# 赋予执行权限并加入 cron
chmod +x /usr/local/bin/daily-backup.sh
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/daily-backup.sh") | crontab -
如果服务器承载的是正式上线项目,备份策略应该至少包含三种介质(本地、异地、离线)中的两种。对于自建站点,最低限度也建议把数据库和配置文件定期同步到对象存储(如 S3 兼容服务),并在重要操作前手动做一次快照。
说到服务器隐私保护,如果你的 VPS 上运行着多个 Web 服务或自建邮件系统,源站 IP 的暴露面也需要纳入考量。本站有一篇专门讲这个的文章:搭建 Postfix SMTP 中继隐藏源站 IP,保护服务器隐私——和本文的 SSH 加固配合使用,能形成从「端口→服务→IP」三层纵深防御。
六、适合安全实践的 VPS 推荐
本文中的所有安全配置,都需要一台拥有 root 权限的 VPS 来实践。如果你是第一次接触 Linux 服务器安全,强烈建议在低价 VPS 上先动手练一遍——配坏了可以随时销毁重建,成本不过几毛钱。
入门首选:Vultr
Vultr 是按小时计费的 KVM 虚拟化 VPS,最低配置 $2.5/月(仅 IPv6)或 $6/月(含 IPv4)。最大的优势是随时开随时删——练习安全配置时如果把自己锁在门外,在控制台一键销毁重建即可,完全不用担心浪费月租。全球 30+ 个数据中心,支持快照备份、自定义 ISO、VNC 控制台(救砖必备),所有功能都直接对新手友好。
性价比之选:RackNerd
RackNerd 以节日促销价格闻名,$10–$20/年就能拿到 1GB 内存以上的 KVM VPS,性价比极高。适合拿来做长期的安全沙盒、个人博客、或者监控节点。控制面板是标准的 SolusVM,支持重装系统和 VNC,安全配置翻车了也不用发愁。
进阶开发:DigitalOcean
DigitalOcean 的 Droplet 起价 $4/月,但它的周边生态比低价厂商丰富得多:内置的 Cloud Firewall 可以在 VPS 外层再套一层防火墙规则,等于硬件级的额外安全层;完善的 API 让你可以把安全配置脚本化、自动化部署。如果你是 DevOps 方向的进阶用户,DO 的整套工具链非常值得体验。
以上三家我都实际使用过一年以上,它们共有的特点是:KVM 虚拟化(意味着你能拿到真正的内核控制权,这对 iptables/Fail2ban 的正常运行至关重要)、VNC 控制台(安全配置失败的最后救命稻草)、以及快照/备份功能(做高风险操作前的安全网)。
七、常见问题 FAQ
Q1:改了 SSH 端口后连不上服务器了,怎么办?
这是最常见也最让人手心冒汗的场景。首先别慌——如果你没重启 sshd 服务,旧端口 22 仍然是通的,用旧端口连回去修正配置即可。如果已经重启了且新旧端口都连不上,唯一的出路是 VNC 控制台。几乎所有主流 VPS 厂商(包括上文推荐的三家)都提供控制台。通过厂商面板的 VNC 登录到服务器(不需要网络,相当于你直接坐在机房接上了显示器),然后修正 /etc/ssh/sshd_config 并 systemctl restart sshd。这也是为什么本文反复强调:改 SSH 配置后务必保留一个已认证的旧会话作为回退通道。
Q2:Fail2ban 把自己的 IP 封了,怎么解封?
如果你有两台服务器或者一个代理节点,SSH 到另一台机器再跳板进来,然后执行:
sudo fail2ban-client set sshd unbanip 你的被封IP
如果只有这一台机器且完全进不去了,同样走 VNC 控制台登录后执行上述命令。预防方法是提前把自己常用的固定 IP 加入 Fail2ban 的 ignoreip 白名单:ignoreip = 127.0.0.1/8 ::1 你的IP/32。
Q3:UFW 启用后 Docker 的端口还能访问吗?
这是一个高频踩雷点。Docker 默认会直接操作 iptables 的 FORWARD 链来暴露端口,而 UFW 主要管理 INPUT 链,两者并不冲突——但 Docker 的端口绕过 UFW 规则是「特性」而非 Bug。这意味着你 ufw deny 8080 之后,docker run -p 8080:8080 仍然会让端口对公网开放。解决方案有多种,包括在 Docker daemon 配置中禁用 iptables 操作、使用 ufw-docker 工具,或者改用 Docker Compose 的 expose 代替 ports。完整方案见本站专题文章:Docker 端口映射后防火墙失效?6 种方案彻底解决端口暴露问题。
Q4:密钥认证已经开了,为什么还要改 SSH 端口?不是多余吗?
密钥认证解决的是「暴力破解成功」的问题——攻击者猜不到你的密钥,确实破不了。但改端口解决的是另一个问题:日志噪音和资源消耗。默认 22 端口每天可能收到数千次扫描请求,虽然每次都被拒绝,但 Fail2ban 的日志解析、iptables 的规则匹配、SSH 守护进程的 fork 开销都是实打实的 CPU 和内存消耗。把端口改到高位后,扫描流量通常会下降 95% 以上,你的系统日志也会干净很多——真正有威胁的定向攻击才更容易被发现。
Q5:unattended-upgrades 会不会在我不在的时候把系统升崩了?
这种担忧非常合理。好在默认配置只启用 -security 源——这代表着来自发行版官方安全团队审核过的仅安全修复,不包含功能更新、大版本升级或内核主线更新。安全补丁通常只改几行代码,引入兼容性问题的概率极低。如果你特别谨慎,可以关闭 Automatic-Reboot,改为由你手动在合适的时间窗口执行重启。另外,所有自动更新的操作日志都会写入 /var/log/unattended-upgrades/,可以定期检查。
Q6:所有这些配置做完,我的 VPS 算「安全」了吗?
在互联网安全领域,没有人能承诺「绝对安全」——这是一条铁律。但完成本文的全部配置后,你的 VPS 的安全水平已经显著超过了 90% 的互联网公开服务器。你的攻击面从「SSH 22 端口 + 弱密码 + root 登录 + 全端口开放」收缩到了「SSH 高位端口 + 密钥认证 + 普通用户 + 仅必要端口开放 + 暴力破解自动封禁 + 安全补丁自动更新」。接下来要做的,就是把安全意识和实操习惯日常化:定期看日志、不用时关端口、不在服务器上装来路不明的脚本、保持软件栈的更新节奏——安全不是终点,是持续的过程。
原创文章,作者:kp51,如若转载,请注明出处:https://www.kepu51.com/instant-messaging/837.html
