当您的服务器有了一定曝光度,简单修改 SSH 端口和配置 UFW 已不足以应对现代威胁。本指南从系统层、Web 服务层和 CDN 层三个维度出发,带您构建一套完整的多层纵深防御体系,让攻击者无从下手。
⚔️ 现代服务器的攻击图景
互联网上每时每刻都有自动化扫描机器人(如 Shodan、Censys 抓取引擎及各类黑客工具)在遍历公网 IP。一台新开的 VPS,通常在上线后 30 分钟内就会出现在扫描器的记录里。了解攻击类型,才能对症下药:
暴力破解
持续尝试 SSH/数据库密码。典型特征:auth.log 中大量 "Failed password" 记录。
防御: 密钥认证 + Fail2ban。
漏洞扫描
探测 wp-admin、.env、phpmyadmin、.git 等敏感路径,寻找未修补的已知漏洞。
防御: Fail2ban + WAF 规则。
CC / 应用层 DDoS
海量并发请求耗尽 CPU 和内存,使服务无响应。典型:每秒数千次 POST 请求打某个 API 接口。
防御: 并发限速 + Cloudflare。
流量型 DDoS
Gbps 级别的垃圾流量直接堵死机房带宽,服务器内核层完全无能为力。
防御: 隐藏真实 IP 是唯一出路。
🎯 核心防御哲学
真正高效的安全策略不是"修补漏洞",而是让攻击者根本找不到目标。本指南的所有内容都围绕这个思路展开:隐藏真实 IP → 关闭不必要的端口 → 让剩余的攻击流量自动封锁或消耗在混淆层。
🥷 核心战略:彻底隐藏源站真实 IP
如果黑客掌握了您 VPS 的公网 IP,任何内核级防火墙规则都无济于事——流量型 DDoS 会直接把您的机房上行带宽塞满,导致整个机房受牵连(商家会对攻击目标 IP 执行"黑洞路由",即拔网线隔离)。防御 DDoS 的终极方法,就是让攻击者找不到真实 IP。
IP 泄露的五大常见途径
若邮件服务与网站部署在同一台服务器,发信时邮件头会携带真实 IP。解决方案:使用 SendGrid、腾讯企业邮箱等第三方邮件服务,完全隔离邮件服务器 IP。
Censys、SecurityTrails、ViewDNS 等工具会存档历史 DNS 解析记录。如果您的域名曾直接解析过真实 IP,这些记录永久保留。唯一出路:换一个新 IP 并从头开始。
申请 SSL 证书时,CA 会将证书信息写入公开的 CT 日志(crt.sh)。若证书包含您的域名,即使 Cloudflare 代理,攻击者仍能从证书日志中反查出域名与 IP 的关联。
如 direct.yourdomain.com、api.yourdomain.com 等子域名若未开启 Cloudflare 橙云代理,直接暴露真实 IP,攻击者可通过子域名 ping 出主站 IP。
运行 Prometheus Exporter、Node Exporter 等监控服务时,若监听 0.0.0.0 且未配置认证,扫描器可通过 /metrics 接口指纹识别出您的服务器。应绑定到 127.0.0.1 或 Tailscale 内网 IP。
终极白名单模式:只允许 Cloudflare IP 访问 Web 端口
在系统防火墙层面,拒绝所有外网直连,仅放行 Cloudflare CDN 节点的 IP 段访问 80/443 端口。这样即使黑客扫到了您的真实 IP,发起的攻击也会在 UFW 层静默丢弃,完全不消耗 CPU 资源。
#!/bin/bash
# 文件路径:/usr/local/bin/update-cf-whitelist.sh
# 功能:拉取 Cloudflare 最新 IP 段,只允许 CF 节点访问 80/443,封闭所有其他来源
# 建议每周执行一次(加入 Cron):0 4 * * 1 /usr/local/bin/update-cf-whitelist.sh
# 先关闭对 Web 端口的所有公网访问
ufw deny 80/tcp
ufw deny 443/tcp
# 拉取 Cloudflare 最新的 IPv4 地址段并逐一放行
# 截至 2026 年,CF IPv4 包含约 15 个 CIDR 块,如 103.21.244.0/22, 141.101.64.0/18 等
echo "正在更新 Cloudflare IPv4 白名单..."
for ip in $(curl -s https://www.cloudflare.com/ips-v4); do
ufw allow from "$ip" to any port 80,443 proto tcp comment "CF-IPv4"
done
# 同样放行 Cloudflare IPv6 地址段
echo "正在更新 Cloudflare IPv6 白名单..."
for ip in $(curl -s https://www.cloudflare.com/ips-v6); do
ufw allow from "$ip" to any port 80,443 proto tcp comment "CF-IPv6"
done
echo "Cloudflare 白名单更新完成!当前规则:"
ufw status | grep CF 0 4 * * 1 /usr/local/bin/update-cf-whitelist.sh),因为 Cloudflare 偶尔会更新其 IP 段列表。
🚫 实战:Nginx 防 IP 直接访问与证书探测
全球扫描器(Shodan、Censys、各类黑客爬虫)在随机遍历 IP 时,会发起 HTTP/HTTPS 请求。若 Nginx 没有专门配置,默认会将第一个定义的 server 块当作响应返回——这会把您的真实域名和 SSL 证书信息暴露给扫描器。
正确做法:将一个 return 444 的 server 块设为 default_server,让所有"无主请求"(直接通过 IP 访问、Host 头不匹配任何已知域名的请求)都被直接切断 TCP 连接。
# 文件路径:/etc/nginx/sites-available/default
# 此配置必须排在其他 server{} 块之前,作为 Nginx 最先匹配的"兜底"规则
server {
# 同时监听 IPv4 与 IPv6,default_server 让 Nginx 把所有"无主"请求转到这里
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _; # 匹配任意 Host 头,包括直接 IP 访问
# ⚠️ 必须配置一个证书,否则 443 上的 TLS 握手会失败并泄露报错信息
# 使用系统自带的蛇油(self-signed)证书即可,无需真实证书
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# 444 是 Nginx 专有非标准状态码
# 效果:直接在 TCP 层关闭连接,不返回任何 HTTP 报头或报文
# 对扫描器来说:它发出请求,什么都收不到,超时后才能判断结果——极大拖慢扫描效率
return 444;
} 🔑 实战:SSH 深度硬化清单
SSH 是服务器管理的核心入口,也是暴力破解攻击最集中的目标。以下是一份经过实践验证的 SSH 硬化清单,每一条都附有详细的原因说明:
# 前提:普通管理用户、密钥登录和 sudo 已在另一个终端验证
# Debian / Ubuntu 可将自定义项放入:
# /etc/ssh/sshd_config.d/90-vpsknow-hardening.conf
# 【第一步】禁用密码与交互式认证,强制使用已验证的密钥
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
# 【第二步】禁用 root 用户直接登录(使用普通用户 sudo)
PermitRootLogin no
# 【第三步】限制只允许特定用户登录(改为实际用户名)
AllowUsers youruser
# 【第四步】关闭不使用的转发能力;依赖 SSH 隧道时不要照抄
X11Forwarding no
AllowTcpForwarding no
# 【第五步】限制失联客户端占用;这不是严格的“无操作超时”
ClientAliveInterval 180
ClientAliveCountMax 2
# 【第六步】限制单连接认证失败次数
MaxAuthTries 3
# 可选:自定义端口主要减少扫描噪声,不替代以上措施
# 修改前先放行新端口,并核对发行版的 socket activation 行为
# Port 39217
# 保存后先校验;失败时不要重载或退出旧会话
sudo sshd -t
sudo systemctl reload ssh
# 最后在新终端验证密钥、端口和 sudo,再关闭旧会话 sshd -t,校验通过后重载服务,并在新 SSH 会话完成验收。旧会话确认前不要退出。
👊 进阶:端口敲门(Port Knocking)
端口敲门是一种让 SSH 端口在防火墙层面"完全不可见"的隐身技术。在平时,SSH 端口对外完全关闭,扫描器无论如何都无法发现它。只有当您按照预设的顺序向特定端口发送"敲门"数据包后,服务器才会临时为您的 IP 开放 SSH 端口。
工作原理示意
服务端配置(knockd)
# 安装 knockd(端口敲门守护程序)
sudo apt install knockd -y
# 编辑配置文件:/etc/knockd.conf
[options]
UseSyslog
# 定义一个"开门"序列:依次敲 7000(tcp) → 8000(udp) → 9000(tcp),10秒内完成
[openSSH]
sequence = 7000,8000,9000
seq_timeout = 10
tcpflags = syn
command = /sbin/ufw allow from %IP% to any port 39217 proto tcp
# %IP% 是 knockd 自动替换为发起敲门客户端的真实 IP
# 定义一个"关门"序列:依次敲 9000 → 8000 → 7000 关闭访问
[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 10
tcpflags = syn
command = /sbin/ufw delete allow from %IP% to any port 39217 proto tcp
# 启动 knockd 服务
sudo systemctl enable --now knockd 客户端操作(您的本地电脑)
# 在您的本地电脑上安装 knock 客户端
# macOS: brew install knock
# Linux: sudo apt install knockd
# Windows: 使用 nmap 模拟,见下文
# 执行敲门序列(依次向三个端口发一个 TCP SYN 包)
knock -v 1.2.3.4 7000 8000:udp 9000
# 1.2.3.4 替换为您的服务器公网 IP
# 敲完后 SSH 连接(使用修改后的端口)
ssh -p 39217 youruser@1.2.3.4
# Windows 用户用 nmap 模拟敲门
nmap -Pn --host-timeout 100 --max-retries 0 -p 7000 1.2.3.4
nmap -Pn --host-timeout 100 --max-retries 0 -p U:8000 1.2.3.4
nmap -Pn --host-timeout 100 --max-retries 0 -p 9000 1.2.3.4 🛡️ 实战:iptables / nftables 缓解 CC/SYN 攻击
对于没有接入 CDN 的 TCP 服务(如游戏服务器),或需要在服务器层面增加一道防护的场景,可使用内核级规则限制单个 IP 的并发连接数与连接速率。现代 Ubuntu 的 iptables 命令通常已经使用 nftables 后端,因此不要只按系统版本猜测;先检查实际后端,再选择兼容命令或原生 nftables 配置。
# ── 兼容方案:iptables 命令界面(先确认实际后端)────────────────────────
# Ubuntu 20.10+ 的 iptables 命令通常使用 nftables 后端:
# update-alternatives --display iptables
# 规则1:限制单个 IP 在 80/443 端口的并发 TCP 半连接数上限为 20
# connlimit 统计的是处于 SYN_RECV 状态的连接(即尚未完成三次握手的连接)
# --reject-with tcp-reset 相比 DROP,能让客户端更快感知到拒绝,节省服务器资源
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --syn --dport 443 -m connlimit --connlimit-above 20 -j REJECT --reject-with tcp-reset
# 规则2:限制新建连接速率(每秒超过 30 个新 SYN 包的 IP 直接封禁 60 秒)
# 这能有效阻断 SYN Flood:正常用户每秒新建连接不会超过个位数
iptables -A INPUT -p tcp --syn -m recent --name syn_flood --update --seconds 1 --hitcount 30 -j DROP
iptables -A INPUT -p tcp --syn -m recent --name syn_flood --set
# 规则3:ICMP 洪水防护(ping 频率限制,每秒最多 1 次,突发最多 5 次)
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 5 -j ACCEPT
iptables -A INPUT -p icmp -j DROP
# 持久化保存规则(重启后不丢失)
apt install iptables-persistent -y
netfilter-persistent save # ── 推荐方案:原生 nftables(现代 Ubuntu / Debian)────────────────────
# nftables 是 iptables 的官方继任者,语法更清晰,性能更优
# 编辑或创建:/etc/nftables.conf
table inet filter {
# 使用 meter(流量计)为每个 IP 单独计数,比 iptables connlimit 精度更高
set tcp_flood {
type ipv4_addr
flags dynamic, timeout
timeout 60s # 计数器 60 秒后自动清零
}
chain input {
type filter hook input priority 0; policy accept;
# 限制单个 IPv4 来源每 10 秒内的 TCP SYN 数量
# 超过 60 个即视为 SYN Flood,直接丢包
ip protocol tcp tcp flags syn add @tcp_flood { ip saddr limit rate over 60/minute } drop
# ICMP 速率限制(防止 ping 洪水)
ip protocol icmp limit rate 10/second accept
ip protocol icmp drop
}
}
# 应用配置并设置开机自启
systemctl enable --now nftables
nft -f /etc/nftables.conf | 对比项 | iptables | nftables |
|---|---|---|
| 内核支持 | 长期支持(老机器兼容性最好) | Linux 3.13+ 内核原生支持 |
| 语法 | 多个工具(iptables/ip6tables/ebtables)各自独立 | 统一语法,IPv4/IPv6/以太网一套规则 |
| 大规模 IP 集合 | 需借助 ipset,配置繁琐 | 内置 set,O(1) 哈希查找,性能更优 |
| 动态规则更新 | 需要 iptables-restore 重载整表 | 支持原子性局部更新,不中断流量 |
| 推荐场景 | 兼容旧脚本或既有工具链;需确认实际后端 | 新部署、统一管理 IPv4/IPv6 与大规模 IP 集合 |
🤖 进阶:Fail2ban 恶意爬虫封锁
Fail2ban 根据日志与过滤器匹配结果,把达到阈值的来源地址写入封禁动作。发行版自带的 nginx-botsearch jail 通常读取 Nginx error log;实际路径由 Fail2ban 的发行版变量决定,启用前必须用本机日志验证。
# 编辑或创建:/etc/fail2ban/jail.d/nginx-local.conf
# 只覆盖本站需要的 jail,避免复制整份 jail.conf 后长期漂移
[DEFAULT]
# 默认只信任本机;固定管理 IP 应确认归属和变更流程后再加入
ignoreip = 127.0.0.1/8 ::1
# 使用发行版自带的 nginx-botsearch 过滤器
[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
# 先观察错误日志中的真实命中,再按正常流量调参
maxretry = 5
findtime = 10m
bantime = 1h
# 上线前测试配置和真实日志;失败时不要重启服务
# fail2ban-client -t
# fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-botsearch.conf
# systemctl reload fail2ban
# fail2ban-client status nginx-botsearch 📋 上线前必须确认的匹配边界
- 运行
fail2ban-client -t,确认 jail、过滤器、日志路径和 action 均可加载。 - 用
fail2ban-regex对真实 error log 回放,检查命中与漏报,而不是假设某个 URL 一定会触发。 - 先使用有限封禁时间观察误判;WordPress 登录保护应优先结合应用限速、MFA 或 WAF 规则。
☁️ 进阶:Cloudflare 边缘封禁与 IP List
接入 Cloudflare 后,源站必须先恢复并记录真实访客 IP。如果 Nginx 日志仍记录 Cloudflare 节点地址,Fail2ban 可能误封 Cloudflare 出口,导致正常访客一起受影响。先核对日志链路,再考虑把源站判定同步到边缘。
Cloudflare 当前建议使用 WAF 自定义规则 + IP List 做 IP 封禁,而不是为每个地址持续创建 IP Access Rule。IP List 可集中维护地址集合,一条规则即可引用;自动化程序只更新列表内容,更容易审计、限权和清理。
# 1. 先确认 Nginx 日志中的来源 IP 是真实访客,而不是 Cloudflare 节点
tail -n 20 /var/log/nginx/access.log
# 2. 确认 Fail2ban 实际读取的日志和命中结果
fail2ban-client status
fail2ban-client status nginx-botsearch
# 3. 在 Cloudflare 控制台创建账户级 IP List,例如:blocked_ips
# 4. 在 WAF 自定义规则中引用:
# ip.src in $blocked_ips
# 动作优先选择 Managed Challenge;确认无误后再考虑 Block
# 5. 自动化时使用最小权限、可过期的 API Token
# 不要把 Token 写进公开仓库、网页代码或命令历史
# 6. 设置过期与回收机制,避免临时封禁永久累积
# 7. 从外部网络验证规则,并在 Security Events 中检查命中 了解现有功能、50,000 条账户上限,以及官方为何建议优先使用自定义规则。
IP Lists免费计划也可使用 1 个自定义列表;各非企业计划合计最多 10,000 个列表条目。
WAF 自定义规则规则数量随套餐变化;先确认当前计划额度,再设计自动化和回收策略。
✅ 安全加固一键检查清单
完成本指南后,请对照以下清单逐项验证,确保没有遗漏任何防护层:
IP 隐藏
- 所有 A/AAAA 记录均已开启 Cloudflare 橙云代理,无裸 IP 解析
- MX 记录指向第三方邮件服务(非本机 IP)
- 已通过 UFW 脚本只放行 Cloudflare IP 段访问 80/443
- 已申请新 IP(若历史 IP 曾裸露在 Censys/Shodan 记录中)
SSH 安全
- SSH 端口已修改为非标准端口(非 22)
- 已禁用密码登录(PasswordAuthentication no)
- 已禁用 root 直接登录(PermitRootLogin no)
- 已配置端口敲门或 AllowUsers 白名单
Nginx 防护
- 已配置 default_server 返回 444,防止 IP 直接访问
- 使用蛇油证书作为 443 默认 server 的占位证书
自动防御
- Fail2ban 已配置 SSH jail(maxretry ≤ 5)
- Fail2ban 已配置 Nginx web 扫描 jail
- (可选)Fail2ban 已联动 Cloudflare API 自动封 IP
DDoS 缓解
- iptables/nftables 已配置 SYN 并发限速规则
- ICMP 频率已限制(防 ping 洪水)
- 规则已持久化(重启后不丢失)
❓ 常见问题解答
套了 Cloudflare 之后,我的源站 IP 就绝对安全了吗?
不能完全保证,关键在于您有没有泄露过真实 IP。Cloudflare 只是代理了您的 HTTP/HTTPS 流量,若您在套 CF 之前就用真实 IP 运行了一段时间,Shodan、Censys、ViewDNS 等数据库已经记录了该 IP 与您域名的关联。在这种情况下,攻击者可以绕过 CF 直接对真实 IP 发起攻击。最彻底的解决方案:套好 CF 后,花几美元让服务商更换一个全新的 IP 地址,彻底斩断历史记录。
return 444 和 return 403 有什么区别?我应该用哪个?
444:Nginx 专有非标准状态码,直接在 TCP 层关闭连接,不发送任何 HTTP 响应。扫描器无法判断您运行了什么服务,信息泄露最少,且不消耗 HTTP 处理资源。403:返回一个完整的 HTTP 响应(包含 Server 头和响应体),扫描器至少能确认"这里有一个 HTTP 服务",还可能暴露 Nginx 版本号。结论:对陌生的 IP 直访请求,始终用 444;403 用于对合法用户拒绝访问的场景(如限定了 allowlist 后的资源)。
端口敲门安全吗?万一序列被中间人截获怎么办?
端口敲门提供的是隐匿性而非加密性,属于"通过隐藏实现安全(Security through Obscurity)"的策略。理论上,若网络路径上存在流量嗅探,序列可能被截获并重放。实际风险较低,因为序列有 seq_timeout 时间窗口限制,且与来源 IP 绑定。最佳实践:将端口敲门作为额外的安全层使用,而非替代密钥认证。SSH 密钥认证才是安全底线,即使敲门序列被知道,没有私钥也无法登录。也可以考虑使用 fwknop(基于密钥的单包授权 SPA)作为更安全的替代方案——SPA 包经过加密且每次唯一,无法重放。
Fail2ban 封禁规则是否适用于 IPv6?如何配置?
是否覆盖 IPv6 取决于发行版、Fail2ban 版本和当前 banaction,不能只看配置名称。先运行 fail2ban-client get sshd actions,再检查对应 action 与系统防火墙规则。新部署可优先使用 nftables-multiport 等 nftables action,并用 IPv4、IPv6 两个外部地址分别触发测试;任何未验证的 IPv6 放行都应视为防护缺口。
我的 VPS 遭受 DDoS 后被商家"黑洞"了,多久能解封?如何预防下次?
"黑洞路由"(Null Route)是商家为了保护整个机房将受攻击 IP 路由到空的手段。解封时间因商家而异:搬瓦工通常 1-2 小时自动解封;OVH 有时需要 24 小时;部分小商家需要人工操作。预防下次被黑洞:① 将所有对外服务切换到 Cloudflare CDN,隐藏真实 IP——这是根本;② 更换一个新 IP 地址,彻底断开与旧 IP 的关联;③ 选择有"高防"套餐的商家(如 SpartanHost、OVH),这些商家在上游已接入 DDoS 清洗服务(通常为 Voxility 或自建),可以吸收几十到几百 Gbps 的攻击而不触发黑洞。
安全加固后 iptables 规则越来越多,会影响服务器性能吗?
iptables 采用线性链式匹配,当规则数量在数千条以内时,性能影响微乎其微(个人 VPS 通常不超过 100 条)。关键优化技巧:① 将最高频匹配的规则(如 -m state --state ESTABLISHED,RELATED -j ACCEPT)放在链的最前面,大多数合法流量在第一条规则处就命中,无需继续匹配;② 若需要封禁大量 IP(如地区封锁、动态黑名单),使用 ipset——哈希表结构,无论放入多少 IP 都是 O(1) 查找;③ 新系统推荐迁移到 nftables,其内置的 set 数据结构在大规模场景下性能显著优于 iptables。
Cloudflare API 封 IP 有数量上限吗?Fail2ban 大量封禁会不会超限?
有,而且必须按 Cloudflare 当前文档核对:IP Access Rules 目前是每个账户最多 50,000 条,但官方建议 IP 封禁优先使用 WAF 自定义规则 + IP List。IP List 已覆盖免费计划;Free 可创建 1 个自定义列表,Free、Pro、Business 的自定义列表合计最多 10,000 个条目,Enterprise 上限更高。无论采用哪种方式,都要设置封禁有效期、定期回收和误封恢复流程,不能把地址无限累积。
服务器安全加固完成后,如何验证防护效果是否真的生效?
多维度验证:① 外部端口扫描:从另一台机器用 nmap -p 1-65535 服务器IP 扫描,确认只有预期端口(SSH 自定义端口)是 open 状态,80/443 应是 filtered(UFW 丢弃);② IP 直接访问测试:用浏览器直接输入 http://服务器IP,应该连接超时而非返回任何内容;③ Cloudflare 绕过测试:关闭 CF 代理,用真实 IP 访问 80 端口,UFW 应静默丢弃;④ Fail2ban 状态检查:fail2ban-client status 查看所有 jail 状态,fail2ban-client status sshd 查看已封禁 IP 列表;⑤ Shodan 自查:在 Shodan.io 搜索您的 IP,检查是否有不应暴露的服务信息。
完成本篇后,下一步应该按什么顺序继续学习?
按本站的 30 篇学习路径,第 10 篇(本篇,security-advanced)→ 第 11 篇(automation-scripts,自动化运维脚本)→ 第 12 篇(logs-and-troubleshooting,日志分析与排错) 是最佳进阶路径。学完安全加固后,您最迫切需要的是:① 用 Shell 脚本 + Cron 把本篇学到的封 IP、更新 CF 白名单等重复工作自动化;② 学会读懂 auth.log、syslog、Nginx access/error log,在出现问题时快速定位根因。这三篇构成了"安全加固 → 自动化维护 → 日志溯源"的完整闭环。
本文的防护措施是否适用于非 HTTP 服务(如游戏服务器、TURN 中继)?
部分适用,但需要调整。完全适用的: SSH 硬化、端口敲门、iptables/nftables 并发限速、IP 隐藏的总体思路。不适用或需替换的: Cloudflare 的 CDN 代理只支持 HTTP/HTTPS(以及部分 TCP 代理,仅限 Enterprise 计划);对于 UDP 游戏流量或 TURN 中继,无法用 CF 隐藏 IP。替代方案:① 选购带 Anti-DDoS 的专用游戏服务器(如 OVH Game 系列、SpartanHost);② 使用 TCPShield(专为 Minecraft 等游戏设计的代理层);③ 使用 Cloudflare Spectrum(收费,支持任意 TCP/UDP 协议的代理与 DDoS 防护)。