怎么防止开启 Cloudflare 后源站仍被 DDoS 攻击?
防止 Cloudflare 防护失效的关键是确保源站 IP 不泄露,并配置源站防火墙只接受来自 Cloudflare 的流量。
先说结论:源站 IP 一旦泄露,Cloudflare 的 DDoS 防护就形同虚设,必须从源头隐藏 IP 并限制访问来源。
- 先判断:检查源站 IP 是否已泄露,查看历史 DNS 记录和服务器日志
- 优先做:配置源站防火墙只允许 Cloudflare IP 段访问,启用 Argo Tunnel 隐藏源站
- 再验证:从非 Cloudflare 节点直接访问源站 IP,确认请求被拒绝
- 注意风险:更换源站 IP 会导致业务短暂中断,请在维护窗口操作
快速处理思路
这个问题不适合用单一命令解决,需要多层配置配合。核心思路是:隐藏源站真实 IP + 限制访问来源 + 监控泄露风险。
如果源站 IP 已经泄露,建议直接更换服务器 IP,再按以下步骤重新配置。更换 IP 前请确保已做好数据备份并通知用户。
为什么会这样
Cloudflare 的 DDoS 防护工作原理是将流量先引导至其全球边缘节点,经过清洗后再转发到源站。这个防护链条有一个关键前提:攻击流量必须经过 Cloudflare 网络。
如果攻击者知道了源站的真实 IP 地址,就可以绕过 Cloudflare 直接攻击源站。此时 Cloudflare 的防护体系完全失效,因为流量根本不经过它的网络。这种情况常见于:
- 网站启用 Cloudflare 前,DNS 历史记录中保留了真实 IP
- 服务器向外发送邮件时,邮件头中暴露了源站 IP
- 网站代码中存在直接连接外部服务的请求,泄露了源站 IP
- 子域名未接入 Cloudflare,通过子域名反推主站 IP
分步处理
第一步:检查源站 IP 是否已泄露
在配置防护前,先确认当前源站 IP 的暴露情况:
- 查询历史 DNS 记录:使用 SecurityTrails (securitytrails.com) 或 ViewDNS (viewdns.info) 查询域名历史 A 记录。
- 检查服务器日志:查看 Nginx/Apache 日志,确认是否有非 Cloudflare IP 段的直接访问请求。
- 本地验证:在本地终端执行
curl -s http://ipinfo.io/ip确认出口 IP,对比服务器公网 IP。
如果发现 IP 已泄露,建议更换服务器 IP 后再继续配置。更换 IP 期间业务会中断,请提前规划维护窗口。
第二步:配置源站防火墙
在源站服务器上配置防火墙,只允许 Cloudflare 的 IP 段访问。以 iptables 为例,注意命令中不要误用反引号:
iptables -A INPUT -p tcp `--dport` 80 -s 173.245.48.0/20 -j ACCEPT iptables -A INPUT -p tcp `--dport` 443 -s 173.245.48.0/20 -j ACCEPT iptables -A INPUT -p tcp `--dport` 80 -j DROP iptables -A INPUT -p tcp `--dport` 443 -j DROP
Cloudflare 的 IP 段会定期更新,手动维护容易遗漏。建议编写脚本自动同步最新列表。以下是一个简单的 Bash 脚本示例,用于更新 IPv4 白名单:
#!/bin/bash
# 保存为 update_cf_ips.sh
CF_IPS_URL="https://www.cloudflare.com/ips-v4"
CHAIN_NAME="CLOUDFLARE_IPS"
# 创建新链
iptables -N $CHAIN_NAME 2>/dev/null || iptables -F $CHAIN_NAME
# 获取最新 IP 段并添加规则
while IFS= read -r ip; do
iptables -A $CHAIN_NAME -s $ip -j ACCEPT
done <(curl -s $CF_IPS_URL)
# 将 INPUT 链相关流量跳转至新链
iptables -A INPUT -p tcp `--dport` 80 -j $CHAIN_NAME
iptables -A INPUT -p tcp `--dport` 443 -j $CHAIN_NAME
# 设置 Cron 任务每周更新一次
# crontab -e
# 0 3 * * 0 /root/update_cf_ips.sh请根据实际业务需求调整脚本,生产环境建议先在测试机验证。
第三步:启用 Argo Tunnel
Argo Tunnel 通过加密隧道将源站隐藏在 Cloudflare 网络之后,即使攻击者获取了源站 IP,也无法直接发起攻击,因为源站不再监听公网端口。配置步骤:
- 安装 cloudflared 客户端:
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb dpkg -i cloudflared-linux-amd64.deb
- 认证隧道:
cloudflared tunnel login
浏览器会打开认证页面,选择域名后返回终端。 - 创建隧道:
cloudflared tunnel create `--name` my-tunnel
记录返回的 Tunnel ID。 - 配置路由:在 Cloudflare 后台 Zero Trust 面板中配置 Tunnel 路由,将域名指向本地 localhost:80 或服务端口。
- 运行隧道:
cloudflared tunnel run `--token` <YOUR_TOKEN>
这种方式下,源站不需要开放任何公网端口,安全性更高。
第四步:检查子域名和关联服务
确保所有子域名都接入 Cloudflare,包括:
- www、mail、ftp 等常见子域名
- 测试环境、staging 环境
- API 接口域名
同时检查服务器是否向外发送邮件。如果必须发送邮件,请使用第三方 SMTP 中继服务(如 SendGrid、Mailgun),避免邮件头泄露源站 IP。配置 Postfix 使用中继示例:
smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_security_options = noanonymous relayhost = [smtp.sendgrid.net]:587
怎么验证是否生效
配置完成后,需要验证防护措施是否生效:
- 直接访问源站 IP:从非 Cloudflare 节点(如本地电脑不经过代理)执行命令,应该无法连接或返回错误:
curl -H "Host: yourdomain.com" http://YOUR_ORIGIN_IP
如果返回网站内容,说明防火墙未生效。 - 检查 HTTP 头:通过 Cloudflare 访问网站,响应头中应包含 CF 相关标识:
curl -I https://yourdomain.com
检查是否包含cf-ray或cf-cache-status头。 - 查看服务器日志:确认所有请求的 Remote Addr 都来自 Cloudflare IP 段。
- 使用在线工具:通过多个 IP 查询工具检查域名解析是否指向 Cloudflare。
常见坑
- IP 段未及时更新:Cloudflare 的 IP 段会变化,防火墙规则需要定期同步,建议使用自动化脚本。
- 忽略 IPv6:如果服务器开放了 IPv6,需要同时配置 IPv6 的访问限制(ip6tables)。
- 邮件服务泄露:服务器直接发送邮件会在邮件头中暴露源站 IP,建议使用第三方邮件服务。
- 历史 DNS 记录:即使当前 DNS 已指向 Cloudflare,历史记录仍可能被查询到,IP 泄露后建议更换。
- 免费套餐限制:Cloudflare 免费套餐对大规模网络层洪水攻击的缓解能力有限,主要针对应用层攻击和中小规模网络层攻击。
- 源站端口暴露:除了 80/443 端口,其他服务端口(如数据库、管理后台)也需要限制访问来源,不要绑定 0.0.0.0。
- 更换 IP 停机风险:更换源站 IP 会导致 DNS 传播期间部分用户无法访问,请提前公告。
参考来源
- Cloudflare 官方文档 - 保护源服务器 IP 地址
- Cloudflare 官方文档 - 使用 cloudflared 创建隧道
- Cloudflare 官方文档 - 防火墙规则与 IP 访问控制