伺服器監控有很多種做法,從 Prometheus + Grafana 的完整觀測 stack,到最簡單的「有事傳訊息給我」。對於管理一到幾臺 VPS 的開發者或小團隊,後者更實際:設定快、不需要額外服務、手機就能收到通報。
Telegram Bot API 是這個場景最好的選擇。不需要自建 webhook 伺服器、不需要付費、API 簡單到一條 curl 指令就能傳訊息,而且 Telegram 在臺灣不被封鎖、在手機上推播通知可靠。
建立 Bot 取得 Token 在 Telegram 搜尋 @BotFather,開始對話後:
按照提示輸入 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 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 import osimport jsonimport shutilimport urllib.requestimport urllib.parseimport subprocessTOKEN = 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 TG_TOKEN=你的Token TG_CHAT_ID=你的ChatID
用 systemd timer 定期執行監控 搭配 systemd timer 每 10 分鐘跑一次:
1 2 3 4 5 6 7 8 9 10 11 12 [Unit] Description =Server Health MonitorAfter =network-on line.target[Service] Type =on eshotUser =deployEnvironmentFile =/etc/server-monitor.envExecStart =/usr/local/bin/server-monitor.pyStandardOutput =journalStandardError =journal
1 2 3 4 5 6 7 8 9 10 11 [Unit] Description =Run server monitor every 10 minutes[Timer] OnBootSec =5 minOnUnitActiveSec =10 minPersistent =true [Install] WantedBy =timers.target
1 2 sudo systemctl daemon-reloadsudo systemctl enable --now server-monitor.timer
讓重要腳本失敗時自動通報 除了定期監控,systemd 還支援在 service 失敗時觸發通報:
1 2 3 4 5 6 7 8 [Unit] Description =Database BackupOnFailure =notify-failure@%n.service [Service] Type =on eshotExecStart =/usr/local/bin/db-backup.sh
1 2 3 4 5 6 7 [Unit] Description =Telegram notification for %i failure[Service] Type =on eshotExecStart =/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、爬蟲、監控系統等客製化開發服務,從規劃到上線一站式完成。
洽談專案 →