$ aoox

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

  1. 01eventdeploy, backup, job, container mati, disk, sertifikat, DNS, error log, server remote, monitor HTTP
  2. 02filterchannel dengan toggle event itu aktif
  3. 03formatpayload per platform: HTML, attachments, embeds, JSON, email
  4. 04kirimfetch dengan timeout 10 detik; gagal hanya dicatat di log

Channel yang didukung

TipeYang diisiCara mendapatkannya
TelegramBot token + Chat IDBuat 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.
SlackWebhook URLSlack app → Incoming Webhooks → Add New Webhook to Workspace → pilih channel.
DiscordWebhook URLChannel → Edit → Integrations → Webhooks → New Webhook → Copy URL.
WebhookWebhook URL (https://…) + Secret opsionalEndpoint apa pun yang menerima POST JSON — n8n, Zapier, aplikasi sendiri. Secret mengaktifkan tanda tangan HMAC.
EmailHost SMTP, Port, Username, Password, Pengirim, PenerimaPenerima dipisah koma. Port 465 = TLS implisit, 587 = STARTTLS. Untuk Gmail pakai app password.

Menambahkan channel

  1. 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).

  2. 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 SMTP 535 Authentication failed.

  3. Picu event sungguhan

    Deploy sekali, atau jalankan job yang sengaja gagal (exit 1) untuk memastikan toggle bekerja.

Event

ToggleTerpicu saatIsi 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 suksesDeployment aplikasi berakhir success (termasuk rollback).Aplikasi, project, image, durasi, tautan ke halaman aplikasi.
Deploy gagalDeployment aplikasi atau stack compose gagal.Sama + potongan pesan error (500 karakter).
Backup gagalBackup database/volume (manual atau terjadwal) gagal, termasuk gagal unggah ke S3.Database/aplikasi, pemicu (manual/terjadwal), error.
Job gagalScheduled job berstatus failed atau timeout.Nama job, perintah (200 karakter), 500 karakter terakhir output.
Container matiContainer 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 penuhPemakaian filesystem Docker melewati ambang (default 90 %, DISK_ALERT_PERCENT); diperiksa sekali sehari.Persentase terpakai, ambang, ruang tersisa.
Sertifikat gagalTraefik gagal menerbitkan/memperbarui sertifikat sebuah domain (diperiksa tiap 10 menit).Domain dan pesan error dari ACME.
DNS domain bermasalahDNS 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_ORIGIN terisi.
  • 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 event di 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:

deployment.started
{
  "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"
}
deployment.success / deployment.failure
{
  "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"
}
container.down
{
  "title": "Container down: aoox-app-shop",
  "level": "failure",
  "event": "container.down",
  "container": "aoox-app-shop",
  "exitCode": 137,
  "restarting": true
}
app.error
{
  "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

HeaderIsi
X-Aoox-EventNama event, mis. deployment.success.
X-Aoox-DeliveryID unik pengiriman — pakai untuk idempotensi.
X-Aoox-SignatureHanya bila Secret diisi: sha256=HMAC-SHA256(secret, raw body), skema yang sama dengan GitHub.
Verifikasi di penerima (Node.js)
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)
Hitung HMAC atas byte body mentah, bukan hasilJSON.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

GejalaPenyebab & solusi
Tes sukses tapi event tidak pernah masukToggle 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 blockedBot belum ditambahkan ke grup, chat id tanpa prefix -100 untuk supergroup, atau pengguna belum /start.
Discord/Slack 4xxURL webhook kedaluwarsa/dihapus di provider. Buat ulang dan perbarui channel.
Email tidak sampai, tes suksesMasuk spam, atau Pengirim tidak diizinkan domain SMTP (SPF/DKIM). Pakai alamat pengirim milik domain SMTP.
TimeoutEndpoint lambat > 10 detik atau tidak terjangkau dari container API. Balas cepat (204) lalu proses async.
Belum tersedia
Notifikasi per project atau per aplikasi (channel berlaku platform-wide); event untuk stack compose selain deploy gagal; ringkasan harian.

Langkah berikutnya

Ada yang keliru? Edit halaman ini di GitHub ↗