想让攻击拦截、带宽突增、源站挂掉这些事第一时间弹到手机上,Telegram 是运维群里最省事的落点。但具体怎么接,取决于你手里的 CDN 控制台长什么样,先做这一步判断,能省掉大半工作量:
- 控制台的通知/监控页里有 Telegram 选项:填 Bot Token 和 Chat ID,勾事件,结束。不需要服务器,不需要写代码。
- 只有「通用 Webhook」或「自定义回调 URL」:Cloudflare、AWS、阿里云这类平台发出的 JSON 报文和 Telegram Bot API 的入参不兼容,中间必须加一层转换(Workers、Lambda 或一个小容器)。
- 既没有 Webhook,只有日志下载或 OpenAPI:那就不是「推送告警」,而是「定时拉数据再发」,写个定时脚本聚合后发到频道。
三条路径的 Telegram 侧准备工作是一样的,先做完这一步。
第一步:拿到 Bot Token 和 Chat ID
- 在 Telegram 里搜
@BotFather,发/newbot,按提示起名字和用户名,拿到形如123456789:ABC-DEF1234ghIkl...的 HTTP API Token。这串东西等同密码,别写进 Git 仓库。 - 建一个运维群,把机器人拉进去。群里如果开了隐私模式或限制发言,要确认机器人有发消息权限。
- 取 Chat ID:在群里随便发一条消息(这一步不能省,没有新消息
getUpdates返回空),然后浏览器打开https://api.telegram.org/bot<TOKEN>/getUpdates,在返回的 JSON 里找chat.id。群组 ID 是负数,超级群通常以-100开头,照抄,别把负号丢了。也可以把@RawDataBot拉进群直接看它回显的 ID。 - 验证通道:
curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id="-1001234567890" \
-d text="CDN告警通道测试"返回 "ok":true 就说明 Token、Chat ID、权限三者都对。如果这一步在国内服务器上执行失败,不是配置问题——api.telegram.org 在境内直连通常不通,后面中转服务必须放在海外节点,这点下面还会提。

路径一:控制台原生绑定(有就优先用)
一些偏防护方向的 CDN 平台把 Telegram 做成了内置通知渠道,控制台里直接有 Bot Token 和 Chat ID 两个输入框,下面是事件勾选框:DDoS/CC 攻击触发、带宽或 QPS 超阈值、源站不可达、证书状态等。填完保存,一般会有「发送测试消息」按钮。
这条路的价值不在省那几十行代码,而在于:告警内容是平台按事件类型排版好的结构化文本,攻击类型、触发规则、目标域名、时间窗口都在里面;同时不用再维护一台中转机器,也就没有「中转挂了但没人知道」的盲区。如果你正在选型,这项能力值得在试用阶段就验证——RockCloud 的日志面板与 Telegram 数据推送就属于控制台内置,接入后可以在免费测试期间直接把告警通道配好再决定是否上生产,具体材料和接入顺序可以参考高防CDN怎么申请免费测试。
配置完别急着走,做一次真实触发验证:把源站健康检查的目标端口临时关掉,看群里几秒内有没有消息。只按「测试发送」按钮,验证的只是 Token 对不对,不代表事件规则真的会触发。
路径二:通用 Webhook + 一层转换
如果控制台只给你一个「Webhook URL」输入框,就必须自己搭转换层。原因很简单:Telegram 的 sendMessage 要求 POST body 里必须有 chat_id 和 text 两个字段,而 CDN 发出来的是它自己定义的告警 JSON,直接把 Telegram API 的 URL 填进 Webhook 输入框,只会收到 400。
转换层用 Cloudflare Workers 最省事,不用管机器,而且天然在海外。核心逻辑就这么点:
export default {
async fetch(request, env) {
const e = await request.json();
// 按你的 CDN 实际字段名改这几行
const text =
`⚠️ ${e.alert_type || 'CDN 告警'}\n` +
`域名: ${e.zone_name || e.domain || '-'}\n` +
`级别: ${e.severity || '-'}\n` +
`时间: ${new Date().toISOString()}\n` +
`详情: ${(e.text || JSON.stringify(e)).slice(0, 800)}`;
const r = await fetch(
`https://api.telegram.org/bot${env.BOT_TOKEN}/sendMessage`,
{
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ chat_id: env.CHAT_ID, text }),
}
);
return new Response(r.ok ? 'ok' : 'fail', { status: r.ok ? 200 : 502 });
},
};几个容易踩的点:
- Token 放环境变量,别硬编码在脚本里,Workers 用 Secret,Lambda 用环境变量或密钥管理。
- 别急着开
parse_mode。用 Markdown 或 HTML 排版时,告警文本里一旦出现_、*、<、未闭合的反引号(URL 和 UA 里很常见),Telegram 会直接返回 400,告警反而发不出去。要排版就老老实实做转义,或者先用纯文本跑稳。 - 给 Webhook URL 加个随机路径或校验参数,否则任何人都能往你的运维群灌消息。
- 截断长度。单条消息上限 4096 字符,原始 JSON 里塞一堆日志字段会超限,先
slice。 - 转发失败要有兜底:Telegram 侧返回非 200 时,把原始报文写进日志或另一个通道,别让错误静默消失。
路径三:定时聚合,发日报而不是发告警
流量消耗、缓存命中率、Top 访问 URL、Top 拦截 IP 这类数据不属于「事件」,Webhook 不会推,得自己拉:用 CDN 的日志转储(Logpush 之类)或 OpenAPI 查指标,用 Python/Node 脚本按小时或按天聚合,再调 sendMessage 发到一个单独的「日报频道」。
把日报和告警分到两个群,是个很实用的习惯——告警群保持安静,一响就是真事;日报群随便翻,不打扰值班的人。日报里值得放的通常是:昨日总带宽与峰值时间点、命中率变化、5xx 占比、拦截请求量 Top 来源。真要追查某个异常点,还是回控制台看细节,路径可以参考CDN控制台怎么看流量和网络日志。
绕不开的两件事:限速和告警风暴
Telegram 有硬性速率限制。 同一个群通常每秒只允许发 1 条,跨聊天合计约每秒 30 条。平时无所谓,问题出在 CC 攻击或源站批量 5xx 的时候:规则被反复触发,一分钟几百条告警,超限后 Bot API 返回 429 Too Many Requests,后面的消息要么被丢,要么排队几分钟才到——恰恰是最需要看到告警的时刻,通道哑了。
所以推送服务必须自带收敛,至少做到:
- 按指纹去重:
域名 + 事件类型 + 级别作为 key,存在 KV/Redis 里,同一 key 在 5 分钟窗口内只发首条,后续只累加计数。 - 窗口末尾补一条汇总:「过去 5 分钟同类告警 318 次,峰值 QPS xxx」,比 318 条刷屏有用得多。
- 恢复也要发:只发触发不发恢复,群里永远不知道事情过去了没有,值班的人只能自己去控制台确认。
- 处理 429:读响应里的
retry_after,按它退避重试,别原地重发加剧限流。
中转服务必须在海外。 国内服务器直连 api.telegram.org 存在出境连通性限制,本地跑得好好的脚本部署到境内机器上就会超时。Workers、海外 VPS、境外区域的 Lambda 都可以,别把这层放在被防护的源站上——源站被打瘫的时候,告警也跟着一起没了。
上线前的最后三个动作
- 演练一次真实触发,不是点测试按钮。关掉一个源站端口、或用压测工具打一下受保护路径,确认消息真的到群里,且内容能看懂是哪个域名、哪条规则。
- 加一条心跳。每天固定时间发一条「通道正常」,Bot 被误踢出群、Token 被重置、中转欠费这些故障,否则只有下次出事时才会发现。
- 分级分群。攻击触发、源站不可达这类需要立刻响应的进值班群并开提示音;带宽阈值、证书 30 天到期这类进普通群。所有事件塞同一个群,两周之后大家就会把它静音,推送也就白做了。
真遇到攻击已经开始、告警还没配好的情况,顺序要反过来——先按网站被DDoS攻击了怎么快速恢复访问把访问恢复,再回头补通知链路。
评论(0)