有人悄悄登了你的 VPS?用 Telegram Bot / 微信 Server酱 打造登录与宕机实时警报

有人悄悄登录了你的 VPS 你却毫不知情?黑客爆破成功的第一时间收到警报才能止损。本文手把手教你用 Telegram Bot 或微信 Server酱 / PushDeer,通过修改 /etc/pam.d/sshd,实现 SSH 登录、宕机与资源告警的实时推送到手机,附完整脚本。

延伸阅读

更多相关攻略推荐:Ollama AI系列(2):VPS上的AI推理与API应用Ollama AI系列(2):VPS上的AI推理与API应用【CPU选型 01】搭载 AMD Ryzen 9950X 的 VPSARM / Ampere 席卷 VPS:性价比真香还是兼容陷阱?Ollama AI系列(2):VPS上的AI推理与API应用

一、为什么你一定要给 VPS 装个"登录报警器"

先说个扎心的事实:只要你买了一台面向公网的 VPS,并且开着 SSH(端口 22),你的机器基本从开机那一刻起就一直在被路人扫描。那些自动化的爆破脚本,会拿着成百上千个常见弱密码,对着全网的 IP 段一遍遍尝试登录。你没看错,这不是夸张,是每天每夜都在发生的事。

很多新手觉得:"我密码够复杂,怕什么。"但问题是,密码再复杂,你也没法保证哪天某个服务的漏洞被爆出来,或者你手滑把密钥权限设成了 644,又或者运维小伙伴的电脑中了木马。一旦真的有人登录成功,而你毫无察觉,那台机器可能几分钟内就变成了别人的肉鸡:挂挖矿、做跳板、发垃圾邮件,甚至拿去攻击别人。

真正的止损窗口,就是"登录发生后的那几秒"。如果你能在有人成功登录的第一时间,在手机上收到一条带 IP、带时间的推送,你就有可能立刻改密码、封 IP、甚至直接关机排查。反过来,如果你要等服务器已经被用来发攻击流量、被机房拉黑了才发现,那就晚了,账号可能被封,钱也退不回来。

所以这篇文章要教你的,不是什么高深运维,而是一套便宜、简单、几乎零成本的"报警器":只要有人通过 SSH 登录你的 VPS,或者你的机器 CPU 飙到 100%、磁盘快满了,手机立刻弹消息。下面一步一步来。

二、原理其实特别简单:有人 SSH 登录,就触发一条消息

很多同学一听到"监控告警"就觉得要搭一套 Prometheus + Grafana,或者买个商业监控服务,吓得直接划走。其实完全不用。我们用的思路就一句话:让系统在"登录成功"这个动作发生时,顺手帮你发条消息。

Linux 的登录流程走的是 PAM(Pluggable Authentication Modules,可插拔认证模块)。SSH 登录成功后,PAM 会进入"会话(session)"阶段,而这个阶段是可以挂外部脚本的。换句话说,我们往 PAM 配置里塞一行命令,告诉它:"每次开会话,顺便跑一下我这个脚本"。脚本里干的事也很朴素:拼一段文字(谁、从哪个 IP、什么时间登录的),然后用 curl 调一下 Telegram 或者微信的接口,把这段话发到你的手机上。

整套链路就三步:第一,搞一个能发消息的机器人;第二,写个发消息的小脚本;第三,把脚本挂到 PAM 上。下面我们分别拆开讲,每一步都会给可直接抄的命令。

三、第一步:先搞一个 Telegram Bot(30 秒搞定)

Telegram 的 Bot 接口对个人是完全免费的,也没有什么资质审核,这是它最香的地方。打开 Telegram,搜索 @BotFather(这是官方用来管理机器人的机器人,别搜错了),点进去发一条消息:

  • 发送 /newbot
  • 它会先问你机器人的"显示名称",随便起,比如 My VPS Alarm
  • 接着问"用户名",这个必须以 bot 结尾,比如 my_vps_alarm_bot
  • 确认后,BotFather 会回你一长串 token,长这样:123456789:AAExampleTokenStringHere

这个 token 就是你机器人的"密码",谁拿到它谁就能操控你的机器人,所以千万别贴到公开仓库、博客或者截图发群里。万一泄露了,回去给 BotFather 发 /revoke 就能作废旧 token、换新的一串。

拿到 token 后,先验证一下没敲错。在终端里执行:

  • curl https://api.telegram.org/bot你的TOKEN/getMe
  • 如果返回里 "ok": true,还带出你的 bot 信息,说明 token 没问题

这里有个冷知识:Telegram 的机器人不能主动给一个没找过它的人发消息。所以下一步,你得先去"撩"它一下,把它的 chat_id 拿到手,它才知道该往哪个会话推消息。

四、拿到 chat_id:机器人不能主动找你,得你先"撩"它

在 Telegram 里点开你刚创建的机器人,随便发一条消息,比如 "hello"。然后回到终端,执行:

  • curl https://api.telegram.org/bot你的TOKEN/getUpdates
  • 在返回的 JSON 里找 message.chat.id 这个数字,比如 5123456789

这个 chat.id 就是你的私人会话地址,记下来。如果你更想推到群里(比如把几台服务器的告警都汇总到一个群),那就把机器人拉进群,在群里发句话,再用同样的方法 getUpdates 读群聊的 chat.id,群聊的 id 是负数,正常,照用就行。

嫌手动解析 JSON 麻烦的话,也可以把机器人发给 @get_id_bot 之类的工具号,它会直接把你的 id 回给你,省事。但核心逻辑不变:先有会话,才有 chat.id。

五、写告警脚本:把登录的 IP、时间、用户名抓出来

现在写一个发消息的脚本,比如放到 /usr/local/bin/ssh_login_alert.sh。PAM 在调用脚本时会自动塞进来几个环境变量,我们直接用就行:

  • PAM_USER:登录的用户名,比如 root 或者 ubuntu
  • PAM_RHOST:登录来源的公网 IP,这是最关键的字段
  • PAM_SERVICE:服务名,这里通常是 sshd
  • PAM_TTY:终端类型,SSH 登录一般是 ssh

脚本大致长这样(把 TOKEN 和 CHAT_ID 换成你自己的):

  • #!/bin/bash
  • TOKEN="你的TOKEN"
  • CHAT_ID="你的CHAT_ID"
  • USER_NAME="${PAM_USER:-unknown}"
  • SRC_IP="${PAM_RHOST:-unknown}"
  • NOW=$(date '+%Y-%m-%d %H:%M:%S')
  • HOST=$(hostname)
  • TEXT="VPS 登录提醒:用户 $USER_NAME 从 $SRC_IP 于 $NOW 登录了 $HOST"
  • curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" -d "chat_id=$CHAT_ID" -d "text=$TEXT"

写完记得给执行权限:chmod 700 /usr/local/bin/ssh_login_alert.sh,并且把属主设为 root,避免被别的用户篡改。想先测试一下?可以手动模拟一次 PAM 调用:

  • sudo env PAM_USER=test PAM_RHOST=1.2.3.4 /usr/local/bin/ssh_login_alert.sh
  • 手机上如果立刻收到消息,说明脚本链路通了

小提示:有时候密钥登录下 PAM_RHOST 可能为空,稳妥起见脚本里可以拿 SSH_CONNECTION 变量兜底,把它的第一个字段也当成来源 IP,这样不会漏报。

六、挂到 PAM:改 /etc/pam.d/sshd

这一步是把脚本真正接进登录流程。先备份,宁可麻烦也别省:

  • sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
  • 确认 SSH 真的在用 PAM:sudo sshd -T | grep usepam,看到 usepam yes 再继续

然后编辑 /etc/pam.d/sshd,在文件末尾加一行:

  • session optional pam_exec.so /usr/local/bin/ssh_login_alert.sh

这里有两个坑要专门提醒你。第一,控制位一定要用 optional,而不是 required。optional 的意思是:就算这个脚本执行失败(比如网络抽风、Telegram 接口连不上),登录照样成功,不影响你正常进门。如果你手滑写成 required,而某天脚本出错,你就可能被自己挡在门外,进不去服务器了,那才叫尴尬。第二,改 PAM 的时候,一定保持一个已经登录的 SSH 会话不要关,万一配错至少还能从那个旧会话里救回来。

改完退出,再从另一台机器 SSH 登录一次,手机上应该马上弹出登录提醒。再去翻系统日志确认没报错:sudo journalctl -u ssh --since "10 min ago",搜 pam_exec 或者 telegram 关键字即可。

七、微信党怎么办:Server酱 / PushDeer 同样能推

不是所有人都用 Telegram,国内很多朋友更习惯微信。方案也简单,最省事的是 Server酱(ServerChan)。去 sct.ftqq.com 用 GitHub 登录,拿到一个 SendKey,然后用一行 curl 就能推到微信:

  • curl -X POST "https://sctapi.ftqq.com/你的SendKey.send" -d "title=VPS登录提醒" -d "desp=root 从 1.2.3.4 登录"
  • 接口返回 JSON 里 code 为 0 表示成功

注意几个细节:免费版每天只有 5 条额度,做登录告警完全够用,但别拿它刷屏;title 里不能带换行;desp 支持 Markdown,可以写好看点。如果你的 SendKey 是以 sctp 开头,要把地址换成 https://你的uid.push.ft07.com/send/你的SendKey.send,uid 是 sctp 和 t 之间的那串数字。

另一个选择是 PushDeer,它是国内开发者做的,接口是 https://api2.pushdeer.com/message/push,参数带 pushkey、text、desp,也能直接在 App 里收消息,还能作为 Server酱的通道来用。两个都行,看你手机里装哪个顺手。把上面脚本里的 curl 那行换成对应的微信接口,其余逻辑完全不变。

八、进阶:CPU 飙到 100%、磁盘快满,也给你报警

登录提醒只是开胃菜。你还可以顺手监控几个最要命的资源指标,用 crontab 每 5 分钟跑一次就行。逻辑很直白:

  • 磁盘:用 df 看根分区使用率,超过 90%(也就是剩余小于 10%)就告警
  • CPU:如果 1 分钟平均负载长期接近核心数,或者某个进程长时间占满单核,就告警
  • 内存:可用内存低于某个阈值,或者开始频繁用 swap,也提醒一下

这种脚本同样用 curl 调 Telegram 或 Server酱接口发消息,只是触发条件从"登录"变成了"指标越线"。举个例子,检查磁盘的片段可以是:用 df -P / 取出使用率数字,和 90 比较,大于就发"磁盘快满"的提醒。把它丢进 crontab:

  • */5 * * * * /usr/local/bin/vps_resource_check.sh

宕机怎么报?宕机时你自己的脚本当然跑不了,得靠外部。可以用免费的 Uptime Robot 或者 Uptime Kuma 这类监控,每隔一两分钟 ping 一下你 VPS 的端口,连续几次不通就往邮箱或微信推"服务器疑似宕机"。外部监控 + 内部告警,这套组合拳基本就把常见意外都罩住了。