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_URLbisa 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
- 01pushgit push origin main
- 02providerGitHub/GitLab memanggil Webhook URL
- 03verifikasitoken URL (+ tanda tangan bila secret aktif)
- 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.
Buat token di provider
Provider Jenis token Scope minimum GitHub Fine-grained atau classic PAT Classic: repo. Fine-grained: Contents → Read.GitLab Project/Personal access token read_repositoryGenerik Username + password/token HTTP basic Akses baca Integrasi → Kredensial Git → Kredensial Git baru (owner/admin)
Pilih Provider, isi Username dan Password / token. Token disimpan terenkripsi (
ENCRYPTION_KEY) dan tidak ditampilkan lagi.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
Salin Webhook URL dari tab Webhook
https://api.panel.example.com/webhooks/9f3a1c…e21dToken 32 byte acak, unik per aplikasi. Buat ulang kapan saja — URL lama langsung tidak berlaku.
Daftarkan di provider
GitHub
Field Nilai Payload URL Webhook URL Content type application/jsonSecret Isi bila secret diaktifkan (langkah berikutnya) Events Just the push event; tambah Pull requests untuk preview GitLab
Field Nilai URL Webhook URL Secret token Isi bila secret diaktifkan Trigger Push events; tambah Merge request events untuk preview 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
pingselaluignored, 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
| Situasi | Status | Body |
|---|---|---|
| Push ke branch aplikasi | 200 | { result: "queued" } — deploy diantrekan |
| Push ke branch lain / event bukan push / branch dihapus | 200 | ignored + reason yang menjelaskan |
| Masih ada deployment berjalan | 200 | busy — tidak diantre; push lagi setelah selesai |
| PR/MR dibuka, diperbarui, ditutup (preview aktif) | 200 | preview / preview-closed |
| Secret aktif tapi tanda tangan salah/hilang | 401 | Ditolak |
| Token URL tidak dikenal | 404 | Ditolak |
| Lebih dari 30 request/menit | 429 | Throttle |
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
GitHub
Repo → Settings → Webhooks
Klik webhook yang dipakai aoox (Edit).
Tab Recent Deliveries
Klik delivery paling atas (yang terbaru).
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
Settings → Webhooks → Edit
Buka bagian Recent events di bawah form.
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):
Klik aktifkan, salin nilai secret
Ditampilkan di tab Webhook selama aktif supaya bisa disalin ulang.
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.
- GitHub: field Secret → header
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=truedi.env.distagar 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 setelahaoox 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
| Gejala | Penyebab & solusi |
|---|---|
| Provider: connection refused / timeout | PUBLIC_API_URL tidak bisa dijangkau dari internet, atau port 3001 tertutup firewall. |
| 200 ignored padahal push ke branch benar | Branch di form aplikasi berbeda (mis. master vs main), atau event yang dikirim bukan push. |
| Selalu 401 setelah mengaktifkan secret | Content type GitHub bukan application/json, atau secret belum ditempel/berbeda. |
| Deploy jalan tapi build gagal: repository not found | Repo privat tanpa Kredensial Git, atau token kedaluwarsa. |
| URL di tab Webhook masih menampilkan localhost:3001 padahal panel sudah pakai domain | Instalasi 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: 404 | Payload 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 diperbaiki | Status itu hanya diperbarui setelah ada delivery baru — lihat Redeliver: uji ulang tanpa push baru. |
| Membedakan dua jenis 404 | Body 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). |
busy; webhook untuk stack compose.Langkah berikutnya
Ada yang keliru? Edit halaman ini di GitHub ↗