$ aoox

DocsAplikasi

Webhook auto-deploy

Deploy otomatis setiap push ke branch aplikasi, dan kredensial Git untuk repo privat.

Pemicu
Push ke branch aplikasi
Endpoint
POST <PUBLIC_API_URL>/webhooks/<token>
Keamanan
Token di URL + secret HMAC opsional

Prasyarat

  • PUBLIC_API_URL bisa dijangkau dari internet — GitHub/GitLab memanggilnya dari luar. IP publik + port 3001, atau domain via Domain untuk panel.
  • Aplikasi sudah pernah di-deploy sekali secara manual (registry, build, dsb. sudah beres).

Alur

  1. 01pushgit push origin main
  2. 02providerGitHub/GitLab memanggil Webhook URL
  3. 03verifikasitoken URL (+ tanda tangan bila secret aktif)
  4. 04deploydiantrekan seperti tombol Deploy

Kredensial Git (repo privat)

Dibutuhkan agar daemon Docker (dan helper Nixpacks) bisa meng-clone repo privat. Tidak berhubungan dengan webhook masuk, tapi biasanya diatur bersamaan.

  1. Buat token di provider

    ProviderJenis tokenScope minimum
    GitHubFine-grained atau classic PATClassic: repo. Fine-grained: Contents → Read.
    GitLabProject/Personal access tokenread_repository
    GenerikUsername + password/token HTTP basicAkses baca
  2. Integrasi → Kredensial Git → Kredensial Git baru (owner/admin)

    Pilih Provider, isi Username dan Password / token. Token disimpan terenkripsi (ENCRYPTION_KEY) dan tidak ditampilkan lagi.

  3. Pilih di form aplikasi

    Select Kredensial Git di Pengaturan aplikasi. URL repo tetap ditulis tanpa user:token@ — aoox menyusunnya sendiri saat build dan menyensor token di log.

  • Menghapus kredensial melepasnya dari aplikasi yang memakainya; build berikutnya gagal bila repo privat.
  • Untuk GitHub fine-grained token, pastikan repo-nya termasuk dalam daftar akses token.

Mengaktifkan webhook

  1. Salin Webhook URL dari tab Webhook

    https://api.panel.example.com/webhooks/9f3a1c…e21d

    Token 32 byte acak, unik per aplikasi. Buat ulang kapan saja — URL lama langsung tidak berlaku.

  2. Daftarkan di provider

    GitHub

    FieldNilai
    Payload URLWebhook URL
    Content typeapplication/json
    SecretIsi bila secret diaktifkan (langkah berikutnya)
    EventsJust the push event; tambah Pull requests untuk preview

    GitLab

    FieldNilai
    URLWebhook URL
    Secret tokenIsi bila secret diaktifkan
    TriggerPush events; tambah Merge request events untuk preview
  3. Uji: push ke branch aplikasi

    Deployment baru muncul di tab Deploy beberapa detik setelah push. Di provider, halaman Recent Deliveries menampilkan respons API — lihat tabel di bawah untuk membacanya.

    Tanpa menunggu provider, tes langsung dari server dulu — event ping selalu ignored, aman dipakai untuk memastikan URL & token benar sebelum menyentuh GitHub/GitLab:

    curl -i -X POST https://<API_DOMAIN>/webhooks/<token> \
      -H "Content-Type: application/json" \
      -H "X-GitHub-Event: ping" \
      -d "{}"
    # harus 200 dengan body {"result":"ignored","reason":"event ping"}

Membaca respons webhook

SituasiStatusBody
Push ke branch aplikasi200{ result: "queued" } — deploy diantrekan
Push ke branch lain / event bukan push / branch dihapus200ignored + reason yang menjelaskan
Masih ada deployment berjalan200busy — tidak diantre; push lagi setelah selesai
PR/MR dibuka, diperbarui, ditutup (preview aktif)200preview / preview-closed
Secret aktif tapi tanda tangan salah/hilang401Ditolak
Token URL tidak dikenal404Ditolak
Lebih dari 30 request/menit429Throttle
busy berarti push saat build masih berjalan tidak diantre. Kalau alur kerja timmu sering push beruntun, biasakan menunggu deployment selesai, atau push sekali lagi setelahnya.

Redeliver: uji ulang tanpa push baru

Paling sering menyelesaikan masalah
Setelah memperbaiki Payload URL, secret, atau masalah di sisi API/proxy, jangan hanya menunggu — provider tidak mengirim ulang sendiri. Kirim ulang delivery yang sama lewat Redeliver (GitHub) / Resend request (GitLab) untuk langsung tahu apakah perbaikannya berhasil, tanpa perlu push commit baru.

GitHub

  1. Repo → Settings → Webhooks

    Klik webhook yang dipakai aoox (Edit).

  2. Tab Recent Deliveries

    Klik delivery paling atas (yang terbaru).

  3. Tombol Redeliver

    Buka tab Response setelahnya — harus 200. Status "Last delivery was not successful" di daftar webhook hanya diperbarui setelah ada delivery baru (redeliver atau push baru); memperbaiki penyebabnya saja tidak menghapus status merah itu sampai ada percobaan baru.

GitLab

  1. Settings → Webhooks → Edit

    Buka bagian Recent events di bawah form.

  2. Resend request

    Pada baris event yang gagal. Alternatif tanpa event lama sama sekali: tombol Test → pilih Push events untuk memicu pengiriman baru tanpa perlu push sungguhan.

Secret (tanda tangan)

Tanpa secret, siapa pun yang tahu URL bisa memicu deploy (bukan mengubah kode — hanya membangun ulang branch yang sama). Untuk menutupnya, di bagian Secret (tanda tangan):

  1. Klik aktifkan, salin nilai secret

    Ditampilkan di tab Webhook selama aktif supaya bisa disalin ulang.

  2. Tempel di provider

    • GitHub: field Secret → header X-Hub-Signature-256 = sha256=HMAC-SHA256(secret, raw body).
    • GitLab: field Secret token → header X-Gitlab-Token = secret apa adanya.
  3. Kirim ulang delivery terakhir dari provider

    Lihat Redeliver di atas. Harus 200. Bila 401, secret di provider tidak cocok.

  • Rotasi membuat nilai baru — perbarui di provider sebelum push berikutnya.
  • Nonaktifkan kembali ke perilaku token-URL saja.
  • Perbandingan memakai timingSafeEqual; HMAC dihitung atas byte body persis, bukan JSON hasil parse.
  • Lapis tambahan opsional untuk GitHub: tulis WEBHOOK_VERIFY_GITHUB_IP=true di .env.dist agar delivery GitHub yang bersecret juga harus datang dari rentang IP resmi GitHub (kosong = mati; jangan dinyalakan untuk GitHub Enterprise Server atau GitLab). Instalasi lama baru menerima variabel ini setelah aoox reinstall.

Monorepo: deploy hanya bila folder berubah

Aplikasi dengan Root directory (lihat Cara build) punya switch Webhook: deploy hanya bila file di folder ini berubah. Bila aktif, push yang hanya menyentuh folder lain dijawab ignored tanpa deployment. Default mati, jadi perilaku lama (setiap push ke branch men-deploy) tidak berubah.

  • aoox membaca daftar file per commit di payload push GitHub dan GitLab (added, modified, removed).
  • Bila tidak yakin, aoox tetap deploy. Itu berlaku saat payload tanpa daftar file, sebuah commit tanpa daftar file (merge commit di GitHub), push 20 commit atau lebih (batas payload kedua penyedia), force push, atau branch baru.
  • Perubahan di luar folder yang dipakai build (mis. packages/shared) tidak memicu deploy. Matikan switch-nya untuk aplikasi yang bergantung pada file di luar foldernya.
  • Berlaku untuk push ke branch aplikasi; event pull request untuk preview tidak difilter.

Jebakan umum

GejalaPenyebab & solusi
Provider: connection refused / timeoutPUBLIC_API_URL tidak bisa dijangkau dari internet, atau port 3001 tertutup firewall.
200 ignored padahal push ke branch benarBranch di form aplikasi berbeda (mis. master vs main), atau event yang dikirim bukan push.
Selalu 401 setelah mengaktifkan secretContent type GitHub bukan application/json, atau secret belum ditempel/berbeda.
Deploy jalan tapi build gagal: repository not foundRepo privat tanpa Kredensial Git, atau token kedaluwarsa.
URL di tab Webhook masih menampilkan localhost:3001 padahal panel sudah pakai domainInstalasi lama: PUBLIC_API_URL dulu hanya diteruskan ke container web, bukan api. Tambahkan PUBLIC_API_URL: ${PUBLIC_API_URL:-http://localhost:3001} ke environment: service api di docker-compose.dist.yml, lalu docker compose -f docker-compose.dist.yml -f docker-compose.override.yml --env-file .env.dist up -d. aoox update panel tidak menulis ulang file compose, jadi instalasi lama butuh langkah manual ini sekali.
GitHub: Invalid HTTP Response: 404Payload URL memakai domain dashboard/web (mis. panel.example.com/webhooks/…), bukan domain API — endpoint webhook ada di API; web (Next.js) yang membalas 404. Pakai https://<API_DOMAIN>/webhooks/<token> (salin dari tab Webhook), bukan domain panel.
“Last delivery was not successful” masih merah setelah diperbaikiStatus itu hanya diperbarui setelah ada delivery baru — lihat Redeliver: uji ulang tanpa push baru.
Membedakan dua jenis 404Body teks polos 404 page not found = ditolak Traefik (router domain API tidak cocok, atau domain itu belum menjangkau container API); body JSON {"statusCode":404,...} = sampai ke API tapi token di URL tidak dikenal (token lama setelah "Buat URL baru", atau salah salin).
Belum tersedia
Verifikasi IP provider; antrean deploy saat busy; webhook untuk stack compose.

Langkah berikutnya

Ada yang keliru? Edit halaman ini di GitHub ↗