DocsInfrastruktur
Notifikasi
Mengirim kabar deploy, backup, job, container mati, disk menipis, sertifikat gagal, dan DNS domain bermasalah ke Telegram, Slack, Discord, webhook, atau email.
- Channel
- Telegram · Slack · Discord · Webhook · Email
- Event
- 12 toggle per channel
- Lingkup
- Platform-wide, owner/admin
Alur
- 01eventdeploy, backup, job, container mati, disk, sertifikat, DNS, error log, server remote, monitor HTTP
- 02filterchannel dengan toggle event itu aktif
- 03formatpayload per platform: HTML, attachments, embeds, JSON, email
- 04kirimfetch dengan timeout 10 detik; gagal hanya dicatat di log
Channel yang didukung
| Tipe | Yang diisi | Cara mendapatkannya |
|---|---|---|
| Telegram | Bot token + Chat ID | Buat bot lewat @BotFather (token 123456789:AAH…). Chat ID: kirim pesan ke bot lalu buka https://api.telegram.org/bot<token>/getUpdates; grup/channel biasanya diawali -100…. Bot harus ada di grup itu. |
| Slack | Webhook URL | Slack app → Incoming Webhooks → Add New Webhook to Workspace → pilih channel. |
| Discord | Webhook URL | Channel → Edit → Integrations → Webhooks → New Webhook → Copy URL. |
| Webhook | Webhook URL (https://…) + Secret opsional | Endpoint apa pun yang menerima POST JSON — n8n, Zapier, aplikasi sendiri. Secret mengaktifkan tanda tangan HMAC. |
| Host SMTP, Port, Username, Password, Pengirim, Penerima | Penerima dipisah koma. Port 465 = TLS implisit, 587 = STARTTLS. Untuk Gmail pakai app password. |
Menambahkan channel
Integrasi → Notifikasi → Channel notifikasi baru (owner/admin)
Isi Nama, pilih Tipe, isi field-nya, dan nyalakan toggle event yang diinginkan. Token/URL/ password disimpan terenkripsi dan tidak ditampilkan lagi — daftar channel hanya menunjukkan petunjuk target (mis. chat id, domain).
Kirim tes
Tombol tes mengirim pesan contoh ke channel itu. Error provider ditampilkan apa adanya — mis. Telegram
chat not found(bot belum di grup / chat id salah) atau SMTP535 Authentication failed.Picu event sungguhan
Deploy sekali, atau jalankan job yang sengaja gagal (
exit 1) untuk memastikan toggle bekerja.
Event
| Toggle | Terpicu saat | Isi pesan |
|---|---|---|
Deploy dimulai (nonaktif default) | Deployment aplikasi baru dimulai (build, webhook, auto-update, atau rollback — bukan penyesuaian runtime seperti ganti replika/limit). | Aplikasi, project, pemicu (manual/webhook/auto-update, + commit & pengirim bila dari webhook), tautan ke halaman aplikasi. |
| Deploy sukses | Deployment aplikasi berakhir success (termasuk rollback). | Aplikasi, project, image, durasi, tautan ke halaman aplikasi. |
| Deploy gagal | Deployment aplikasi atau stack compose gagal. | Sama + potongan pesan error (500 karakter). |
| Backup gagal | Backup database/volume (manual atau terjadwal) gagal, termasuk gagal unggah ke S3. | Database/aplikasi, pemicu (manual/terjadwal), error. |
| Job gagal | Scheduled job berstatus failed atau timeout. | Nama job, perintah (200 karakter), 500 karakter terakhir output. |
| Container mati | Container aplikasi/database berhenti tak terduga — lihat aturan di Monitoring. Berlaku juga untuk aplikasi di server remote. | Nama container, exit code, apakah sedang restart; nama server bila di server remote. |
| Disk hampir penuh | Pemakaian filesystem Docker melewati ambang (default 90 %, DISK_ALERT_PERCENT); diperiksa sekali sehari. | Persentase terpakai, ambang, ruang tersisa. |
| Sertifikat gagal | Traefik gagal menerbitkan/memperbarui sertifikat sebuah domain (diperiksa tiap 10 menit). | Domain dan pesan error dari ACME. |
| DNS domain bermasalah | DNS sebuah domain tidak lagi mengarah ke IP yang benar — diperiksa tiap 15 menit, terpicu setelah dua kali cek berturut-turut gagal (mismatch/tidak bisa di-resolve). | Domain, status (mismatch/unresolved), pesan penjelasan. |
Error aplikasi (nonaktif default) | Log container aplikasi yang sedang running cocok dengan pola error umum (traceback, panic, exception, level=error, dll — diperiksa tiap menit). | Aplikasi, project, jumlah error, maksimal 3 contoh baris (disensor), tautan ke halaman aplikasi. |
Server remote tidak terjangkau (aktif default) | Server remote tidak menjawab (SSH/Docker) dua kali cek berturut-turut (cek tiap menit). Satu pesan pulih dikirim saat terjangkau lagi; pengingat maksimal sekali per jam selama down. | Nama server, alamat, galat; lama down pada pesan pulih. |
Monitor HTTP gagal (aktif default) | Pemeriksaan HTTP sebuah aplikasi gagal N kali berturut-turut (monitor opsional per aplikasi, lihat Monitoring). Satu pesan pulih saat sehat lagi; pengingat maksimal tiap 6 jam selama down. | Aplikasi, project, target, kode/galat, berapa kali gagal; lama down pada pesan pulih; tautan ke halaman aplikasi. |
Peringatan CPU atau memori (aktif default) | Aplikasi atau database menjaga CPU atau memori di atas ambang yang Anda atur selama waktu tertentu (aturan opsional per sumber daya, mati sampai diaktifkan; lihat Monitoring). Satu pesan saat dimulai, pengingat tiap 6 jam selama tetap tinggi, dan satu pesan “kembali normal”. | Aplikasi atau database, project, CPU atau memori, nilai saat ini, ambang dan durasi; tautan ke halaman aplikasi. |
- Deploy dimulai nonaktif secara default (beda dari event lain) — deploy bisa sering terjadi (auto-update, webhook), jadi harus dinyalakan sendiri per channel yang memang ingin tahu. Juga tidak terpicu untuk deployment
kind: config(ganti mode swarm/replika/limit sumber daya pada image yang sama) — itu bukan deploy baru yang perlu ditunggu. - Tautan ke halaman aplikasi disertakan bila
WEB_ORIGINterisi. - Kegagalan kirim ke satu channel hanya dicatat di log API dan tidak mempengaruhi channel lain maupun proses yang memicunya (deploy tidak pernah gagal karena notifikasi).
- Container mati: maksimal 1 notifikasi per container per 10 menit.
- Server remote tidak terjangkau dan Monitor HTTP gagal aktif secara default, tetapi hanya bekerja bila kamu memakai fiturnya (menambah server remote / menyalakan monitor di sebuah aplikasi), jadi tidak berisik untuk yang tidak memakainya. Keduanya memakai satu toggle untuk pesan gagal dan pesan pulih (dibedakan lewat level dan
eventdi payload webhook:server.down/server.recovered,http.down/http.recovered). - DNS domain bermasalah: dua kali cek gagal berturut-turut (meredam gangguan DNS sesaat) sebelum notifikasi pertama dikirim, lalu maksimal 1 kali per hari per domain selama status tetap bermasalah. Domain yang tidak bisa dibandingkan sama sekali (tidak ada IP pembanding) tidak pernah mengirim.
- Error aplikasi nonaktif secara default — deteksi dari teks log rawan salah tebak. Maksimal 1 notifikasi per aplikasi per 15 menit, kecuali muncul bentuk error yang belum pernah terlihat sejak API terakhir start, yang tetap langsung dikirim. Bisa dinonaktifkan per aplikasi lewat switch Abaikan error di log di tab Pengaturan aplikasi — lihat Aplikasi.
Payload webhook generik
Channel Webhook mengirim POST dengan Content-Type: application/json. Field umum: title, level (success / failure / info), url, lalu field khusus event:
{
"title": "Deployment started: shop",
"level": "info",
"url": "https://panel.example.com/applications/…",
"event": "deployment.started",
"deploymentId": "…",
"kind": "build",
"applicationId": "…",
"application": "shop",
"project": "Toko",
"trigger": "webhook",
"commitSha": "a1b2c3d4e5f6",
"commitMessage": "fix: checkout bug",
"triggeredBy": "octocat"
}{
"title": "Deployment succeeded: shop",
"level": "success",
"url": "https://panel.example.com/applications/…",
"event": "deployment.success",
"deploymentId": "…",
"kind": "deploy",
"applicationId": "…",
"application": "shop",
"imageRef": "localhost:5000/toko/shop:a1b2c3d4e5f6",
"error": null,
"finishedAt": "2026-09-22T04:30:00.000Z"
}{
"title": "Container down: aoox-app-shop",
"level": "failure",
"event": "container.down",
"container": "aoox-app-shop",
"exitCode": 137,
"restarting": true
}{
"title": "Application error detected: shop",
"level": "failure",
"url": "https://panel.example.com/applications/…",
"event": "app.error",
"applicationId": "…",
"count": 2,
"fingerprints": ["TypeError: Cannot read <n>", "FATAL: <n>"]
}Contoh penerima (Node.js)
app.post("/hooks/aoox", express.json(), (req, res) => {
const { event, level, title } = req.body
if (event === "deployment.failure") alertOnCall(title)
res.sendStatus(204)
})Header & tanda tangan
| Header | Isi |
|---|---|
X-Aoox-Event | Nama event, mis. deployment.success. |
X-Aoox-Delivery | ID unik pengiriman — pakai untuk idempotensi. |
X-Aoox-Signature | Hanya bila Secret diisi: sha256=HMAC-SHA256(secret, raw body), skema yang sama dengan GitHub. |
const sig = req.get("X-Aoox-Signature")
const mine = "sha256=" + createHmac("sha256", SECRET).update(rawBody).digest("hex")
if (!sig || !timingSafeEqual(Buffer.from(sig), Buffer.from(mine))) return res.sendStatus(401)JSON.stringify ulang. Tanpa secret, amankan endpoint dengan URL yang sulit ditebak. Webhook keluar bisa mencapai alamat internal (SSRF by design) — itulah sebabnya hanya owner/admin yang boleh menambah channel.Jebakan umum
| Gejala | Penyebab & solusi |
|---|---|
| Tes sukses tapi event tidak pernah masuk | Toggle event belum dinyalakan di channel itu, atau event memang tidak terjadi (mis. container mati di server remote tidak terdeteksi). |
| Telegram: chat not found / bot was blocked | Bot belum ditambahkan ke grup, chat id tanpa prefix -100 untuk supergroup, atau pengguna belum /start. |
| Discord/Slack 4xx | URL webhook kedaluwarsa/dihapus di provider. Buat ulang dan perbarui channel. |
| Email tidak sampai, tes sukses | Masuk spam, atau Pengirim tidak diizinkan domain SMTP (SPF/DKIM). Pakai alamat pengirim milik domain SMTP. |
| Timeout | Endpoint lambat > 10 detik atau tidak terjangkau dari container API. Balas cepat (204) lalu proses async. |
Langkah berikutnya
Ada yang keliru? Edit halaman ini di GitHub ↗