8.0 KiB
Telegram Reset Button untuk Notifikasi Expired (MSR Hotspot)
Ringkasan perubahan arsitektur notifikasi expired hotspot & tombol "🔄 Reset" via Telegram. Tanggal: 1 Agu 2026 · RouterOS v6.49.6 · Mikhmon (Docker)
1. Masalah Awal
- Notifikasi "User X expired" sebelumnya dikirim oleh
notify-expire.phpdi server Mikhmon, yang menampilkan inline keyboard 🔄 Reset dengancallback_data=reset_<user>. - Router (MikroTik) tidak bisa menjangkau path lama (
192.168.100.6, sudah mati). Scheduler di router mengirim notifikasi ke URL Telegram lama yang tidak lagi berfungsi. - Akibatnya pesan expired terkirim tanpa tombol Reset, dan callback reset tidak berfungsi.
2. Solusi Baru (Arsitektur)
[RouterOS Scheduler] --/tool/fetch sendMessage--> [Telegram Bot] --Kirim ke Grup (thread "Notif Expire")
^
[User klik 🔄 Reset] --> callback_query --> [Bot] --> poller getUpdates
|
v
[Host rl] cron tiap menit --> msr-poller.sh --> docker start mikhmon
|
v
telegram-cb.php (di container) --> RouterOS API reset user
|
v
Telegram: "✅ {user} has been reset"
Komponen
| Komponen | Lokasi | Peran |
|---|---|---|
| Scheduler RouterOS | Router 192.168.100.2 | Kirim pesan expired + reply_markup tombol Reset langsung ke Telegram |
| Telegram Bot | 5115036608:AAGey... |
Terima/teruskan pesan & callback |
| Cron host | /usr/local/bin/msr-poller.sh di rl |
Setiap menit: docker start mikhmon + curl telegram-cb.php |
telegram-cb.php |
/var/www/html/ di container mikhmon |
getUpdates → reset user di RouterOS → jawab callback + kirim konfirmasi |
lib/routeros_api.class.php |
/var/www/html/lib/ |
Koneksi RouterOS API dari PHP |
3. Perubahan yang Dilakukan
3.1 Scheduler RouterOS (Family, Bulanan2, Bulanan4)
on-event scheduler sekarang melakukan /tool/fetch ke Telegram sendMessage dengan:
chat_id=-1002554941429,message_thread_id=42(thread "Notif Expire")text=" . $name . "+expiredreply_markup= JSON inline keyboard URL-encoded:
%7B%22inline_keyboard%22%3A%5B%5B%7B%22text%22%3A%22%F0%9F%94%84%20Reset%22%2C%22callback_data%22%3A%22reset_" . $name . "%22%7D%5D%5D%7D
yang setara dengan:
{"inline_keyboard":[[{"text":"🔴 Reset","callback_data":"reset_<name>"}]]}
Contoh cuplikan on-event Family:
tool fetch url=("https://api.telegram.org/bot5115036608:AAGey.../sendMessage?chat_id=-1002554941429&message_thread_id=42&text=" . $name . "+expired&reply_markup=" . "%7B%22inline_keyboard%22%3A...%22reset_" . $name . "%22%7D%5D%5D%7D") mode=https http-method=get keep-result=no
Penting: deduplikasi (:if ($curlim = "")) tetap dipertahankan agar setiap user hanya dikirim sekali.
3.2 Container Mikhmon — Install php81-curl
Container PHP 8.1 (Alpine) awalnya tanpa ekstensi cURL → telegram-cb.php error HTTP 500.
docker exec -u root mikhmon apk add --no-cache php81-curl
3.3 Perbaikan include path telegram-cb.php
Dari dirname(__DIR__) . '/lib/routeros_api.class.php' → __DIR__ . '/lib/routeros_api.class.php' (2 tempat), karena file berada langsung di /var/www/html/.
3.4 Poller Host (atasi sablier)
Container mikhmon dikelola sablier (traefik plugin) yang mematikannya setelah 5 menit idle — cron di dalam container tidak bisa diandalkan. Solusi: cron di host yang men-starter container lalu memanggil callback.
/usr/local/bin/msr-poller.sh:
#!/bin/bash
CB_KEY="msr-2026-reset"
URL="http://172.18.0.15/telegram-cb.php?key=${CB_KEY}"
docker start mikhmon >/dev/null 2>&1
sleep 1
curl -s -m 30 "$URL" >/dev/null 2>&1
Crontab host (crontab -l):
* * * * * /usr/local/bin/msr-poller.sh >/dev/null 2>&1
Catatan:
docker startidempotent (kalau sudah jalan, no-op) → otomatis menjaga container hidup.- Polling maksimal latency ~1 menit setelah klik tombol.
3.5 Callback Handler telegram-cb.php
- Auth via
?key=msr-2026-reset(403 kalau salah). getUpdates(hanyacallback_query).- Untuk
databerawalanreset_:- Cari user di
/ip/hotspot/user/print?name=<user> set limit-uptime=0, comment=''+reset-counters- Hapus scheduler bernama
<user>(jika ada) answerCallbackQuery(✅ {user} reset!)sendMessageke chat/thread:✅ *{user}* has been reset\nReady to use again
- Cari user di
- User tidak ditemukan →
answerCallbackQueryalertUser {user} not found(tanpa pesan). - Meng-konfirmasi offset via
getUpdates?offset=<last_id+1>setelah diproses.
4. Verifikasi
| Item | Hasil |
|---|---|
| Pesan expired + tombol Reset muncul di grup | ✅ Bubble punya reply-markup-button "Reset" |
Klik tombol → callback reset_<user> sampai ke bot |
✅ data: "reset_TMR-1" via getUpdates |
| Poller cron memproses callback | ✅ processed: 1 |
| User di-reset di router | ✅ limit-uptime 10s → None (unlimited), counters reset |
| Scheduler user dihapus | ✅ |
| Konfirmasi bot di grup | ✅ msr_net: TMR-1 has been reset (09:11) |
Test user TMR-1 dibuat khusus lalu dihapus setelah verifikasi.
5. Operasional & Troubleshooting
Cek status
- Poller:
ssh rl "cat /usr/local/bin/msr-poller.sh; crontab -l | grep poller" - Container:
ssh rl "docker ps --filter name=mikhmon --format '{{.Status}}'" - Callback pending:
curl 'http://172.18.0.15/telegram-cb.php?key=msr-2026-reset'→ harusprocessed: 0/no updates - Webhook tidak terpasang (poller getUpdates aman):
getWebhookInfo→url: "",allowed_updates:["callback_query"]
Gejala umum
- HTTP 500 dari telegram-cb.php → cek cURL:
docker exec mikhmon php -r 'var_dump(function_exists("curl_init"));' - Container mati → sablier mematikannya setelah 5m idle; poller harusnya men-starter. Cek log poller/cron.
- Callback tidak terproses → JANGAN baca
getUpdatesmanual (maju offset & poller kehilangan callback). Biarkan poller cron yang memproses. - Tombol tidak muncul →
reply_markuptidak ter-encode dengan benar; cekverify-markup.py& on-event scheduler.
6. Kredensial & Referensi
- Router:
192.168.100.2, APIremote.vpnmurahjogja.my.id:33206, loginmi4/m14 - Bot:
5115036608:AAGeyXVq5eNvdAkaCQHU9NfH16uAAiSKiuk - Chat/Grup:
-1002554941429, thread42("Notif Expire") - Container:
mikhmon(animegasan/mikhmon:v3-latest) di hostrl(root@100.100.31.46, ssh aliasrl, key~/.ssh/pl) - Callback secret:
msr-2026-reset - Container IP:
172.18.0.15
7. Skrip Bantu (folder C:\Users\Admin\dev\mikhmon-fix\)
| Skrip | Fungsi |
|---|---|
patch-notif2.py |
Patch on-event scheduler → tambah reply_markup Reset button |
verify-markup.py |
Verifikasi on-event berisi reply_markup & reset_ |
verify-notif.py |
Verifikasi isi scheduler (api.telegram.org, tidak ada URL lama) |
dump-sched.py |
Dump penuh on-event scheduler |
telegram-cb.php |
Callback handler (sumber; di-deploy ke container) |
poller.sh |
Poller host (sumber; di-deploy ke /usr/local/bin/msr-poller.sh) |
mk-user.py / rm-user.py |
Buat / hapus user test |
send-expired-tmr.py |
Kirim pesan expired + tombol untuk user tertentu |
check-reset.py |
Cek limit-uptime & scheduler user setelah reset |
8. Catatan
- Bot menampilkan tombol sebagai "Reset" — teks
🔄(U+1F504,%F0%9F%94%84) di-render Telegram sebagai ikon 🔄. keep-result=nodi scheduler fetch (tidak menyimpan file respons di router). Saat debug bisa ubahkeep-result=yesuntuk lihat filesendMessage?....- Jika tombol ditekan dua kali, user kedua dikirim ulang notif "expired" (karena sudah reset, limit-uptime unlimited → tidak ada scheduler baru sampai limit diubah lagi).