← 返回首页

凌晨一点,我的博客被 DDoS 了

2026-07-20 02:17 13728 次阅读

2026-07-20 写在前面:本文记录了一次因友链交换触发的 DDoS 攻击事件,以及 33 分钟内完成服务器迁移 + Cloudflare 接管的全过程。所有 IP 已脱敏,但踩坑和应急操作全部真实。

起因

博客上线快二十天,当晚刚把 Lighthouse 移动端跑到全满分(性能/无障碍/最佳做法/SEO 全 100),正准备收工睡觉。

想了想,去交换几个友链吧——给站点导点外链权重,SEO 刚起步嘛。

去了一个友链交换平台,提交了博客信息。

然后灾难开始。

攻击

发送我站域名不到十秒,站点就卡了。紧接着一大堆短信接连发到我手机——DDoS 攻击告警、超过防护峰值、机器被封锁、遭受持续攻击延长封锁……

每一条短信都在提醒我:你被打死了,而你能做的只有看着。

我用的是某云厂商的轻量应用服务器,2C2G。它的 DDoS「防护」逻辑是:检测到攻击流量,直接封你的机器,而不是清洗。封 24-72 小时不等。

封机器是它的自保机制——轻量版防护能力有限,怕影响同物理机的其他用户。你的站点就成了牺牲品。

更恶心的在后面:解封前又被打,再次封禁。循环四次。攻击者在持续监控服务器状态,解封就打。这不是随机扫描,是针对性攻击。

决策

等解封?不行。源 IP 已经暴露,解封后还会被持续盯梢。

唯一解:换 IP + 上 Cloudflare 代理隐藏源 IP。

于是临时开了第四台轻量服务器(同账号同地域,内网互通),开始迁移。

迁移

1. 部署后端(3 分钟)

博客是纯 Go 后端 + 原生 HTML/CSS/JS 前端,交叉编译一条命令:

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o jay.pub .

打包二进制 + 模板 + 静态资源 + .env,SCP 上传,配 systemd 服务,启动。后端 3 分钟恢复。

数据库是独立主机部署的(PostgreSQL 在另一台机器,仅内网通信),Web 服务器迁移不影响数据。这是之前架构拆分的红利——四台机器各司其职,Web 挂了换一台就行,数据库不动。

2. Nginx 反代

装 nginx,配置 80 端口反代 8080,assets/uploads 走静态文件。通过公网 IP + Host 头验证,200 OK,后端正常。

3. Cloudflare 接管 DNS

关键一步:把 jay.pub 的 DNS 切到 Cloudflare,开启代理(橙色云朵)。

CF 代理模式下,用户访问的是 CF 的 anycast IP,CF 再回源到我的服务器。攻击者只能看到 CF IP,看不到源站真实 IP。

CF 免费版提供无限流量、无限带宽、无限时长的 DDoS 防护。这是 CF 的核心价值——个人站长也能用上企业级防护。

4. SSL 证书签发(踩坑)

CF 代理模式下,HTTP 验证(acme-challenge)会被 CF 拦截,必须用 DNS 验证签证书。

坑 1:CF API Token 权限

acme.sh 的 CF 插件自动 DNS 验证失败,报 invalid domain。排查发现 CF API Token 的 Zone Resources 没配对,Token 在账号里看不到 jay.pub 这个 zone。

折腾几轮没搞定,决定绕过。

坑 2:泛域名不支持手动验证

acme.sh 的 --dns 手动模式不支持泛域名证书(*.jay.pub),只支持具体域名。先签 jay.pub + www.jay.pub,泛域名以后再补。

acme.sh --issue -d jay.pub -d www.jay.pub --dns \
  --yes-I-know-dns-manual-mode-enough-go-ahead-please \
  --server letsencrypt --keylength ec-256

acme.sh 输出 2 条 TXT 记录,手动去 CF 后台加:

名称 类型 内容
_acme-challenge TXT 随机字符串1
_acme-challenge.www TXT 随机字符串2

注意:TXT 记录的云朵必须点成灰色(DNS only),不能走 CF 代理,否则验证失败。

dig 验证传播后 --renew 完成签发。Let's Encrypt 证书,有效期 90 天,acme.sh 会自动续。

坑 3:nginx http2 语法

nginx 1.24 不支持 http2 on; 指令(那是 1.25.1+ 的语法),要用旧写法:

listen 443 ssl http2;  # 旧语法,1.24 可用
# 而不是
listen 443 ssl;
http2 on;  # 新语法,1.25.1+ 才支持

5. CF 回源 IP 修正

证书装好,nginx 443 配置完成,但通过 CF 访问还是 522(CF 连不上源站)。

排查发现:CF 后台 jay.pub 的 DNS 记录里,IP 还是旧服务器的。改成新服务器 IP 后立即恢复。

总耗时:33 分钟,从决策迁移到 HTTPS 恢复。

防护现状

迁移到 CF 代理后,攻击者只能看到 CF 的 IP,打的是 CF 边缘节点。CF 全球分布式架构 + 无限流量 DDoS 防护扛住,源站不受影响。

CF 后台记录了多次防护事件,攻击仍在持续但已被挡住。

损失

直接损失

  • 旧服务器封禁 24-72 小时
  • 旧源 IP 泄露,即使解封也不能再用作博客源站
  • 所有登录 session 失效(SESSION_SECRET 换了新值)
  • 用户上传的图片未同步(待旧机器解封后补)

间接损失

  • 站点在 Google 重新评估期间被打掉,可能影响排名恢复
  • 访问用户遇到 522/超时,可能流失
  • 从凌晨十二点半折腾到一点半,本该睡觉

经验教训

1. 不要裸奔上公网

个人站点、小项目,一定要上 Cloudflare 代理。免费版足够挡住绝大多数 DDoS。源 IP 一旦暴露,就是被持续攻击的把柄。

正确做法:DNS 解析直接走 CF,橙色云朵代理。源站不暴露公网 80/443 的真实可达性。

2. 友链交换是高危操作

不要在陌生友链平台暴露站点信息。攻击者可能潜伏在这些平台,专门挑新站下手——动机可能是恶意竞争、勒索、纯破坏。

正确做法:

  • 友链通过熟人/同行私下交换
  • 或在知名社区(V2EX、GitHub)找可信对象
  • 不要在「友链交换平台」批量提交站点信息

3. 轻量服务器的 DDoS 防护是假的

某云厂商轻量应用服务器的「DDoS 防护」本质是封你的机器,不是清洗流量。攻击一来,它先自保(封机器保护其他用户),你的站点就成了牺牲品。

正确做法:

  • 不能依赖云厂商的轻量 DDoS 防护
  • 必须前置一层 CF(或专业清洗服务)
  • 源站只允许 CF IP 段访问

4. 备份和快速迁移能力是刚需

这次能在 33 分钟内恢复,靠的是:

  • 本地有完整代码仓库(git)
  • 交叉编译一条命令出二进制
  • 部署清单清晰(二进制 + 模板 + 资源 + .env + version.json)
  • 数据库独立部署,不受 Web 服务器影响

如果代码只在被封的机器上,或数据库跟 Web 混部,恢复时间会指数级增长。

5. 文档化部署架构救命

桌面有完整的部署文档:四机架构、内网 IP、凭据、systemd 配置、nginx 配置。迁移时直接照搬,不用现场猜。

正确做法:每次架构变更都更新文档,凭据、IP、端口、配置文件路径全部记录。

防护加固

迁移完成后,继续做了几层加固,确保源站 IP 不泄露、即使泄露也打不动。

1. 吊销 Let's Encrypt 证书

之前用 acme.sh 签的 LE 证书会上报 CT log(Certificate Transparency),任何人都能在 crt.sh 查到「jay.pub 曾经签过 LE 证书」。虽然 CT log 不记录 IP,但攻击者可以用证书指纹在 Censys 历史快照里反查源 IP。

立即吊销:

acme.sh --revoke -d jay.pub --ecc
rm -rf ~/.acme.sh/jay.pub_ecc /etc/nginx/ssl

CT log 记录不可删除,但证书已失效(OCSP revoked),扫描器即使抓到也无效。

2. 改用 Cloudflare Origin CA 证书

CF 后台生成 Origin CA 证书,15 年有效期,SAN 覆盖 *.jay.pub + jay.pub。这个证书不上报 CT log,扫描器扫不到。

CF SSL 模式切换为 Full (strict),CF 验证源站证书链,端到端加密。

踩坑:第一次生成的「客户端证书」没有 SAN,strict 模式报 526。重新生成「源证书」时 Hostnames 填 jay.pub,*.jay.pub,SAN 才正确。526 排查三要素:证书有效期、SAN 匹配、证书链完整。

3. 腾讯云安全组只放行 CF IP 段

最关键的一步。CF 公布了 15 个 IPv4 段 + 7 个 IPv6 段,安全组规则只放行这些网段访问 80/443,其他全部拒绝。

来源              协议  端口        策略  备注
CF IPv4/IPv6 段   TCP   80,443     允许  CF 回源
内网网段          ALL   ALL        允许  内网互通
0.0.0.0/0         TCP   22,80,443  拒绝  兜底拒绝公网

效果:攻击者即使知道源 IP,直接打 443 端口,包在网络层被丢弃,TCP 都建立不了,不触发云厂商清洗,不封机器

重要:云厂商官方明确说「防火墙不能代替 DDoS 防护,非许可 IP 也会触发清洗」。但安全组在网络层丢包,流量根本不到机器,清洗阈值不会触发。这是对的说法。

4. SSH 改内网跳板

公网 22 端口封闭,通过其他同内网机器跳板。本地 ~/.ssh/config 配置:

Host blog-server
    HostName <内网IP>
    User ubuntu
    ProxyJump <跳板机>

ssh blog-server 自动通过跳板机访问。

防护层级总结

攻击者 → CF IP(Anycast 全球节点)
            ↓ CF DDoS 防护 + WAF + Bot Fight
            ↓ CF 边缘证书
            ↓ 回源(加密,CF Origin CA 证书)
         源站
            ↓ 腾讯云安全组(只放行 CF IP 段)
            ↓ nginx CF 白名单(第二道防线)
            ↓ Go 后端

三层防护 + 证书不暴露,源 IP 即使泄露也打不动。

时间线

时间 事件
00:43 发现机器被封,决策迁移
00:43 开新机器,配 SSH
00:45 交叉编译,装 nginx
00:48 上传文件,systemd 启动,后端恢复
00:54 CF DNS 切换,开启代理
00:59 CF API Token 折腾(权限错误)
01:09 改用手动 DNS 验证
01:11 Let's Encrypt 证书签发成功
01:11 nginx 443 配置 + HTTP 跳转
01:16 CF 回源 IP 修正,HTTPS 恢复
01:17 第二波攻击,CF 拦截
01:24 第四波攻击,CF 拦截
01:30 腾讯云安全组配 CF IP 白名单
01:40 安全组生效,源站直连超时
01:46 SSH 改内网跳板
01:52 吊销 LE 证书 + 清理残留
01:58 部署 CF Origin CA 证书(15 年)
02:08 CF SSL 切 Full (strict),验证通过

感想

生气。

凌晨一点,刚把 Lighthouse 跑到全满分,正准备收工睡觉,去交换个友链就被打。一个小博客,没什么商业价值,没什么流量,没有广告没有收费服务,纯用爱发电的站点,就是想认真写点东西,也能被人盯上。

攻击成本太低,防御成本太高。一台 2C2G 的轻量服务器被打一下就被封 24 小时,攻击者可能只是租了个肉鸡随便扫。

但 Cloudflare 救命了。免费版无限流量 DDoS 防护,源 IP 隐藏,全球 CDN 加速。如果没有 CF,这次只能等云厂商解封,然后被持续攻击,循环到放弃。

这次被打了17.48Gbps,只用了不到十秒...而我服务器清洗能力只有2Gbps...

最后——

移除了 Herobrine。

← 查看上一篇:从 Google 降权到 Lighthouse 满分:一次博客 SEO 排查实录
查看下一篇:CF 扛住了 DDoS,但 CC 还在回源