Linux 自動化 Telegram Bot Python 監控 伺服器管理

用 Telegram Bot 把伺服器狀態推到手機:從建立 Bot 到監控通報

磁碟快滿、服務掛掉、備份失敗——這些事情你不應該等到使用者反映才知道。用 Telegram Bot API 配合 Python 或 Bash,把伺服器監控通報推到手機,設定過程不超過 30 分鐘。

伺服器監控有很多種做法,從 Prometheus + Grafana 的完整觀測 stack,到最簡單的「有事傳訊息給我」。對於管理一到幾臺 VPS 的開發者或小團隊,後者更實際:設定快、不需要額外服務、手機就能收到通報。

Telegram Bot API 是這個場景最好的選擇。不需要自建 webhook 伺服器、不需要付費、API 簡單到一條 curl 指令就能傳訊息,而且 Telegram 在臺灣不被封鎖、在手機上推播通知可靠。

建立 Bot 取得 Token

在 Telegram 搜尋 @BotFather,開始對話後:

1
/newbot

按照提示輸入 Bot 名稱(顯示名稱,可以有空格)和 username(必須以 bot 結尾,例如 myserver_monitor_bot)。

BotFather 會回傳一個 API token,格式像 7654321098:AAHxxxxxxxxxxxxxxxxxxxxxxxxx。這就是你的 Bot 密碼,不要提交進版本庫。

取得你的 Chat ID

Telegram Bot 不能主動找人說話——使用者必須先傳訊息給 Bot,Bot 才能回傳訊息給那個對話。先在 Telegram 找到你剛建立的 Bot,傳任意一條訊息給它。

然後用這個 URL 取得你的 Chat ID(替換 YOUR_TOKEN):

1
curl "https://api.telegram.org/botYOUR_TOKEN/getUpdates"

回傳的 JSON 裡找 message.chat.id 欄位,那個數字就是你的 Chat ID。記下來。

最簡單的傳訊方式:直接呼叫 API

不需要任何 library,一條 curl 就能傳:

1
2
3
curl -s -X POST "https://api.telegram.org/botYOUR_TOKEN/sendMessage" \
-d chat_id="YOUR_CHAT_ID" \
-d text="伺服器通報:磁碟使用率已超過 85%"

這個特性讓通報腳本可以用 Bash 寫,不需要安裝 Python 或任何依賴,部署到任何 Linux 伺服器都能用。

Bash 通報函式:最輕量的做法

建立一個可以在任何腳本裡呼叫的通報函式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
# /usr/local/bin/tg-notify
# 用法:tg-notify "標題" "訊息內容" [info|warning|error]

TOKEN="你的Bot_Token"
CHAT_ID="你的Chat_ID"

send_tg() {
local level="${3:-info}"
local emoji
case "$level" in
error) emoji="🔴" ;;
warning) emoji="🟡" ;;
success) emoji="🟢" ;;
*) emoji="🔵" ;;
esac

local text="${emoji} *${1}*
${2}

_$(hostname) · $(date '+%Y-%m-%d %H:%M:%S')_"

curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
-d "text=${text}" \
-d "parse_mode=Markdown" \
> /dev/null
}

send_tg "$1" "$2" "${3:-info}"
1
chmod +x /usr/local/bin/tg-notify

之後任何腳本都可以這樣呼叫:

1
2
3
tg-notify "備份成功" "PostgreSQL 備份完成,大小:234MB" success
tg-notify "磁碟警告" "/ 分割區使用率達 87%" warning
tg-notify "服務中斷" "nginx 未回應 health check" error

用 Python 寫更完整的監控腳本

如果需要更多邏輯(閾值判斷、多個服務檢查、狀態持久化),Python 更適合。用標準函式庫的 urllib 就夠,不需要安裝額外套件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env python3
# /usr/local/bin/server-monitor.py

import os
import json
import shutil
import urllib.request
import urllib.parse
import subprocess

TOKEN = os.environ.get("TG_TOKEN", "")
CHAT_ID = os.environ.get("TG_CHAT_ID", "")

def send_message(text: str, level: str = "info") -> None:
emoji = {"error": "🔴", "warning": "🟡", "success": "🟢"}.get(level, "🔵")
full_text = f"{emoji} {text}"

data = urllib.parse.urlencode({
"chat_id": CHAT_ID,
"text": full_text,
"parse_mode": "Markdown",
}).encode()

req = urllib.request.Request(
f"https://api.telegram.org/bot{TOKEN}/sendMessage",
data=data,
method="POST"
)
try:
urllib.request.urlopen(req, timeout=10)
except Exception as e:
print(f"[ERROR] 傳送 Telegram 通報失敗:{e}")


def check_disk(path: str = "/", threshold: int = 85) -> None:
total, used, free = shutil.disk_usage(path)
usage_pct = int(used / total * 100)

if usage_pct >= threshold:
send_message(
f"*磁碟使用率警告*\n"
f"路徑:`{path}`\n"
f"使用率:{usage_pct}%(閾值:{threshold}%)\n"
f"剩餘:{free // (1024**3)} GB",
level="warning" if usage_pct < 95 else "error"
)


def check_service(service_name: str) -> None:
result = subprocess.run(
["systemctl", "is-active", service_name],
capture_output=True, text=True
)
if result.stdout.strip() != "active":
send_message(
f"*服務異常*\n"
f"服務:`{service_name}`\n"
f"狀態:`{result.stdout.strip()}`",
level="error"
)


def check_memory(threshold: int = 90) -> None:
with open("/proc/meminfo") as f:
lines = {k.strip(): v.strip() for k, v in
(line.split(":", 1) for line in f)}

total = int(lines["MemTotal"].split()[0])
available = int(lines["MemAvailable"].split()[0])
usage_pct = int((1 - available / total) * 100)

if usage_pct >= threshold:
send_message(
f"*記憶體使用率警告*\n"
f"使用率:{usage_pct}%(閾值:{threshold}%)\n"
f"可用:{available // 1024} MB",
level="warning"
)


if __name__ == "__main__":
check_disk("/", threshold=85)
check_memory(threshold=90)
check_service("nginx")
check_service("postgresql")

Token 和 Chat ID 用環境變數傳入,不要硬寫在腳本裡:

1
2
3
# /etc/environment 或是在 systemd service 的 [Service] 區塊設定
TG_TOKEN=你的Token
TG_CHAT_ID=你的ChatID

用 systemd timer 定期執行監控

搭配 systemd timer 每 10 分鐘跑一次:

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/systemd/system/server-monitor.service
[Unit]
Description=Server Health Monitor
After=network-online.target

[Service]
Type=oneshot
User=deploy
EnvironmentFile=/etc/server-monitor.env
ExecStart=/usr/local/bin/server-monitor.py
StandardOutput=journal
StandardError=journal
1
2
3
4
5
6
7
8
9
10
11
# /etc/systemd/system/server-monitor.timer
[Unit]
Description=Run server monitor every 10 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=10min
Persistent=true

[Install]
WantedBy=timers.target
1
2
sudo systemctl daemon-reload
sudo systemctl enable --now server-monitor.timer

讓重要腳本失敗時自動通報

除了定期監控,systemd 還支援在 service 失敗時觸發通報:

1
2
3
4
5
6
7
8
# /etc/systemd/system/db-backup.service
[Unit]
Description=Database Backup
OnFailure=notify-failure@%n.service # 失敗時觸發通報

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
1
2
3
4
5
6
7
# /etc/systemd/system/[email protected]
[Unit]
Description=Telegram notification for %i failure

[Service]
Type=oneshot
ExecStart=/usr/local/bin/tg-notify "任務失敗" "%i 執行失敗,請檢查 journalctl -u %i" error

這樣備份腳本一旦失敗,就會立刻收到 Telegram 通報,不需要另外寫 try/catch 或加 error handler。

安全注意事項

Bot token 是你的 Bot 密碼,任何拿到 token 的人都能用你的 Bot 傳訊息。幾個基本原則:

用環境變數而非硬編碼:不要把 token 直接寫在腳本裡,用 /etc/server-monitor.env 這類只有 root 能讀的檔案存放,再用 EnvironmentFile= 載入。

設定 Chat ID 白名單:你的監控腳本只會主動傳訊息給你,不需要處理接收。如果 Bot 也要回應指令,記得檢查傳來的 message 的 chat_id 是否是你自己的,否則任何人都能觸發你的 Bot 指令。

定期輪換 Token:如果 token 外洩,在 BotFather 裡執行 /revoke 可以讓舊 token 立即失效並產生新的。


想要在穩定的臺灣機房環境跑自動化監控?NCSE Network 的 VPS 有 24/7 的基礎設施支援,讓你的監控腳本不斷線。詳情見 ncse.tw

需要技術開發支援?

NCSE Network 提供 Discord Bot、LINE Bot、AI Agent、爬蟲、監控系統等客製化開發服務,從規劃到上線一站式完成。

洽談專案 →