跳转到内容

VPS 安全加固实战指南 2026:从零到堡垒级服务器防护

VPS Security Hardening

🛡️ 一台刚买回来的 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 安全加固的核心理念

  1. 最小权限原则 — 只开放必要的端口,只授予必要的权限
  2. 纵深防御 — 多层防护,不依赖单一手段
  3. 自动响应 — Fail2ban + 告警,不要靠人工盯日志
  4. 持续更新 — 安全不是一次性工作,漏洞每天都在发现
  5. 备份为王 — 再好的防护也可能被突破,备份是最后防线

💡 本文是 VPS 安全总纲,站内已有多篇专题文章深入讲解各个模块。本文会引用它们作为延伸阅读,确保你既有全局视角又能深入细节。


二、SSH 安全加固

SSH 是攻击者的首要目标,也是我们加固的第一道防线。

2.1 密钥登录:彻底告别密码

bash
# 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 配置

bash
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_config

修改以下关键参数:

bash
# ===== 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
bash
# 重启 SSH 服务
sudo systemctl restart sshd

# 验证配置语法(不会重启服务)
sudo sshd -t

2.3 SSH 2FA(可选但推荐)

对于高安全要求的场景,可以启用 Google Authenticator 双因子认证:

bash
# 安装 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 推荐)

bash
# 安装 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 verbose

3.2 UFW 高级配置

bash
# 仅允许特定 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.log

3.3 nftables 配置(Debian 12+ / CentOS 推荐)

nftables 是 iptables 的继任者,语法更简洁,性能更好:

bash
# 安装
sudo apt install -y nftables

# 创建配置文件
sudo nano /etc/nftables.conf
bash
#!/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;
    }
}
bash
# 应用规则
sudo nft -f /etc/nftables.conf

# 开机自启
sudo systemctl enable nftables

# 查看规则
sudo nft list ruleset

📖 延伸阅读Linux 防火墙端口开放完全指南 | iptables 防火墙指南


四、Fail2ban 入侵防御

Fail2ban 通过监控日志自动封禁恶意 IP,是 SSH 防爆破的标配工具。

4.1 安装与基础配置

bash
sudo apt install -y fail2ban

# Fail2ban 的配置不要直接修改 jail.conf,而是创建 jail.local
sudo nano /etc/fail2ban/jail.local
ini
# ===== 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
bash
# 创建端口扫描过滤器
sudo nano /etc/fail2ban/filter.d/port-scan.conf
ini
[Definition]
failregex = .*block.*from.*SRC=.*
ignoreregex =
bash
# 重启 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.66

4.2 Fail2ban 进阶:递增封禁

上面的配置中已经启用了 bantime.increment,效果如下:

第 N 次被封封禁时间
第 1 次1 小时
第 2 次2 小时
第 3 次4 小时
第 4 次8 小时
......
上限7 天

📖 延伸阅读Fail2ban 防暴力破解配置完全指南


五、内核参数加固

Linux 内核默认配置以兼容性为主,不少参数对安全并不友好。通过 sysctl 调优可以显著提升系统安全性。

5.1 安全加固 sysctl 配置

bash
sudo nano /etc/sysctl.d/99-security.conf
bash
# ===== 网络安全加固 =====

# 开启 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
bash
# 应用配置
sudo sysctl -p /etc/sysctl.d/99-security.conf

# 验证
sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl kernel.randomize_va_space

5.2 内核参数说明表

参数作用
tcp_syncookies1防 SYN Flood 攻击
rp_filter1反向路径过滤,防 IP 欺骗
accept_redirects0禁用 ICMP 重定向
accept_source_route0禁用源路由
icmp_echo_ignore_broadcasts1防 Smurf 攻击
log_martians1记录可疑数据包
randomize_va_space2ASLR 地址随机化
dmesg_restrict1限制 dmesg 访问
kptr_restrict2隐藏内核指针
suid_dumpable0禁用核心转储
protected_symlinks1符号链接保护

⚠️ 注意:如果你运行 WireGuard 或 3X-UI 代理面板,需要保持 net.ipv4.ip_forward = 1。具体配置请参考 WireGuard 自建 VPN 完整教程3X-UI 面板自建代理教程


六、用户与权限管理

6.1 创建非 root 管理用户

永远不要用 root 直接操作。创建一个有 sudo 权限的普通用户:

bash
# 创建新用户
adduser deploy

# 加入 sudo 组
usermod -aG sudo deploy

# 验证 sudo 权限
su - deploy
sudo whoami  # 应返回 root

6.2 sudo 安全配置

bash
sudo visudo -f /etc/sudoers.d/security
bash
# ===== 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 nginx

6.3 禁用不必要的系统账户

bash
# 查看所有用户的 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 nobody

6.4 文件权限加固

bash
# 关键系统文件权限
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

bash
# 安装
sudo apt install -y unattended-upgrades apt-listchanges

# 自动配置
sudo dpkg-reconfigure -plow unattended-upgrades
bash
# 编辑配置文件
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
bash
Unattended-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";
bash
# 编辑自动更新周期
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
bash
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Download-Upgradeable-Packages "1";
bash
# 验证配置(试运行)
sudo unattended-upgrade --dry-run --verbose

# 手动触发一次
sudo unattended-upgrade -v

7.2 需要排除的包

某些包不希望自动更新(如自定义内核、特定版本锁定):

bash
# 在 50unattended-upgrades 中添加
Unattended-Upgrade::Package-Blacklist {
    "nginx";
    "docker-ce";
    "redis-server";
};

💡 建议:对于生产环境的关键服务(如数据库),建议关闭自动更新,改用 定时手动更新 + 更新前快照 的策略。


八、Docker 容器安全

如果你在 VPS 上跑 Docker(很多人都是),容器安全同样重要。

8.1 Docker 守护进程加固

bash
sudo nano /etc/docker/daemon.json
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"
}
bash
sudo systemctl restart docker

8.2 容器安全最佳实践

bash
# 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 myapp

8.3 Docker 安全检查脚本

bash
#!/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 不存在"
fi

8.4 Docker Compose 安全配置示例

yaml
# 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)定期扫描关键文件,发现任何篡改立即告警。

bash
# 安装
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

配置定时检查脚本:

bash
sudo nano /etc/cron.daily/aide-check
bash
#!/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"
fi
bash
sudo chmod +x /etc/cron.daily/aide-check

9.2 rkhunter — Rootkit 检测

bash
# 安装
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"

配置每日自动扫描:

bash
sudo nano /etc/cron.daily/rkhunter-check
bash
#!/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
fi
bash
sudo chmod +x /etc/cron.daily/rkhunter-check

📖 延伸阅读Linux 服务器入侵检测与安全审计实战


十、日志告警与 DDoS 缓解

10.1 日志监控告警

bash
# 安装 logwatch(每日安全摘要邮件)
sudo apt install -y logwatch

# 配置
sudo nano /etc/logwatch/conf/logwatch.conf
bash
MailTo = admin@y-m.top
MailFrom = logwatch@y-m.top
Range = yesterday
Detail = High
Service = All
bash
# 测试发送
sudo logwatch --output mail --range yesterday

# 它会每天自动运行(已集成到 /etc/cron.daily/)

10.2 SSH 登录告警

在用户登录时发送通知:

bash
sudo nano /etc/ssh/sshrc
bash
#!/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.top
bash
sudo chmod +x /etc/ssh/sshrc

10.3 DDoS 缓解策略

策略适用场景效果实施难度
UFW 速率限制小规模连接洪水
Fail2ban应用层 CC 攻击
Cloudflare CDNL3/L4/L7 DDoS
iptables/nftables 限速SYN Flood
BBR 拥塞控制带宽耗尽型攻击

10.3.1 开启 BBR 拥塞控制

bash
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 = bbr

10.3.2 iptables SYN Flood 防护

bash
# 限制每秒 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 save

10.3.3 Cloudflare 防护(推荐)

对于 Web 服务,最有效的 DDoS 防护是套一层 Cloudflare:

  1. 域名 DNS 迁移到 Cloudflare
  2. 开启 Proxy(橙色云朵)
  3. SSL/TLS 设为 Full (Strict)
  4. 开启 Always Use HTTPS
  5. 安全级别设为 High
  6. 开启 Bot Fight Mode
  7. 配置 WAF 规则拦截恶意请求

📖 延伸阅读Cloudflare Tunnel 内网穿透 | Cloudflare WARP 中转


十一、应急响应:被黑了怎么办

即使做了所有加固,也可能被突破。关键是如何快速响应。

11.1 应急响应流程

发现异常 → 隔离服务器 → 保留证据 → 排查范围 → 清除威胁 → 恢复服务 → 复盘总结

11.2 第一步:隔离

bash
# 立即断网(通过云平台控制台操作,不要用 SSH 断网,否则自己也连不上)
# 或通过防火墙仅允许自己的 IP
sudo ufw deny incoming
sudo ufw allow from YOUR_IP to any port 58291

# 禁用所有非必要服务
sudo systemctl stop nginx
sudo systemctl stop docker

11.3 第二步:排查

bash
# 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 --sk

11.4 第三步:清除与恢复

bash
# 杀死可疑进程
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 -y

11.5 最终建议:重装系统

如果确认被入侵,最安全的做法是重装系统

  1. 备份关键数据(只备份应用数据,不备份系统配置)
  2. 云平台重装系统
  3. 按本文流程重新加固
  4. 恢复数据(逐个检查后再恢复)
  5. 更新所有密钥和密码

💡 记住:你永远无法 100% 确定清除了所有后门。重装是唯一可靠的选择。

📖 延伸阅读VPS 数据备份与恢复完整指南 | rsync 增量备份指南


十二、安全检查清单:上线前 30 条

将以下清单逐条检查后再上线服务:

SSH 安全

防火墙

入侵防御

内核加固

用户与权限

自动更新

完整性监控

容器安全

备份


十三、一键加固脚本

将以上核心步骤整合为一键脚本,方便新 VPS 快速加固:

bash
#!/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,修改配置区参数后执行:

bash
chmod +x vps-hardening.sh
sudo ./vps-hardening.sh

FAQ:常见问题

Q1:加固后 SSH 连不上了怎么办?

先用云平台的 VNC 控制台登录,然后检查:

  1. SSH 端口是否正确:grep "^Port" /etc/ssh/sshd_config
  2. 密钥是否配置正确:cat ~/.ssh/authorized_keys
  3. 防火墙是否放行:ufw status
  4. Fail2ban 是否误封:fail2ban-client status sshd
  5. SSH 服务是否运行:systemctl status sshd

如果确认配置正确但仍无法连接,临时恢复备份:

bash
cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config
systemctl restart sshd

Q2:Fail2ban 把自己的 IP 封了怎么办?

bash
# 查看被封的 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 fail2ban

Q3:unattended-upgrades 会自动重启服务器吗?

只有在配置中开启了 Automatic-Reboot "true" 时才会。关键服务(如数据库)建议关闭自动重启,改用手动更新:

bash
# 在 50unattended-upgrades 中设置
Unattended-Upgrade::Automatic-Reboot "false";

Q4:Docker 容器用了 --read-only 后无法写入怎么办?

挂载可写卷到需要写入的目录:

bash
docker run --read-only \
  -v /data/app/logs:/app/logs \
  -v /data/app/uploads:/app/uploads \
  --tmpfs /tmp \
  myapp

Q5:AIDE 报告大量文件变更,正常吗?

首次运行 AIDE 后如果安装了新软件或修改了配置,会产生大量变更报告。处理方式:

  1. 确认变更是你自己操作引起的
  2. 更新 AIDE 基准:sudo aide --update && sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
  3. 如果变更不是你引起的,立即排查入侵

Q6:如何判断服务器是否被入侵?

快速检查清单:

bash
# 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 — 老系统兼容,但不推荐新部署使用

混用可能导致规则冲突。


总结与延伸阅读

安全加固优先级

如果你时间有限,按以下优先级执行:

优先级加固项耗时效果
P0SSH 密钥 + 禁用密码 + 修改端口5 分钟阻断 90% 自动化攻击
P0防火墙仅开放必要端口3 分钟减少攻击面
P1Fail2ban 防爆破5 分钟自动封禁恶意 IP
P1内核 sysctl 加固2 分钟防网络层攻击
P2创建非 root 用户3 分钟限制权限
P2自动安全更新3 分钟防 CVE 漏洞
P3AIDE + rkhunter10 分钟入侵检测
P3Docker 安全加固5 分钟容器隔离
P3日志告警通知10 分钟实时感知

P0 + P1 总共 15 分钟,就能挡住 95% 的攻击。

延伸阅读


🛡️ 安全没有终点,只有持续的加固。 上线不是结束,而是开始。定期更新、定期检查、定期演练——这才是真正的安全之道。


延伸阅读

免责声明

本文仅供技术交流和学习参考。涉及第三方服务的链接可能包含 sponsored 标记,请自行核实服务条款、价格和可用性,并遵守当地法律法规。