VPS 安全加固实战指南 2026:从零到堡垒级服务器防护
🛡️ 一台刚买回来的 VPS,就像一扇没上锁的门。 默认配置下,SSH 端口开放、密码登录允许、root 直登启用、防火墙未配置——攻击者只需几分钟暴力破解就能拿到 root 权限。本文带你从零开始,系统完成 10 大安全加固模块,将一台裸奔的 VPS 变成堡垒级服务器。
本文涵盖 10 大安全模块:
- ✅ SSH 安全加固(密钥登录 + 端口修改 + 禁用密码)
- ✅ 防火墙配置(UFW / nftables 生产规则)
- ✅ Fail2ban 入侵防御(SSH + Nginx + 多 Jail 配置)
- ✅ 内核参数加固(sysctl 安全调优)
- ✅ 用户与权限管理(sudo + 最小权限原则)
- ✅ 自动安全更新(unattended-upgrades)
- ✅ Docker 容器安全(只读文件系统 + 资源限制 + 网络隔离)
- ✅ 文件完整性监控(AIDE)与 Rootkit 检测(rkhunter)
- ✅ 日志告警与 DDoS 缓解
- ✅ 应急响应流程 + 30 条上线检查清单
一、VPS 安全威胁全景
在动手加固之前,先了解你的 VPS 面临哪些威胁:
1.1 常见攻击类型
| 攻击类型 | 危险等级 | 发生频率 | 典型手法 | 目标 |
|---|---|---|---|---|
| SSH 暴力破解 | ⭐⭐⭐⭐ | 极高 | 字典攻击、撞库、弱密码扫描 | root 权限 |
| 挖矿木马 | ⭐⭐⭐⭐⭐ | 高 | 利用漏洞植入挖矿程序 | CPU/GPU 资源 |
| 勒索软件 | ⭐⭐⭐⭐⭐ | 中 | 加密文件勒索赎金 | 数据 |
| DDoS 攻击 | ⭐⭐⭐⭐ | 中 | 大流量洪水攻击 | 服务可用性 |
| Web 应用攻击 | ⭐⭐⭐⭐ | 高 | SQL 注入、XSS、命令注入 | 数据库/权限 |
| 后门植入 | ⭐⭐⭐⭐⭐ | 中 | Webshell、SSH 后门、计划任务 | 持久化控制 |
| CVE 漏洞利用 | ⭐⭐⭐⭐⭐ | 中 | 利用已知未修补漏洞 | 系统/应用权限 |
1.2 攻击者的典型入侵路径
扫描开放端口 (22/80/443/3306/6379)
↓
尝试 SSH 暴力破解 ← 90% 攻击从这里开始
↓
成功 → 植入挖矿程序 / 后门 / 横向移动
失败 → 转向 Web 应用漏洞
↓
利用未修补 CVE (Nginx/Docker/Redis 等)
↓
获取 shell → 提权 → 持久化
↓
清除日志 / 植入定时任务 / 创建后门用户1.3 安全加固的核心理念
- 最小权限原则 — 只开放必要的端口,只授予必要的权限
- 纵深防御 — 多层防护,不依赖单一手段
- 自动响应 — Fail2ban + 告警,不要靠人工盯日志
- 持续更新 — 安全不是一次性工作,漏洞每天都在发现
- 备份为王 — 再好的防护也可能被突破,备份是最后防线
💡 本文是 VPS 安全总纲,站内已有多篇专题文章深入讲解各个模块。本文会引用它们作为延伸阅读,确保你既有全局视角又能深入细节。
二、SSH 安全加固
SSH 是攻击者的首要目标,也是我们加固的第一道防线。
2.1 密钥登录:彻底告别密码
# 1. 在本地机器生成 ED25519 密钥对(比 RSA 更安全更短)
ssh-keygen -t ed25519 -C "your-email@example.com" -f ~/.ssh/vps_key
# 2. 将公钥上传到 VPS
ssh-copy-id -i ~/.ssh/vps_key.pub root@your-vps-ip
# 3. 测试密钥登录(不要关闭当前终端!)
ssh -i ~/.ssh/vps_key root@your-vps-ip⚠️ 关键:在确认密钥登录成功之前,绝对不要禁用密码登录。否则你会被锁在外面。
2.2 修改 SSH 配置
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config修改以下关键参数:
# ===== SSH 安全加固配置 =====
# 修改默认端口(避免自动扫描,选 10000-65535 之间的端口)
Port 58291
# 禁用密码登录(仅允许密钥)
PasswordAuthentication no
# 禁用空密码
PermitEmptyPasswords no
# 禁用 root 直登(用普通用户 + sudo)
PermitRootLogin no
# 仅允许指定用户登录
AllowUsers your-username
# 登录超时时间(秒)
LoginGraceTime 30
# 最大认证尝试次数
MaxAuthTries 3
# 空闲超时自动断开(秒)
ClientAliveInterval 300
ClientAliveCountMax 2
# 禁用 X11 转发(如不需要)
X11Forwarding no
# 禁用端口转发(如不需要)
AllowTcpForwarding no
# 使用强加密算法
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512# 重启 SSH 服务
sudo systemctl restart sshd
# 验证配置语法(不会重启服务)
sudo sshd -t2.3 SSH 2FA(可选但推荐)
对于高安全要求的场景,可以启用 Google Authenticator 双因子认证:
# 安装 Google Authenticator PAM 模块
sudo apt install -y libpam-google-authenticator
# 为当前用户生成 TOTP 密钥
google-authenticator
# 选择 yes → yes → no → yes → yes
# 配置 PAM
echo "auth required pam_google_authenticator.so" | sudo tee -a /etc/pam.d/sshd
# 在 sshd_config 中启用
sudo sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
echo "AuthenticationMethods publickey,keyboard-interactive" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart sshd📖 延伸阅读:SSH 密钥配置详解 | VPS 安全进阶:超越 Fail2ban
三、防火墙配置
防火墙是服务器的网络防线,只允许必要的流量进出。
3.1 UFW 防火墙(Ubuntu/Debian 推荐)
# 安装 UFW
sudo apt install -y ufw
# ===== 配置默认策略 =====
sudo ufw default deny incoming
sudo ufw default allow outgoing
# ===== 开放必要端口 =====
# SSH(注意:如果你修改了 SSH 端口,这里要对应修改)
sudo ufw allow 58291/tcp comment 'SSH'
# HTTP / HTTPS
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# 如果你运行 3X-UI 面板
sudo ufw allow 2053/tcp comment '3X-UI Panel'
# 如果你运行 WireGuard
sudo ufw allow 51820/udp comment 'WireGuard'
# ===== 限制 SSH 连接频率 =====
# 每个 IP 每 30 秒最多 6 次连接
sudo ufw limit 58291/tcp
# 启用防火墙
sudo ufw enable
# 查看状态
sudo ufw status verbose3.2 UFW 高级配置
# 仅允许特定 IP 段访问管理端口
sudo ufw allow from 192.168.1.0/24 to any port 58291 proto tcp
# 拒绝特定 IP
sudo ufw deny from 203.0.113.66 to any
# 速率限制(防止暴力连接)
sudo ufw limit 58291/tcp
# 记录被拒绝的连接
sudo ufw logging medium
# 查看日志
sudo tail -f /var/log/ufw.log3.3 nftables 配置(Debian 12+ / CentOS 推荐)
nftables 是 iptables 的继任者,语法更简洁,性能更好:
# 安装
sudo apt install -y nftables
# 创建配置文件
sudo nano /etc/nftables.conf#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 允许本地回环
iif "lo" accept
# 允许已建立的连接
ct state established,related accept
# 丢弃无效连接
ct state invalid drop
# ICMP 限速(防止 ping 洪水)
icmp type echo-request limit rate 5/second accept
ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 5/second accept
# SSH 限速(每分钟最多 6 次新连接)
tcp dport 58291 ct state new limit rate 6/minute burst 3 packets accept
# HTTP / HTTPS
tcp dport { 80, 443 } accept
# WireGuard
udp dport 51820 accept
# 记录被拒绝的流量
limit rate 10/minute log prefix "nftables-dropped: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}# 应用规则
sudo nft -f /etc/nftables.conf
# 开机自启
sudo systemctl enable nftables
# 查看规则
sudo nft list ruleset📖 延伸阅读:Linux 防火墙端口开放完全指南 | iptables 防火墙指南
四、Fail2ban 入侵防御
Fail2ban 通过监控日志自动封禁恶意 IP,是 SSH 防爆破的标配工具。
4.1 安装与基础配置
sudo apt install -y fail2ban
# Fail2ban 的配置不要直接修改 jail.conf,而是创建 jail.local
sudo nano /etc/fail2ban/jail.local# ===== Fail2ban 全局配置 =====
[DEFAULT]
# 封禁时间(1 小时)
bantime = 3600
# 查找时间窗口(10 分钟内)
findtime = 600
# 最大失败次数
maxretry = 3
# 封禁动作(使用 UFW 或 iptables)
banaction = ufw
# 忽略的 IP(你的管理 IP)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# 邮件通知(可选)
# destemail = admin@y-m.top
# sender = fail2ban@y-m.top
# action = %(action_mwl)s
# ===== SSH 防护 =====
[sshd]
enabled = true
port = 58291
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# 重复违规者加重处罚
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
# ===== Nginx 防护 =====
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 7200
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 7200
# ===== Nginx 401/403 防护 =====
[nginx-noscript]
enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
# ===== 防止端口扫描 =====
[port-scan]
enabled = true
filter = port-scan
logpath = /var/log/ufw.log
maxretry = 5
bantime = 86400
action = ufw# 创建端口扫描过滤器
sudo nano /etc/fail2ban/filter.d/port-scan.conf[Definition]
failregex = .*block.*from.*SRC=.*
ignoreregex =# 重启 Fail2ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
# 查看状态
sudo fail2ban-client status
sudo fail2ban-client status sshd
# 手动解封 IP
sudo fail2ban-client set sshd unbanip 203.0.113.664.2 Fail2ban 进阶:递增封禁
上面的配置中已经启用了 bantime.increment,效果如下:
| 第 N 次被封 | 封禁时间 |
|---|---|
| 第 1 次 | 1 小时 |
| 第 2 次 | 2 小时 |
| 第 3 次 | 4 小时 |
| 第 4 次 | 8 小时 |
| ... | ... |
| 上限 | 7 天 |
📖 延伸阅读:Fail2ban 防暴力破解配置完全指南
五、内核参数加固
Linux 内核默认配置以兼容性为主,不少参数对安全并不友好。通过 sysctl 调优可以显著提升系统安全性。
5.1 安全加固 sysctl 配置
sudo nano /etc/sysctl.d/99-security.conf# ===== 网络安全加固 =====
# 开启 SYN Cookies(防 SYN Flood)
net.ipv4.tcp_syncookies = 1
# 增加 SYN 队列长度
net.ipv4.tcp_max_syn_backlog = 4096
# SYN+ACK 重试次数(减少半连接占用)
net.ipv4.tcp_synack_retries = 2
# 开启反向路径过滤(防 IP 欺骗)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 禁用 ICMP 重定向(防中间人攻击)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# 禁用源路由(防 IP 欺骗)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# 禁用 ICMP 广播响应(防 Smurf 攻击)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 记录可疑数据包( Martian Packets)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# 忽略错误的 ICMP 请求
net.ipv4.icmp_ignore_bogus_error_responses = 1
# TCP Keepalive 调优(更快发现死连接)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
# ===== 连接数限制 =====
# 端口范围(可用于出站连接的临时端口)
net.ipv4.ip_local_port_range = 10000 65535
# 连接跟踪表大小(内存够的话调大)
net.netfilter.nf_conntrack_max = 131072
net.netfilter.nf_conntrack_timeout_established = 3600
# TIME_WAIT 状态优化
net.ipv4.tcp_max_tw_buckets = 8192
net.ipv4.tcp_tw_reuse = 1
# ===== 内核安全 =====
# 禁用 IPv4 转发(如果不是路由器/VPN)
# 注意:如果你运行 WireGuard/3X-UI 需要转发,设为 1
# net.ipv4.ip_forward = 0
# 禁用 IPv6 转发(同上)
# net.ipv6.conf.all.forwarding = 0
# 地址空间布局随机化(防缓冲区溢出)
kernel.randomize_va_space = 2
# 限制 dmesg 访问(只有 root 能看内核日志)
kernel.dmesg_restrict = 1
# 限制 kptr(内核指针)暴露
kernel.kptr_restrict = 2
# 限制内核性能事件
kernel.perf_event_paranoid = 3
# 限制 BPF(防 eBPF 提权)
kernel.unprivileged_bpf_disabled = 1
# 禁用用户命名空间(防容器逃逸,注意 Docker 需要)
# kernel.unprivileged_userns_clone = 0
# 限制核心转储(防止信息泄露)
fs.suid_dumpable = 0
# 符号链接保护(防 TOCTOU 攻击)
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
# FIFO 保护
fs.protected_fifos = 2
fs.protected_regular = 2# 应用配置
sudo sysctl -p /etc/sysctl.d/99-security.conf
# 验证
sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl kernel.randomize_va_space5.2 内核参数说明表
| 参数 | 值 | 作用 |
|---|---|---|
tcp_syncookies | 1 | 防 SYN Flood 攻击 |
rp_filter | 1 | 反向路径过滤,防 IP 欺骗 |
accept_redirects | 0 | 禁用 ICMP 重定向 |
accept_source_route | 0 | 禁用源路由 |
icmp_echo_ignore_broadcasts | 1 | 防 Smurf 攻击 |
log_martians | 1 | 记录可疑数据包 |
randomize_va_space | 2 | ASLR 地址随机化 |
dmesg_restrict | 1 | 限制 dmesg 访问 |
kptr_restrict | 2 | 隐藏内核指针 |
suid_dumpable | 0 | 禁用核心转储 |
protected_symlinks | 1 | 符号链接保护 |
⚠️ 注意:如果你运行 WireGuard 或 3X-UI 代理面板,需要保持
net.ipv4.ip_forward = 1。具体配置请参考 WireGuard 自建 VPN 完整教程 和 3X-UI 面板自建代理教程。
六、用户与权限管理
6.1 创建非 root 管理用户
永远不要用 root 直接操作。创建一个有 sudo 权限的普通用户:
# 创建新用户
adduser deploy
# 加入 sudo 组
usermod -aG sudo deploy
# 验证 sudo 权限
su - deploy
sudo whoami # 应返回 root6.2 sudo 安全配置
sudo visudo -f /etc/sudoers.d/security# ===== sudo 安全配置 =====
# 要求 sudo 时输入密码(默认行为)
Defaults requiretty
Defaults !visiblepw
# 密码尝试 3 次后退出
Defaults passwd_tries = 3
# 超时时间 5 分钟
Defaults timestamp_timeout = 5
# 记录 sudo 日志
Defaults logfile = "/var/log/sudo.log"
Defaults log_input, log_output
# 允许 deploy 用户执行所有命令
deploy ALL=(ALL) ALL
# 如果有只需要特定命令的用户,用最小权限
# webadmin ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx6.3 禁用不必要的系统账户
# 查看所有用户的 shell
cat /etc/passwd | grep -E "(/bin/bash|/bin/sh)$"
# 禁用不需要登录的系统账户
sudo usermod -s /usr/sbin/nologin sync
sudo usermod -s /usr/sbin/nologin news
sudo usermod -s /usr/sbin/nologin uucp
sudo usermod -s /usr/sbin/nologin operator
sudo usermod -s /usr/sbin/nologin games
# 锁定空密码账户
sudo passwd -l nobody6.4 文件权限加固
# 关键系统文件权限
sudo chmod 644 /etc/passwd
sudo chmod 640 /etc/shadow
sudo chmod 644 /etc/group
sudo chmod 640 /etc/gshadow
# SSH 目录权限
sudo chmod 700 ~/.ssh
sudo chmod 600 ~/.ssh/authorized_keys
# sudoers 文件权限
sudo chmod 440 /etc/sudoers
sudo chmod 440 /etc/sudoers.d/*七、自动安全更新
保持系统更新是安全的基础。配置自动安装安全补丁,不需要手动干预。
7.1 配置 unattended-upgrades
# 安装
sudo apt install -y unattended-upgrades apt-listchanges
# 自动配置
sudo dpkg-reconfigure -plow unattended-upgrades# 编辑配置文件
sudo nano /etc/apt/apt.conf.d/50unattended-upgradesUnattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
# 自动重启(如果更新需要)
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
# 邮件通知(可选)
// Unattended-Upgrade::Mail "admin@y-m.top";
// Unattended-Upgrade::MailReport "on-change";
# 移除不再需要的包
Unattended-Upgrade::Remove-Unused-Dependencies "true";
# 移除不再需要的内核
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";# 编辑自动更新周期
sudo nano /etc/apt/apt.conf.d/20auto-upgradesAPT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Download-Upgradeable-Packages "1";# 验证配置(试运行)
sudo unattended-upgrade --dry-run --verbose
# 手动触发一次
sudo unattended-upgrade -v7.2 需要排除的包
某些包不希望自动更新(如自定义内核、特定版本锁定):
# 在 50unattended-upgrades 中添加
Unattended-Upgrade::Package-Blacklist {
"nginx";
"docker-ce";
"redis-server";
};💡 建议:对于生产环境的关键服务(如数据库),建议关闭自动更新,改用 定时手动更新 + 更新前快照 的策略。
八、Docker 容器安全
如果你在 VPS 上跑 Docker(很多人都是),容器安全同样重要。
8.1 Docker 守护进程加固
sudo nano /etc/docker/daemon.json{
"icc": false,
"no-new-privileges": true,
"userland-proxy": false,
"live-restore": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65536,
"Soft": 1024
}
},
"userns-remap": "default"
}sudo systemctl restart docker8.2 容器安全最佳实践
# 1. 不要用 --privileged 运行容器
# 错误:docker run --privileged nginx
# 正确:docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx
# 2. 只读文件系统 + 临时目录
docker run -d \
--name myapp \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--memory="512m" \
--cpus="1.0" \
--pids-limit=100 \
--security-opt no-new-privileges \
-p 80:80 \
nginx:alpine
# 3. 使用非 root 用户运行
docker run -d \
--user 1000:1000 \
myapp:latest
# 4. 限制网络访问(仅允许出站到指定地址)
docker network create --internal restricted-net
docker run -d --network restricted-net myapp8.3 Docker 安全检查脚本
#!/bin/bash
# 文件名: docker-security-check.sh
echo "===== Docker 安全检查 ====="
# 检查是否有 --privileged 容器
echo "1. 检查特权容器..."
PRIVILEGED=$(docker ps -q | xargs docker inspect --format '{{.Name}} Privileged={{.HostConfig.Privileged}}' | grep "Privileged=true" || echo "无")
echo " $PRIVILEGED"
# 检查是否有容器以 root 运行
echo "2. 检查 root 运行的容器..."
ROOT_CONTAINERS=$(docker ps -q | xargs docker inspect --format '{{.Name}} User={{.Config.User}}' | grep 'User=$' || echo "无")
echo " $ROOT_CONTAINERS"
# 检查是否有容器没有资源限制
echo "3. 检查无资源限制的容器..."
NO_LIMIT=$(docker ps -q | xargs docker inspect --format '{{.Name}} Memory={{.HostConfig.Memory}} CPUs={{.HostConfig.NanoCpus}}' | grep 'Memory=0 CPUs=0' || echo "无")
echo " $NO_LIMIT"
# 检查 Docker 版本
echo "4. Docker 版本: $(docker version --format '{{.Server.Version}}')"
# 检查 daemon.json 配置
echo "5. 安全配置检查..."
if [ -f /etc/docker/daemon.json ]; then
echo " daemon.json 存在"
grep -q "no-new-privileges" /etc/docker/daemon.json && echo " ✓ no-new-privileges 已启用" || echo " ✗ no-new-privileges 未启用"
grep -q "userns-remap" /etc/docker/daemon.json && echo " ✓ userns-remap 已启用" || echo " ✗ userns-remap 未启用"
else
echo " ✗ daemon.json 不存在"
fi8.4 Docker Compose 安全配置示例
# docker-compose.security.yml
services:
webapp:
image: myapp:latest
read_only: true
tmpfs:
- /tmp
- /run
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
memory: 256M
pids_limit: 100
user: "1000:1000"
networks:
- frontend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
networks:
frontend:
driver: bridge
internal: false📖 延伸阅读:Docker 多阶段构建优化 | Immich 私有云部署
九、文件完整性监控与 Rootkit 检测
9.1 AIDE — 文件完整性监控
AIDE(Advanced Intrusion Detection Environment)定期扫描关键文件,发现任何篡改立即告警。
# 安装
sudo apt install -y aide
# 初始化数据库(首次运行会扫描所有文件,耗时较长)
sudo aideinit
# 将初始化数据库设为基准
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# 手动执行检查
sudo aide --check
# 更新基准(当你主动修改了系统文件后)
sudo aide --update
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db配置定时检查脚本:
sudo nano /etc/cron.daily/aide-check#!/bin/bash
# AIDE 每日完整性检查
REPORT=$(sudo aide --check 2>&1)
if echo "$REPORT" | grep -q "All entries match"; then
echo "[$(date)] AIDE 检查通过,文件完整性正常" >> /var/log/aide-check.log
else
echo "[$(date)] ⚠️ AIDE 检测到文件变更!" >> /var/log/aide-check.log
echo "$REPORT" >> /var/log/aide-check.log
# 发送告警邮件(可选)
echo "$REPORT" | mail -s "[ALERT] AIDE 文件完整性检查异常" admin@y-m.top
# Telegram 告警(可选)
# curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
# -d chat_id="<CHAT_ID>" \
# -d text="⚠️ AIDE 检测到文件变更,请检查 /var/log/aide-check.log"
fisudo chmod +x /etc/cron.daily/aide-check9.2 rkhunter — Rootkit 检测
# 安装
sudo apt install -y rkhunter
# 更新数据库
sudo rkhunter --update
sudo rkhunter --propupd
# 执行检查
sudo rkhunter --check --sk
# 查看报告
sudo cat /var/log/rkhunter.log | grep -E "Warning|Rootkit"配置每日自动扫描:
sudo nano /etc/cron.daily/rkhunter-check#!/bin/bash
# rkhunter 每日 Rootkit 扫描
REPORT=$(sudo rkhunter --check --sk --report-warnings-only 2>&1)
if [ -n "$REPORT" ]; then
echo "[$(date)] ⚠️ rkhunter 发现可疑项:" >> /var/log/rkhunter-check.log
echo "$REPORT" >> /var/log/rkhunter-check.log
# Telegram 告警
# curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
# -d chat_id="<CHAT_ID>" \
# -d text="⚠️ rkhunter 发现可疑项,请检查日志"
else
echo "[$(date)] rkhunter 扫描通过,未发现 Rootkit" >> /var/log/rkhunter-check.log
fisudo chmod +x /etc/cron.daily/rkhunter-check📖 延伸阅读:Linux 服务器入侵检测与安全审计实战
十、日志告警与 DDoS 缓解
10.1 日志监控告警
# 安装 logwatch(每日安全摘要邮件)
sudo apt install -y logwatch
# 配置
sudo nano /etc/logwatch/conf/logwatch.confMailTo = admin@y-m.top
MailFrom = logwatch@y-m.top
Range = yesterday
Detail = High
Service = All# 测试发送
sudo logwatch --output mail --range yesterday
# 它会每天自动运行(已集成到 /etc/cron.daily/)10.2 SSH 登录告警
在用户登录时发送通知:
sudo nano /etc/ssh/sshrc#!/bin/bash
# SSH 登录通知
# 获取登录信息
IP=$(echo "$SSH_CONNECTION" | awk '{print $1}')
TIME=$(date "+%Y-%m-%d %H:%M:%S")
USER=$(whoami)
HOST=$(hostname)
# Telegram 通知
curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id="<CHAT_ID>" \
-d text="🔐 SSH 登录通知
服务器: $HOST
用户: $USER
IP: $IP
时间: $TIME"
# 邮件通知
echo "SSH 登录: $USER from $IP at $TIME on $HOST" | mail -s "[SSH] 登录通知" admin@y-m.topsudo chmod +x /etc/ssh/sshrc10.3 DDoS 缓解策略
| 策略 | 适用场景 | 效果 | 实施难度 |
|---|---|---|---|
| UFW 速率限制 | 小规模连接洪水 | 中 | 低 |
| Fail2ban | 应用层 CC 攻击 | 中 | 低 |
| Cloudflare CDN | L3/L4/L7 DDoS | 高 | 低 |
| iptables/nftables 限速 | SYN Flood | 中 | 中 |
| BBR 拥塞控制 | 带宽耗尽型攻击 | 中 | 低 |
10.3.1 开启 BBR 拥塞控制
echo "net.core.default_qdisc = fq" | sudo tee -a /etc/sysctl.d/99-bbr.conf
echo "net.ipv4.tcp_congestion_control = bbr" | sudo tee -a /etc/sysctl.d/99-bbr.conf
sudo sysctl -p /etc/sysctl.d/99-bbr.conf
# 验证
sysctl net.ipv4.tcp_congestion_control
# 应返回: net.ipv4.tcp_congestion_control = bbr10.3.2 iptables SYN Flood 防护
# 限制每秒 SYN 包数量
sudo iptables -A INPUT -p tcp --syn -m limit --limit 20/s --limit-burst 40 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP
# 限制每 IP 并发连接数
sudo iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j DROP
# 保存规则
sudo netfilter-persistent save10.3.3 Cloudflare 防护(推荐)
对于 Web 服务,最有效的 DDoS 防护是套一层 Cloudflare:
- 域名 DNS 迁移到 Cloudflare
- 开启 Proxy(橙色云朵)
- SSL/TLS 设为 Full (Strict)
- 开启 Always Use HTTPS
- 安全级别设为 High
- 开启 Bot Fight Mode
- 配置 WAF 规则拦截恶意请求
📖 延伸阅读:Cloudflare Tunnel 内网穿透 | Cloudflare WARP 中转
十一、应急响应:被黑了怎么办
即使做了所有加固,也可能被突破。关键是如何快速响应。
11.1 应急响应流程
发现异常 → 隔离服务器 → 保留证据 → 排查范围 → 清除威胁 → 恢复服务 → 复盘总结11.2 第一步:隔离
# 立即断网(通过云平台控制台操作,不要用 SSH 断网,否则自己也连不上)
# 或通过防火墙仅允许自己的 IP
sudo ufw deny incoming
sudo ufw allow from YOUR_IP to any port 58291
# 禁用所有非必要服务
sudo systemctl stop nginx
sudo systemctl stop docker11.3 第二步:排查
# 1. 检查当前登录用户
w
who -a
last -20
# 2. 检查可疑进程
ps aux | grep -E "(miner|xmr|kworker.*\s$|python.*http)"
top -c
# 3. 检查网络连接
ss -tunlp
ss -tunp | grep ESTABLISHED
# 4. 检查计划任务(挖矿木马最喜欢藏这里)
crontab -l
sudo crontab -l
ls -la /etc/cron.d/
ls -la /var/spool/cron/
cat /etc/crontab
# 5. 检查异常文件
find /tmp /var/tmp /dev/shm -type f -executable
find / -name "*.sh" -newer /etc/passwd -type f 2>/dev/null
# 6. 检查 SSH 后门
cat ~/.ssh/authorized_keys
grep -r "PermitRootLogin\|PasswordAuthentication" /etc/ssh/
# 7. 检查新增用户
grep -v "nologin\|false" /etc/passwd
# 8. 检查 SUID 文件(提权后门)
find / -perm -4000 -type f 2>/dev/null
# 9. 检查异常 systemd 服务
systemctl list-units --type=service --state=running | grep -v "ssh\|docker\|nginx\|systemd"
# 10. 运行 rkhunter
sudo rkhunter --check --sk11.4 第三步:清除与恢复
# 杀死可疑进程
sudo kill -9 $(pgrep -f "可疑进程名")
# 删除恶意文件
sudo rm -f /tmp/可疑文件
sudo rm -f /var/tmp/可疑文件
# 清除恶意计划任务
crontab -r # 清空当前用户 crontab
sudo rm -f /etc/cron.d/恶意文件
# 删除后门 SSH 密钥
nano ~/.ssh/authorized_keys # 手动删除不认识的密钥
# 重置所有密码
passwd
sudo passwd root
# 更新所有软件
sudo apt update && sudo apt upgrade -y11.5 最终建议:重装系统
如果确认被入侵,最安全的做法是重装系统:
- 备份关键数据(只备份应用数据,不备份系统配置)
- 云平台重装系统
- 按本文流程重新加固
- 恢复数据(逐个检查后再恢复)
- 更新所有密钥和密码
💡 记住:你永远无法 100% 确定清除了所有后门。重装是唯一可靠的选择。
📖 延伸阅读:VPS 数据备份与恢复完整指南 | rsync 增量备份指南
十二、安全检查清单:上线前 30 条
将以下清单逐条检查后再上线服务:
SSH 安全
防火墙
入侵防御
内核加固
用户与权限
自动更新
完整性监控
容器安全
备份
十三、一键加固脚本
将以上核心步骤整合为一键脚本,方便新 VPS 快速加固:
#!/bin/bash
# ============================================================
# VPS 一键安全加固脚本 v2026
# 适用系统: Debian 12+ / Ubuntu 22.04+
# 作者: y-m.top
# ============================================================
set -e
# ===== 配置区(按需修改)=====
SSH_PORT="58291"
NEW_USER="deploy"
SSH_KEY="" # 填入你的公钥(ssh-ed25519 AAAA... email)
# ===== 颜色输出 =====
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
info() { echo -e "${GREEN}[✓]${NC} $1"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
error() { echo -e "${RED}[✗]${NC} $1"; }
# ===== 1. 系统更新 =====
echo "===== 1/8 系统更新 ====="
apt update && apt upgrade -y -o Dpkg::Options::="--force-confold"
info "系统已更新"
# ===== 2. 创建管理用户 =====
echo "===== 2/8 创建管理用户 ====="
if ! id "$NEW_USER" &>/dev/null; then
adduser --gecos "" --disabled-password "$NEW_USER"
usermod -aG sudo "$NEW_USER"
info "用户 $NEW_USER 已创建并加入 sudo 组"
else
warn "用户 $NEW_USER 已存在"
fi
# ===== 3. SSH 加固 =====
echo "===== 3/8 SSH 加固 ====="
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%s)
# 设置 SSH 密钥
if [ -n "$SSH_KEY" ]; then
mkdir -p /home/$NEW_USER/.ssh
echo "$SSH_KEY" > /home/$NEW_USER/.ssh/authorized_keys
chmod 700 /home/$NEW_USER/.ssh
chmod 600 /home/$NEW_USER/.ssh/authorized_keys
chown -R $NEW_USER:$NEW_USER /home/$NEW_USER/.ssh
info "SSH 公钥已添加"
fi
# 修改 SSH 配置
sed -i "s/^#Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sed -i "s/^Port 22/Port $SSH_PORT/" /etc/ssh/sshd_config
sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#PermitEmptyPasswords.*/PermitEmptyPasswords no/' /etc/ssh/sshd_config
sed -i 's/^#MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
sed -i 's/^#LoginGraceTime.*/LoginGraceTime 30/' /etc/ssh/sshd_config
# 添加 AllowUsers
if ! grep -q "^AllowUsers" /etc/ssh/sshd_config; then
echo "AllowUsers $NEW_USER" >> /etc/ssh/sshd_config
fi
info "SSH 配置已加固(端口: $SSH_PORT)"
# ===== 4. 防火墙 =====
echo "===== 4/8 防火墙配置 ====="
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw limit $SSH_PORT/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
echo "y" | ufw enable
info "UFW 防火墙已启用"
# ===== 5. Fail2ban =====
echo "===== 5/8 Fail2ban 配置 ====="
apt install -y fail2ban
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw
ignoreip = 127.0.0.1/8 ::1
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
[sshd]
enabled = true
port = 58291
maxretry = 3
EOF
# 修正 SSH 端口
sed -i "s/port = 58291/port = $SSH_PORT/" /etc/fail2ban/jail.local
systemctl restart fail2ban
systemctl enable fail2ban
info "Fail2ban 已配置"
# ===== 6. 内核加固 =====
echo "===== 6/8 内核参数加固 ====="
cat > /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
kernel.perf_event_paranoid = 3
kernel.unprivileged_bpf_disabled = 1
fs.suid_dumpable = 0
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p /etc/sysctl.d/99-security.conf
info "内核安全参数已应用"
# ===== 7. 自动更新 =====
echo "===== 7/8 自动安全更新 ====="
apt install -y unattended-upgrades
cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
EOF
info "自动安全更新已启用"
# ===== 8. 完整性监控 =====
echo "===== 8/8 安装 AIDE + rkhunter ====="
apt install -y aide rkhunter
rkhunter --update
rkhunter --propupd
info "AIDE 和 rkhunter 已安装(需手动初始化 AIDE 数据库)"
# ===== 完成 =====
echo ""
echo "=========================================="
echo -e "${GREEN}✓ VPS 安全加固完成!${NC}"
echo "=========================================="
echo ""
echo "重要提醒:"
echo "1. 请先用新端口和密钥测试 SSH 连接,确认能连上后再关闭当前终端"
echo " ssh -p $SSH_PORT $NEW_USER@your-vps-ip"
echo "2. 手动初始化 AIDE 数据库:"
echo " sudo aideinit && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db"
echo "3. 建议安装 Docker 后配置 daemon.json 加固"
echo "4. 完整检查清单请参考文章第十二节"
echo ""
warn "警告:请先验证 SSH 密钥登录成功后再关闭当前终端!"将脚本保存为 vps-hardening.sh,修改配置区参数后执行:
chmod +x vps-hardening.sh
sudo ./vps-hardening.shFAQ:常见问题
Q1:加固后 SSH 连不上了怎么办?
先用云平台的 VNC 控制台登录,然后检查:
- SSH 端口是否正确:
grep "^Port" /etc/ssh/sshd_config - 密钥是否配置正确:
cat ~/.ssh/authorized_keys - 防火墙是否放行:
ufw status - Fail2ban 是否误封:
fail2ban-client status sshd - SSH 服务是否运行:
systemctl status sshd
如果确认配置正确但仍无法连接,临时恢复备份:
cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config
systemctl restart sshdQ2:Fail2ban 把自己的 IP 封了怎么办?
# 查看被封的 IP
sudo fail2ban-client status sshd
# 解封 IP
sudo fail2ban-client set sshd unbanip YOUR_IP
# 将自己的 IP 加入白名单
sudo nano /etc/fail2ban/jail.local
# 修改 ignoreip = 127.0.0.1/8 ::1 YOUR_IP
sudo systemctl restart fail2banQ3:unattended-upgrades 会自动重启服务器吗?
只有在配置中开启了 Automatic-Reboot "true" 时才会。关键服务(如数据库)建议关闭自动重启,改用手动更新:
# 在 50unattended-upgrades 中设置
Unattended-Upgrade::Automatic-Reboot "false";Q4:Docker 容器用了 --read-only 后无法写入怎么办?
挂载可写卷到需要写入的目录:
docker run --read-only \
-v /data/app/logs:/app/logs \
-v /data/app/uploads:/app/uploads \
--tmpfs /tmp \
myappQ5:AIDE 报告大量文件变更,正常吗?
首次运行 AIDE 后如果安装了新软件或修改了配置,会产生大量变更报告。处理方式:
- 确认变更是你自己操作引起的
- 更新 AIDE 基准:
sudo aide --update && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db - 如果变更不是你引起的,立即排查入侵
Q6:如何判断服务器是否被入侵?
快速检查清单:
# 1. 检查异常进程(特别是高 CPU 占用)
top -c -o %CPU | head -20
# 2. 检查异常网络连接
ss -tunp | grep ESTABLISHED
# 3. 检查计划任务
crontab -l && sudo crontab -l && ls /etc/cron.d/
# 4. 检查最近修改的文件
find /etc /usr/local/bin /tmp -type f -mtime -7 2>/dev/null
# 5. 运行 rkhunter
sudo rkhunter --check --sk
# 6. 检查登录记录
last -20如果发现可疑进程、异常网络连接或未知计划任务,参考第十一节应急响应流程。
Q7:sysctl 参数设置后重启会丢失吗?
不会。写入 /etc/sysctl.d/ 目录的 .conf 文件会在每次启动时自动加载。但如果你直接用 sysctl -w 设置的参数,重启后会丢失。
Q8:需要同时用 UFW 和 iptables/nftables 吗?
不需要。选择一个即可:
- UFW — Ubuntu/Debian 用户首选,语法简单
- nftables — Debian 12+ / CentOS 默认,性能更好
- iptables — 老系统兼容,但不推荐新部署使用
混用可能导致规则冲突。
总结与延伸阅读
安全加固优先级
如果你时间有限,按以下优先级执行:
| 优先级 | 加固项 | 耗时 | 效果 |
|---|---|---|---|
| P0 | SSH 密钥 + 禁用密码 + 修改端口 | 5 分钟 | 阻断 90% 自动化攻击 |
| P0 | 防火墙仅开放必要端口 | 3 分钟 | 减少攻击面 |
| P1 | Fail2ban 防爆破 | 5 分钟 | 自动封禁恶意 IP |
| P1 | 内核 sysctl 加固 | 2 分钟 | 防网络层攻击 |
| P2 | 创建非 root 用户 | 3 分钟 | 限制权限 |
| P2 | 自动安全更新 | 3 分钟 | 防 CVE 漏洞 |
| P3 | AIDE + rkhunter | 10 分钟 | 入侵检测 |
| P3 | Docker 安全加固 | 5 分钟 | 容器隔离 |
| P3 | 日志告警通知 | 10 分钟 | 实时感知 |
P0 + P1 总共 15 分钟,就能挡住 95% 的攻击。
延伸阅读
- VPS 供应商横向对比 — 选一台安全基础好的 VPS
- Fail2ban 防暴力破解完全指南 — Fail2ban 深度配置
- VPS 安全进阶:超越 Fail2ban — 2FA 和 UFW 高级配置
- 入侵检测与安全审计实战 — AIDE/rkhunter 深度教程
- Linux 防火墙端口完全指南 — UFW/iptables/firewalld 全覆盖
- Nginx 反向代理与 SSL 配置 — Web 服务安全配置
- VPS 数据备份与恢复完整指南 — 最后的安全网
- 3X-UI 面板自建代理教程 — 代理面板部署
- WireGuard 自建 VPN 完整教程 — VPN 协议配置
🛡️ 安全没有终点,只有持续的加固。 上线不是结束,而是开始。定期更新、定期检查、定期演练——这才是真正的安全之道。
延伸阅读
免责声明
本文仅供技术交流和学习参考。涉及第三方服务的链接可能包含 sponsored 标记,请自行核实服务条款、价格和可用性,并遵守当地法律法规。