拒绝流量焦虑!手把手教你用 Go 语言监控搬瓦工 VPS,Telegram 每日自动报备
📊 别再手动查流量了,让代码替你干活
作为一个经常折腾 VPS 的博主,最怕的不是服务器宕机,而是月底突然收到“流量耗尽”的邮件,尤其是像我这种手头好几台搬瓦工(BandwagonHost)机器的人。虽然后台也能看,但我这人记性差,总是忘记去查。为了治好这个懒癌,我最近写了一个简单的 Go 语言脚本,配置好后,它每天能像个贴身管家一样,准时向我的 Telegram 报告流量使用情况。
这个方案不仅轻量(编译出来就几 MB),而且不需要安装任何繁琐的依赖,非常适合放在低配置的机器或者 NAS 上长期跑。今天就把这个“偷懒”神器分享给大家,顺带讲讲核心代码的逻辑和部署技巧。
🛠️ 准备工作:我们需要哪些钥匙?
脚本运行后发送到 Telegram 的流量日报截图,直观展示剩余流量和百分比。
在开始写代码之前,我们得先准备好几把“钥匙”,用来解锁搬瓦工的数据和 Telegram 的发送权限。整个过程大概需要 5 分钟。
1. 搬瓦工 API 信息
登录搬瓦工的控制面板(KiwiVM),在左侧菜单栏找到 API 选项。这里你需要记下两个关键参数:
- VEID:这通常是一串数字,其实就在你浏览器地址栏或者后台首页就有显示。
- API Key:点击生成或查看,记得复制保存,这个就像是你的高级通行证。
2. Telegram Bot 令牌
- 在 Telegram 里搜索
@BotFather,发送/newbot按提示创建一个新机器人。 - 创建成功后,
BotFather会发给你一串Token,格式通常是123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11,这个非常关键。
3. 你的 Telegram Chat ID
- 机器人建好了,但机器人不知道要把消息发给谁。
- 在浏览器访问
https://api.telegram.org/bot<你的Token>/getUpdates(把 bot 后面的 token 换成你刚获取的)。 - 向你的新机器人发送任意一条消息(比如“你好”)。
- 刷新浏览器页面,在返回的 JSON 数据里找到
"chat":{"id":123456789,那个id数字就是我们要的Chat ID。
💻 核心代码解析:它是怎么工作的?
这里我们直接上 Go 语言的源码。为了让代码更整洁,我把配置项抽离到了 config.json 文件中,这样以后改时间或者换账号都不用重新编译代码。
完整的 main.go
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"
)
// Config 结构体用于映射 json 配置文件
type Config struct {
VEID string `json:"veid"`
APIKey string `json:"api_key"`
TGBotToken string `json:"tg_bot_token"`
TGChatID string `json:"tg_chat_id"`
CheckHour int `json:"check_hour"`
CheckMinute int `json:"check_minute"`
}
// 全局配置变量
var AppConfig Config
// BwhResponse 搬瓦工 API 返回的部分结构体
type BwhResponse struct {
PlanDataCounter int64 `json:"data_counter"` // 已用流量
PlanDataNextReset int64 `json:"data_next_reset"` // 流量重置时间
DataLimit int64 `json:"plan_monthly_data"` // 总流量限制
}
// loadConfig 从当前目录加载配置文件
func loadConfig() error {
file, err := os.Open("config.json")
if err != nil {
return fmt.Errorf("无法打开配置文件 config.json: %v", err)
}
defer file.Close()
bytes, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("无法读取配置文件: %v", err)
}
if err := json.Unmarshal(bytes, &AppConfig); err != nil {
return fmt.Errorf("解析配置文件 JSON 失败: %v", err)
}
return nil
}
func main() {
// 启动时先加载配置
if err := loadConfig(); err != nil {
fmt.Println("配置加载失败,程序退出:", err)
return
}
fmt.Println("搬瓦工流量监控服务已启动...")
// 启动时先执行一次检查
checkAndNotify()
// 循环定时任务
for {
now := time.Now()
// 计算下一次执行的时间(从配置中读取小时和分钟)
next := time.Date(now.Year(), now.Month(), now.Day(), AppConfig.CheckHour, AppConfig.CheckMinute, 0, 0, now.Location())
if next.Before(now) {
next = next.Add(24 * time.Hour)
}
fmt.Printf("下一次通知时间: %s\n", next.Format("2006-01-02 15:04:05"))
time.Sleep(next.Sub(now))
checkAndNotify()
}
}
// 核心逻辑:获取流量并发送通知
func checkAndNotify() {
fmt.Println("开始获取流量信息...")
// 1. 调用搬瓦工 API(动态使用 AppConfig 中的变量)
apiURL := fmt.Sprintf("https://api.64clouds.com/v1/getLiveServiceInfo?veid=%s&api_key=%s", AppConfig.VEID, AppConfig.APIKey)
resp, err := http.Get(apiURL)
if err != nil {
fmt.Println("调用搬瓦工 API 失败:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var bwhData BwhResponse
if err := json.Unmarshal(body, &bwhData); err != nil {
fmt.Println("解析 JSON 失败:", err)
return
}
// 2. 计算流量数据 (Bytes 转 GB)
totalGB := float64(bwhData.DataLimit) / 1024 / 1024 / 1024
usedGB := float64(bwhData.PlanDataCounter) / 1024 / 1024 / 1024
remainingGB := totalGB - usedGB
// 计算使用百分比
var usagePercent float64
if totalGB > 0 {
usagePercent = (usedGB / totalGB) * 100
}
resetTime := time.Unix(bwhData.PlanDataNextReset, 0).Format("2006-01-02")
// 3. 组装消息文本
message := fmt.Sprintf(
"📊 搬瓦工 VPS 流量日报\n\n"+
"🔹 总流量: %.2f GB\n"+
"🔸 已使用: %.2f GB (%.1f%%)\n"+
"✅ 剩余流量: %.2f GB\n"+
"📅 重置日期: %s",
totalGB, usedGB, usagePercent, remainingGB, resetTime,
)
// 4. 发送 Telegram 通知
err = sendTGMessage(message)
if err != nil {
fmt.Println("发送 TG 通知失败:", err)
} else {
fmt.Println("通知发送成功!时间:", time.Now().Format("15:04:05"))
}
}
// 发送 Telegram 消息的函数
func sendTGMessage(text string) error {
tgURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", AppConfig.TGBotToken)
formData := url.Values{
"chat_id": {AppConfig.TGChatID},
"text": {text},
"parse_mode": {"Markdown"},
}
resp, err := http.PostForm(tgURL, formData)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("TG API 返回错误码: %d, 原因: %s", resp.StatusCode, string(body))
}
return nil
}
代码逻辑简要分析
这段代码的逻辑其实非常清晰,主要分为三个部分:
- 配置加载 (
loadConfig):程序启动的第一件事,就是去读同目录下的config.json。如果文件不存在或格式写错了,程序会直接报错退出,避免后面运行出 bug。 - 定时循环 (
main):这里没有使用复杂的 cron 库,而是利用 Go 原生的time包。程序启动时会先立刻跑一次检查(验证配置是否正确),然后进入for无限循环。每次循环都会计算下一次触发的时间点(比如配置的是 21:00),然后time.Sleep休眠到那个时间点再执行。这样做的好处是资源占用极低,不像每秒轮询那样浪费 CPU。 - 数据获取与推送 (
checkAndNotify&sendTGMessage):这是心脏部分。它先发 HTTP 请求去搬瓦工 API 拿数据,把 Bytes 转换成 GB,算好百分比,最后拼成一段带 Emoji 的文本,POST 到 Telegram 的接口。
⚙️ 部署实战:五步上线服务
代码有了,接下来就是怎么让它跑起来。我们把上面的代码保存为 main.go,然后在同级目录下创建一个 config.json 文件。
第一步:编写配置文件
新建一个 config.json,把你刚才准备好的信息填进去:
{
"veid": "你的VEID",
"api_key": "你的API Key",
"tg_bot_token": "你的TG Bot Token",
"tg_chat_id": "你的TG Chat ID",
"check_hour": 21,
"check_minute": 0
}
*注意:check_hour 是 24 小时制,如果你想早上 9 点看,就改成 9。`
第二步:本地编译测试
确保你安装了 Go 环境(没安装的去 Go 官网下个安装包)。在终端输入:
go build -o bfw_monitor main.go
这会生成一个名为 bfw_monitor 的可执行文件(Windows 下是 .exe)。直接运行它试试:
./bfw_monitor # Linux/Mac
# 或者
bfw_monitor.exe # Windows
如果一切顺利,你的 Telegram 应该马上就能收到一条日报消息,终端里也会显示“下一次通知时间”。
第三步:后台长期运行(进阶篇)
总不能一直开个终端窗口挂着吧?如果你的机器是 Linux,推荐使用 systemd 来管理这个服务,这样开机自启、崩溃重启都能自动搞定。
创建一个服务文件:
sudo nano /etc/systemd/system/bwg-monitor.service
填入以下内容(注意修改路径):
[Unit]
Description=BandwagonHost Traffic Monitor
After=network.target
[Service]
Type=simple
User=root # 建议使用普通用户,但要注意文件权限
WorkingDirectory=/root/bwg_monitor # 切换到你程序所在的目录
ExecStart=/root/bwg_monitor/bfw_monitor # 程序的绝对路径
Restart=on-failure
[Install]
WantedBy=multi-user.target
保存后重载并启动:
sudo systemctl daemon-reload
sudo systemctl enable bwg-monitor.service
sudo systemctl start bwg-monitor.service
查看日志状态:
sudo systemctl status bwg-monitor.service
第四步(懒人版):直接下载成品
如果你觉得配置 Go 环境或者编译太麻烦,我也已经编译好了常用的版本(Linux 64位),你可以直接下载使用。不过,为了安全起见,建议你在虚拟机里先跑一跑,或者有能力的还是推荐自己源码编译。
(下载链接在文末)
🤔 常见问题与解决方案
Q: 提示“调用搬瓦工 API 失败”?
A: 检查一下你的 VEID 和 API Key 是否复制正确,有没有多余的空格。另外,搬瓦工 API 偶尔会抽风,如果是一次性报错,程序会等到下次时间点重试;如果一直报错,建议手动去浏览器访问一下 API 链接看看返回什么。
Q: Telegram 收不到消息?
A: 最常见的原因是 Chat ID 填错了。请再次确认 getUpdates 返回的 ID 是否正确。此外,确保你已经在 Telegram 里向机器人发送过至少一条消息,否则有些情况下机器人无法主动推送。
Q: 我想监控多个 VPS 怎么办?
A: 目前的代码是单进程的。如果你有多台机器,最简单的方法是复制几份代码和配置文件,放在不同的文件夹里,给每个可执行文件改个名,然后用 systemd 启动多个服务即可。稍微进阶一点的做法是修改 config.json 支持数组,然后遍历查询,但那样改动代码稍微多一点。
💡 总结
这个小小的脚本虽然代码量不大,但实用性非常强。它完美解决了“忘记查流量”这个痛点,而且 Go 语言编译后的二进制文件分发极其方便,不需要担心依赖库缺失的问题。
自动化运维往往就是从解决这些琐碎的小需求开始的。如果你是 VPS 重度用户,希望这个工具能帮你省点心。如果你有更好的想法,比如加上“流量使用率超过 80% 预警”之类的功能,欢迎在代码基础上魔改!

评论已关闭