Gửi cảnh báo hệ thống VPS qua Telegram bot bằng script bash

SSH vào VPS, bạn muốn biết ngay khi CPU đầy, RAM cạn, đĩa gần đầy, nhưng không phải lúc nào cũng login vào kiểm tra. Giải pháp: bot Telegram + script bash. Bài này hướng dẫn tạo script gửi cảnh báo hệ thống (CPU load, RAM usage, disk usage, uptime) về Telegram, chạy định kỳ qua systemd timer. Áp dụng trên Ubuntu 24.04 LTS và Debian 12.
Yêu cầu trước khi bắt đầu
- VPS chạy Ubuntu 24.04 hoặc Debian 12, có quyền root hoặc sudo.
- Một tài khoản Telegram, nên cài app trên điện thoại hoặc desktop.
- Biết tạo bot qua @BotFather và lấy token. Nếu chưa làm, tìm kiếm "BotFather Telegram" trên web, có nhiều hướng dẫn chi tiết.
- Biết lấy chat ID của bạn hoặc nhóm. Dùng @userinfobot hoặc @get_id_bot.
Vì sao không dùng cron mà dùng systemd timer?
Cron là tool điều khiển tác vụ có lịch từ thập niên 70. Nó vẫn chạy tốt, nhưng systemd timer hiện đại hơn: có log rõ ràng (journalctl -u alert-telegram.timer), dễ gỡ lỗi khi script fail, xử lý dependency và random delay tốt hơn. Nếu bạn đã quen cron, cách dưới đây có thể thay đổi lịch dễ dàng, tôi vẫn để cron option ở phần lưu ý cuối.
Bước 1 - Tạo script bash gửi thông báo lên Telegram
Tạo file script và đặt ở /usr/local/bin/ để mọi user truy cập được (nếu cần chạy dưới root thì cũng không phải sửa path).
sudo nano /usr/local/bin/telegram-alert.sh
Dán nội dung sau (thay BOT_TOKEN và CHAT_ID của bạn):
#!/bin/bash
# Cấu hình, thay giá trị dưới đây
BOT_TOKEN="1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
CHAT_ID="-1234567890" # ID nhóm hoặc cá nhân
# Lấy thông số hệ thống
HOSTNAME=$(hostname)
UPTIME=$(uptime -p | sed 's/up //')
LOAD=$(uptime | awk -F'load average:' '{print $2}')
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
RAM_TOTAL=$(free -h | awk '/^Mem:/{print $2}')
RAM_USED=$(free -h | awk '/^Mem:/{print $3}')
RAM_PERC=$(free | awk '/^Mem:/{printf "%.0f", $3/$2 * 100}')
DISK_ALERT=""
DISK_INFO=""
DISK_CRITICAL=0
# Duyệt từng partition, lấy mức dùng
while IFS= read -r line; do
FILESYSTEM=$(echo "$line" | awk '{print $1}')
SIZE=$(echo "$line" | awk '{print $2}')
USED=$(echo "$line" | awk '{print $3}')
USE_PERC=$(echo "$line" | awk '{print $5}' | sed 's/%//')
MOUNT=$(echo "$line" | awk '{print $6}')
DISK_INFO+="├─ $MOUNT: $USED/$SIZE ($USE_PERC%)\n"
if [ "$USE_PERC" -ge 85 ]; then
DISK_ALERT+="⚠️ $MOUNT đã dùng $USE_PERC%\n"
DISK_CRITICAL=1
fi
done < <(df -h | grep '^/dev/')
# Tạo icon dựa trên mức cảnh báo
if [ "$DISK_CRITICAL" -eq 1 ] || [ "$RAM_PERC" -ge 85 ]; then
ICON="🚨"
elif [ "$DISK_CRITICAL" -eq 0 ] && [ "$RAM_PERC" -ge 70 ]; then
ICON="⚠️"
else
ICON="✅"
fi
# RAM và disk usage
DISK_USED=$(df -h / | awk 'NR==2{print $3}')
DISK_TOTAL=$(df -h / | awk 'NR==2{print $2}')
DISK_PERC=$(df / | awk 'NR==2{print $5}')
MESSAGE="$ICON *Cảnh báo hệ thống - $HOSTNAME*
• Uptime: $UPTIME
• CPU load: $LOAD (usage: $CPU_USAGE%)
• RAM: $RAM_USED / $RAM_TOTAL ($RAM_PERC%)
• Disk (/): $DISK_USED / $DISK_TOTAL ($DISK_PERC)
*Chi tiết phân vùng:*
$DISK_INFO"
# Gửi message lên Telegram
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="$MESSAGE" \
-d parse_mode="Markdown" \
-d disable_notification=false
# Nếu có disk >85%, gửi cảnh báo riêng (tách biệt để dễ parse)
if [ "$DISK_CRITICAL" -eq 1 ]; then
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="🚨 *Cảnh báo disk gần đầy*\n$DISK_ALERT" \
-d parse_mode="Markdown"
fi
exit 0
Giải thích: script lấy hostname để phân biệt VPS trong cùng bot, uptime, CPU load + usage, RAM tổng / đã dùng + %, disk usage từng partition. Nếu bất kỳ partition nào dùng >85%, script gửi cảnh báo riêng kèm biểu tượng 🚨. Nếu RAM hoặc disk ở mức 70-84%, icon ⚠️, dưới 70% là ✅.
Phân quyền và test:
sudo chmod +x /usr/local/bin/telegram-alert.sh
sudo /usr/local/bin/telegram-alert.sh
Kiểm tra Telegram, bạn sẽ thấy tin nhắn đầu tiên. Nếu không, xem lỗi ở mục "Xử lý lỗi thường gặp" bên dưới.
Bước 2 - Cấu hình systemd để chạy định kỳ
Tạo service unit, file này mô tả script cần chạy thế nào:
sudo nano /etc/systemd/system/telegram-alert.service
Nội dung:
[Unit]
Description=Send VPS system alert to Telegram
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/telegram-alert.sh
User=root
Group=root
StandardOutput=journal
StandardError=journal
Giải thích: After=network-online.target đảm bảo script chạy sau khi mạng đã sẵn sàng. Type=oneshot vì script chỉ chạy một lần rồi thoát (phù hợp với timer). Output + error đều ghi vào journal để dễ theo dõi.
Tạo timer unit, mục này điều khiển lịch chạy:
sudo nano /etc/systemd/system/telegram-alert.timer
[Unit]
Description=Run telegram alert every 30 minutes
Requires=telegram-alert.service
[Timer]
OnCalendar=*:0/30
Persistent=true
RandomizedDelaySec=60
[Install]
WantedBy=timers.target
OnCalendar=*:0/30: chạy mỗi 30 phút (phút 0, 30). RandomizedDelaySec=60: làm trễ ngẫu nhiên tối đa 60 giây để tránh dồn tải bot nếu nhiều VPS cùng lúc. Persistent=true: nếu VPS tắt vào thời điểm chạy, khi bật lên sẽ chạy bù.
Kích hoạt:
sudo systemctl daemon-reload
sudo systemctl enable telegram-alert.timer
sudo systemctl start telegram-alert.timer
Verify:
sudo systemctl list-timers --all | grep telegram-alert
# Output mong đợi: thấy dòng "telegram-alert.timer" + NEXT time + LEFT time
sudo journalctl -u telegram-alert.service -n 5
# Output: hiển thị log của lần chạy gần nhất, không có lỗi
Bảng tham số cấu hình
| Tham số | Giá trị | Mô tả |
|---|---|---|
| BOT_TOKEN | Chuỗi dài ~46 ký tự | Lấy từ BotFather |
| CHAT_ID | Số nguyên (ví dụ -1234567890) | Lấy từ @userinfobot hoặc @get_id_bot; nhóm có dấu trừ (-) |
| OnCalendar | *:0/30 | Mỗi 30 phút |
| RandomizedDelaySec | 60 | Làm trễ random 0-60s |
| DISK_THRESHOLD | 85 (phần trăm) | Ngưỡng cảnh báo disk |
Xử lý lỗi thường gặp
Lỗi 1: Không nhận được tin nhắn
Chạy thủ công script xem output:
sudo /usr/local/bin/telegram-alert.sh 2>&1
Nếu thấy lỗi HTTP 400 Bad Request: kiểm tra BOT_TOKEN và CHAT_ID có đúng không. Token thường dài ~46 ký tự, chat ID nhóm có dấu trừ trước. Nếu lỗi curl: (6) Could not resolve host: VPS chưa có DNS, kiểm tra file /etc/resolv.conf có dòng nameserver 8.8.8.8 chưa.
Lỗi 2: Script không chạy theo timer
sudo journalctl -u telegram-alert.service -n 20
sudo journalctl -u telegram-alert.timer -n 20
Kiểm tra timer có enable và start chưa. Thường lỗi thiếu systemctl enable ... hoặc quên daemon-reload.
Lỗi 3: Disk usage sai hoặc thiếu partition
Script dùng df -h | grep '^/dev/'. Nếu partition là devtmpfs hoặc tmpfs, nó không thuộc loại đó. Nếu bạn dùng LVM hoặc Btrfs, sửa lệnh df -h | grep -E '^/dev|^mapper'.
Tuỳ chỉnh nâng cao
Bạn có thể mở rộng script để gửi cảnh báo khi:
- CPU load > 2.0: thêm dòng
if (( $(echo "$LOAD > 2.0" | bc -l) )); then - Memory < 10% free: thay vì dùng phần trăm, kiểm tra RAM free rất cao
- Disk I/O cao: dùng
iostat(càisysstat) - Kiểm tra service down: thêm
systemctl is-active nginx
Nếu bạn dùng cron thay vì systemd, thêm dòng vào crontab (ví dụ mỗi 30 phút):
*/30 * * * * /usr/local/bin/telegram-alert.sh
Nhưng tôi khuyến khích dùng systemd vì lý do log và debug đã nêu ở đầu bài.
Với script này, bạn có thể tự động giám sát VPS của mình mà không cần panel bên thứ ba. Chạy trên VPS NVMe, IPv4 Việt Nam, bạn sẽ nhận được cảnh báo ngay khi có sự cố. Nếu cần một VPS Linux mạnh mẽ để chạy các script giám sát, bạn có thể tham khảo dịch vụ tại thuê VPS Linux của thueVPS, hạ tầng NVMe ổn định, full root, phù hợp cho mọi workload tự động hóa.
Câu hỏi: Tôi có thể gửi thông báo cho nhiều người cùng lúc không?
Có. Bạn tạo một Telegram group, thêm bot vào group, lấy group chat ID (bắt đầu bằng dấu trừ), dùng ID đó trong script. Tất cả thành viên trong group đều nhận được tin nhắn.
Câu hỏi: Có cách nào gửi ảnh hoặc biểu đồ không?
Script này chỉ gửi text. Nếu muốn gửi ảnh, bạn cần script tạo ảnh PNG từ dữ liệu (vd dùng gnuplot hoặc shell script vẽ ASCII), rồi gửi qua API sendPhoto của Telegram.
Câu hỏi: Tôi muốn chạy mỗi 5 phút, sửa thế nào?
Sửa giá trị OnCalendar trong file timer thành *:0/5 (mỗi 5 phút), chạy sudo systemctl daemon-reload && sudo systemctl restart telegram-alert.timer.
Câu hỏi: Lỡ script có lỗi cú pháp, tôi có bị spam Telegram không?
Nếu script lỗi, chỉ có systemd log lỗi, Telegram sẽ không nhận tin nhắn. Bạn có thể kiểm tra log journal như đã hướng dẫn. Để an toàn, test script thủ công trước khi bật timer.
Câu hỏi: Có cách nào cảnh báo khi VPS bị tắt nguồn đột ngột không?
Script này chạy định kỳ, nếu VPS tắt thì timer không chạy. Bạn cần một external monitoring (VD uptimerobot.com) hoặc một VPS thứ hai ping check. Trên cùng VPS, không có cách nào gửi được nếu nó đã tắt.
Câu hỏi: Bot có cần chạy trên VPS root không?
Script này dùng root để lấy disk usage đầy đủ. Nếu bạn dùng non-root user, thêm user vào sudo và chạy lệnh với sudo trong script, nhưng cần cấu hình sudoers để không hỏi password.


