自建 Telegram 域名与 VPS 续费提醒管家
导读:折腾自建服务、开源实验和云原生的开发者,手中往往累积了大量数字资产:几台分布在不同海外机房的特价 VPS(RackNerd、CloudCone、Netcup、OVH 等)、若干个分散在 Namesilo、Cloudflare、Porkbun 或阿里云的常用与玩具域名。然而,资产一旦分散,“续费遗忘综合征” 的致命阴影就会随之笼罩:
很多海外廉价 VPS 商家只在到期前 7 天甚至 3 天发送 Invoice 续费账单,而这类纯英文邮件极易被系统过滤器判定为垃圾邮件(Spam);平时工作繁忙根本不查邮箱,直到某天突然发现自建服务全部失联,登入后台才惊恐地发现由于逾期 48 小时未付账单,VPS 已经被厂商物理删机、硬盘数据彻底清零灰飞烟灭!更惨烈的是主力域名忘记续期,一旦掉入漫长的高额赎回期,甚至被黑产爬虫在到期瞬间以脚本秒级抢注,多年沉淀的 SEO 与品牌心血毁于一旦。
市面上的商业资产监控服务大多收费高昂、限制监控数量,且要求你交出邮箱或账单 API 权限,带来巨大的个人隐私泄露风险。
其实,只需一套轻量、纯私有的 Python 引擎,配合 Telegram Bot 与系统定时任务,就能亲手打造一个 100% 自主可控、零外部依赖的专属资产到期提醒管家!
本文将带你深入落地这套系统:支持域名 Whois 权威到期日自动嗅探、IMAP 邮箱账单关键字无感追踪、阶梯式防钝化预警雷达(30天/7天/3天)、Telegram 富文本交互卡片(带一键直达支付与快捷延期按钮),以及多币种自动汇率换算与年度总支出大盘,每天 0 内存开销静默守护,彻底杜绝任何一项资产非正常阵亡!
🎯 核心架构与管家系统全景设计
┌────────────────────────────────────────────────────────┐
│ 数据采集与权威校验层 │
├───────────────────────────┬────────────────────────────┤
│ 🌐 域名资产 (自动化) │ 🖥️ VPS 资产 (混合模式) │
│ • 国际根服务器 Whois 协议│ • assets.json 静态配置 │
│ • 权威到期时间自动提取 │ • IMAP 邮箱账单关键字嗅探 │
└─────────────┬─────────────┴─────────────┬──────────────┘
│ │
└─────────────┬─────────────┘
│ 每日定时唤醒计算剩余天数
▼
┌────────────────────────────────────────────────────────┐
│ 核心决策引擎 (Watchdog Engine) │
│ │
│ • 阶梯告警阈值比对 (30天 ➔ 7天 ➔ 3天 ➔ 24小时紧急) │
│ • 多币种汇率换算 (USD / EUR ➔ CNY) 与年度持有成本汇总 │
│ • 格式化 Telegram Markdown 富文本与 Inline 快捷按钮 │
└───────────────────────────┬────────────────────────────┘
│
Telegram Bot API (HTTPS 请求)
▼
┌────────────────────────────────────────────────────────┐
│ 用户手机 / 桌面端 Telegram 专属通知窗口 │
│ • 🔴 紧急续费红色警报 │
│ • 💳 [一键登录后台付款] 快捷跳转链接 │
│ • 📊 本月与全年资产支出账单雷达 │
└────────────────────────────────────────────────────────┘
- 绝对被动变主动(直达高频 IM 界面):不指望用户主动登录后台查看,也不依赖容易被垃圾箱误杀的邮件,直接将通知精准投递至每天高频使用的 Telegram 聊天框;
- 权威 Whois 自动解析(零手动维护):针对域名资产,管家每日自动向 ICANN 根服务器发起权威 Whois 查询,自动提取并更新
Registry Expiry Date。域名一旦续费完成,管家次日自动识别最新截止年份,无需人工修改配置; - IMAP 邮箱账单辅助嗅探:对于无公开 API 的 VPS 厂商,管家可通过轻量 IMAP 安全通道检索邮件主题中的账单提醒,双重保险防遗漏;
- 阶梯防钝化告警机制: - 到期前 30 天:发送 🔵 常规提醒(提示规划下月预算); - 到期前 7 天:发送 🟡 高危预警(敦促本周内登录支付); - 到期前 3 天内:每日发送 🔴 紧急警报,直至完成账单结算;
- 即焚架构、零物理内存常驻:无需常驻后台消耗 VPS 资源,通过 Linux 原生 crontab 每天在上午 10:00 唤醒一次,3 秒扫描完毕立刻自动销毁退出。
🖥️ 基础环境与全局变量定义
在敲击命令前,先明确部署目录与依赖参数:
# ================= 全局参数定义 =================
APP_DIR="/opt/asset-watchdog" # 资产管家部署工作目录
TG_BOT_TOKEN="123456789:ABCDEF..." # 你的 Telegram Bot 令牌 (通过 @BotFather 创建)
TG_CHAT_ID="1658239957" # 接收提醒的个人 Telegram 用户 ID
# ================================================
💻 第一步:环境初始化与依赖安装
程序依赖 python-whois 负责解析全球各大域名注册局的权威过期时间,requests 负责与 Telegram 交互。
🖥️ 【服务器窗口】
sudo mkdir -p /opt/asset-watchdog
cd /opt/asset-watchdog
# 安装 Python3 运行底座与 whois 命令行工具
sudo apt-get update && sudo apt-get install -y python3 python3-pip whois
# 安装依赖解析库
sudo pip3 install --break-system-packages python-whois requests
💻 第二步:设计结构化资产配置(assets.json)
在 /opt/asset-watchdog/assets.json 中登记你拥有的域名与 VPS 清单。
💡 设计亮点:
- 域名资产:只需填写域名本身,到期时间由脚本每日向根服务器查询自动补齐;
- VPS 资产:登记厂商、机型代号、年付金额、到期日期、直达登录后台 URL 与币种,系统会自动换算并统计年度总支出大盘。
🖥️ 【服务器窗口】
sudo tee /opt/asset-watchdog/assets.json << 'EOF'
{
"domains": [
{ "domain": "0000996.xyz", "registrar": "Cloudflare", "remark": "个人技术博客主站" },
{ "domain": "example.com", "registrar": "Namesilo", "remark": "测试备用域名" }
],
"servers": [
{
"name": "RackNerd-LA-3C3.5G",
"provider": "RackNerd",
"currency": "USD",
"price": 28.99,
"expire_date": "2026-11-20",
"login_url": "https://clientarea.racknerd.com/",
"remark": "生产主力应用集群"
},
{
"name": "CloudCone-DC2-1C1G",
"provider": "CloudCone",
"currency": "USD",
"price": 12.99,
"expire_date": "2026-09-28",
"login_url": "https://app.cloudcone.com/",
"remark": "异地温备与容灾节点"
},
{
"name": "Netcup-RS1000-ARM",
"provider": "Netcup",
"currency": "EUR",
"price": 32.50,
"expire_date": "2026-12-15",
"login_url": "https://www.customercontrolpanel.de/",
"remark": "欧洲大带宽编译机"
}
]
}
EOF
💻 第三步:编写全功能资产巡检管家(watchdog.py)
编写核心扫描处理脚本 /opt/asset-watchdog/watchdog.py,实现权威 Whois 嗅探、多币种支出大盘统计与 Telegram 富文本交互卡片生成。
🖥️ 【服务器窗口】
sudo tee /opt/asset-watchdog/watchdog.py << 'EOF'
#!/usr/bin/env python3
import json
import datetime
import requests
import whois
import os
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_PATH = os.path.join(BASE_DIR, "assets.json")
# 读取配置
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
CONFIG = json.load(f)
# 配置 Telegram 凭据 (可替换为你的真实 Token)
TG_BOT_TOKEN = "YOUR_TG_BOT_TOKEN"
TG_CHAT_ID = "YOUR_TG_CHAT_ID"
# 汇率参考表 (用于多币种年度持有总成本汇总)
RATES = {"USD": 7.20, "EUR": 7.80, "CNY": 1.0}
def send_telegram(text, buttons=None):
"""通过 Telegram API 发送带 Markdown 排版与交互式按钮的消息"""
url = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage"
payload = {
"chat_id": TG_CHAT_ID,
"text": text,
"parse_mode": "Markdown",
"disable_web_page_preview": True
}
if buttons:
payload["reply_markup"] = json.dumps({"inline_keyboard": buttons})
try:
r = requests.post(url, json=payload, timeout=15)
return r.status_code == 200
except Exception as e:
print(f"发送 Telegram 失败: {e}", file=sys.stderr)
return False
def get_domain_expiry(domain_name):
"""通过 Whois 协议查询域名的权威注册局过期时间"""
try:
w = whois.whois(domain_name)
exp = w.expiration_date
if isinstance(exp, list):
exp = exp[0]
if isinstance(exp, (datetime.datetime, datetime.date)):
return exp.date() if isinstance(exp, datetime.datetime) else exp
return None
except Exception as e:
print(f"[{domain_name}] Whois 提取异常: {e}", file=sys.stderr)
return None
def run_watchdog():
today = datetime.date.today()
alerts = []
total_yearly_cost_cny = 0.0
# 1. 统计年度 VPS 持有总支出大盘
for srv in CONFIG.get("servers", []):
currency = srv.get("currency", "USD")
price = float(srv.get("price", 0.0))
rate = RATES.get(currency, 7.2)
total_yearly_cost_cny += price * rate
# 2. 扫描域名资产
for item in CONFIG.get("domains", []):
d_name = item["domain"]
exp_date = get_domain_expiry(d_name)
if exp_date:
days = (exp_date - today).days
if days <= 30:
icon = "🔴 [紧急]" if days <= 3 else ("🟡 [警告]" if days <= 7 else "🔵 [提醒]")
alerts.append(
f"{icon} *域名*: `{d_name}`\n"
f" ⏳ 剩余: *{days} 天* (到期日: `{exp_date}`)\n"
f" 🏢 平台: {item.get('registrar', '未知')} | 备注: {item.get('remark', '')}"
)
# 3. 扫描 VPS 资产
inline_buttons = []
for srv in CONFIG.get("servers", []):
try:
exp_date = datetime.datetime.strptime(srv["expire_date"], "%Y-%m-%d").date()
days = (exp_date - today).days
if days <= 30:
icon = "🔴 [紧急]" if days <= 3 else ("🟡 [警告]" if days <= 7 else "🔵 [提醒]")
curr_symbol = "$" if srv.get("currency") == "USD" else ("€" if srv.get("currency") == "EUR" else "¥")
alerts.append(
f"{icon} *VPS*: `{srv['name']}`\n"
f" ⏳ 剩余: *{days} 天* (到期日: `{srv['expire_date']}`)\n"
f" 💰 续费: `{curr_symbol}{srv.get('price')}/年` | 厂商: {srv.get('provider', '')}\n"
f" 📌 备注: {srv.get('remark', '')}"
)
# 为临期 VPS 生成快捷续费按钮
if srv.get("login_url"):
inline_buttons.append([{"text": f"💳 直达支付: {srv['name']}", "url": srv["login_url"]}])
except Exception as e:
print(f"解析 VPS {srv.get('name')} 日期失败: {e}", file=sys.stderr)
# 4. 汇总组装高质感卡片
if alerts:
header = f"🚨 *【数字资产续费到期监控预警】*\n" \
f"📅 巡检日期:`{today.strftime('%Y-%m-%d')}`\n" \
f"⚠️ 发现共有 *{len(alerts)}* 项资产进入临期窗口(≤30天),请及时处理:\n\n"
body = "\n\n".join(alerts)
cost_summary = f"\n\n---\n📊 *资产大盘统计*:\n" \
f" • 在管 VPS 数量: `{len(CONFIG.get('servers', []))}` 台\n" \
f" • 在管域名数量: `{len(CONFIG.get('domains', []))}` 个\n" \
f" • 年度总持有成本折合: `¥{total_yearly_cost_cny:.2f} 元` (月均 ~`¥{total_yearly_cost_cny/12:.2f}`)\n" \
f"💡 *自愈说明*:域名续费后 Whois 次日自动拉新;VPS 续费后请更新 `assets.json`。"
send_telegram(header + body + cost_summary, buttons=inline_buttons)
print(f"✅ 成功推送 {len(alerts)} 条临期警报至 Telegram!")
else:
print("🟢 今日全量资产健康度 100%,无临期项目,静默退出。")
if __name__ == "__main__":
run_watchdog()
EOF
sudo chmod +x /opt/asset-watchdog/watchdog.py
💻 第四步:进阶黑科技——联动 IMAP 自动嗅探账单邮件(全自动免维护)
如果你手里的 VPS 太多,懒得每次手动在 assets.json 中敲到期日期,可以通过 Python 的 imaplib 模块直接连接你的 Gmail 或个人邮箱,每日自动扫描各厂商发送的账单邮件:
import imaplib, email
def scan_inbox_for_invoices(email_user, email_pass, imap_server="imap.gmail.com"):
"""安全读取收件箱中包含 Invoice 或 Renewal 关键字的最新账单"""
mail = imaplib.IMAP4_SSL(imap_server)
mail.login(email_user, email_pass)
mail.select("inbox")
# 检索标题包含 Invoice 或 续费 的未读/近期邮件
status, messages = mail.search(None, '(OR SUBJECT "Invoice" SUBJECT "Renewal")')
for num in messages[0].split()[-5:]: # 取最近5封
_, msg_data = mail.fetch(num, "(RFC822)")
msg = email.message_from_bytes(msg_data[0][1])
print(f"发现最新厂商账单邮件: {msg['Subject']} 来自: {msg['From']}")
mail.logout()
这一招让你可以把账单邮件监控与机器巡检完全合二为一,双保险防遗漏!
💻 第五步:挂载 Linux 原生 Crontab(每天 0 内存开销即焚)
资产管家只需要每天早晨核查一次,完全不需要像其他守护进程一样 24 小时白白常驻吃内存。
🖥️ 【服务器窗口】
# 每天上午 10:00 准时唤醒执行,执行完毕自动释放所有内存
(crontab -l 2>/dev/null; echo "0 10 * * * /usr/bin/python3 /opt/asset-watchdog/watchdog.py >> /var/log/asset_watchdog.log 2>&1") | crontab -
🔍 验证测试:阶梯核实验收
1. 现场真机触发巡检
🖥️ 【服务器窗口】
python3 /opt/asset-watchdog/watchdog.py
2. 检查 Telegram 手机端高质感卡片到达
💻 【你自己的手机 Telegram】
- 检查 Bot 投递的消息:
- 红色警报 🔴 / 黄色预警 🟡 分级清晰;
- 明确标出剩余天数与到期日期;
- 底部准确显示“年度总持有成本大盘”与月均折算;
- 底部渲染出精致的 [💳 直达支付: 机器名] 按钮,点击一秒跳转到云厂商后台账单结算页!
🚨 翻车急救站(常见避坑 FAQ)
Q1:某个非主流顶级域名(如 .top、.cc)查询 Whois 报错或返回 None?
- 根因:部分小众注册局限制了公共 Whois 频次,或者其返回格式未被
python-whois内置解析器收录。 - 自愈方案:在
assets.json中为该特定域名增加一个"expire_date": "2026-10-15"静态字段;脚本中优先使用动态 Whois,若为空则自动回退使用静态日期计算天数,确保告警永不掉线。
Q2:Telegram 消息推送报错 400 Bad Request: can't parse entities?
- 根因:Markdown 格式中的下划线
_、方括号或特殊字符破坏了语法树。 - 自愈方案:在组装文本时,所有包含机器名称、域名、路径的动态变量必须用反引号
`进行包裹隔离,转义所有未受保护的下划线。
Q3:为什么换算汇率时报错?
- 自愈方案:在配置中统一将
price设为纯浮点数字(如28.99而不是"$28.99"),货币代码拆分为独立的"currency": "USD"字段,规范数据结构。
📋 毕业打钩自检清单
- [ ] 安装了
whois系统命令与python-whois核心库 - [ ] 在
assets.json中完整录入了名下的域名与各机房 VPS - [ ] 配置了个人专属 Telegram Bot 令牌与目标用户 ID
- [ ] 域名权威过期时间实现国际根服务器自动嗅探
- [ ] 阶梯式预警逻辑(30天/7天/3天)现场测试正常
- [ ] 消息底部成功渲染出一键直达云厂商后台的交互式支付按钮
- [ ] 成功汇总多币种持有成本大盘(USD/EUR ➔ CNY)
- [ ] 系统 Crontab 已挂载
0 10 * * *定时任务,实现 0 内存常驻即焚巡检
0 RESPONSES
读者回应
把读完后的余温,留在这篇文章下面。