From fb4739e4078acb2f7e40dcfbb89ed190aef1477e Mon Sep 17 00:00:00 2001 From: Saufi Date: Tue, 16 Jun 2026 16:35:16 +0800 Subject: [PATCH] webhook --- .gitattributes | 4 ++ deploy/README.md | 73 ++++++++++++++++++++++++++++++++ deploy/deploy.sh | 33 +++++++++++++++ deploy/hooks.json | 27 ++++++++++++ deploy/myansuran-webhook.service | 15 +++++++ docker/php-apache/Dockerfile | 9 +++- docker/php-apache/entrypoint.sh | 17 ++++++++ 7 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 deploy/README.md create mode 100644 deploy/deploy.sh create mode 100644 deploy/hooks.json create mode 100644 deploy/myansuran-webhook.service create mode 100644 docker/php-apache/entrypoint.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..047d409 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Pastikan skrip shell sentiasa guna line ending LF walaupun di-commit dari Windows. +*.sh text eol=lf +deploy/deploy.sh text eol=lf +docker/php-apache/entrypoint.sh text eol=lf diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..d28e6b6 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,73 @@ +# Auto-deploy via Git Webhook + +Bila ada `git push` ke Gitea, Gitea hantar webhook ke server. Server tarik kod +terbaru dan jalankan `docker compose up --build -d` secara automatik. + +Aliran: **push → Gitea webhook → `webhook` listener (port 9000) → `deploy.sh`** + +--- + +## 1. Setup di server production (sekali sahaja) + +Andaikan repo berada di `/opt/myansuran` (laraskan path dalam `hooks.json` +dan `myansuran-webhook.service` jika berbeza). + +```bash +# a) Pasang webhook listener +sudo apt-get update && sudo apt-get install -y webhook + +# b) Pastikan user 'deploy' wujud & ahli group docker (boleh tukar nama user) +sudo useradd -m -G docker deploy 2>/dev/null || sudo usermod -aG docker deploy + +# c) Pastikan skrip executable +chmod +x /opt/myansuran/deploy/deploy.sh + +# d) Set secret rahsia dalam hooks.json (ganti GANTI_DENGAN_SECRET_RAHSIA) +# Jana satu secret kuat: +openssl rand -hex 32 +# Lepas tu edit /opt/myansuran/deploy/hooks.json -> letak nilai itu pada "secret" + +# e) Pasang service systemd +sudo cp /opt/myansuran/deploy/myansuran-webhook.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable --now myansuran-webhook +sudo systemctl status myansuran-webhook +``` + +## 2. Setup webhook di Gitea + +Repo → **Settings → Webhooks → Add Webhook → Gitea**: + +- **Target URL:** `http://SERVER_IP:9000/hooks/myansuran-deploy` +- **HTTP Method:** `POST` +- **Content Type:** `application/json` +- **Secret:** secret SAMA seperti dalam `hooks.json` +- **Trigger:** Push events sahaja +- **Branch filter:** `main` + +Klik **Test Delivery** untuk uji. + +## 3. Uji manual + +```bash +# Jalankan deploy terus tanpa webhook (untuk debug) +/opt/myansuran/deploy/deploy.sh + +# Lihat log webhook +sudo journalctl -u myansuran-webhook -f +``` + +--- + +## Nota keselamatan + +- Port `9000` hanya perlu dicapai oleh Gitea. Hadkan dengan firewall: + `sudo ufw allow from to any port 9000 proto tcp` +- Atau letak di belakang Nginx/Apache reverse proxy dengan HTTPS. +- Signature HMAC-SHA256 menghalang sesiapa tanpa secret daripada trigger deploy. + +## Tukar branch + +Default deploy branch ialah `main`. Untuk branch lain, set dalam service: +`ExecStart=... ` tambah `Environment=BRANCH=staging`, dan tukar `refs/heads/main` +dalam `hooks.json` kepada branch berkenaan. diff --git a/deploy/deploy.sh b/deploy/deploy.sh new file mode 100644 index 0000000..822a5b8 --- /dev/null +++ b/deploy/deploy.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Skrip deploy yang dipanggil oleh webhook bila ada push ke Gitea. +# Ia mengesan sendiri lokasi repo (folder induk kepada deploy/), +# tarik kod terbaru, dan bina semula container. +# +set -euo pipefail + +# Cabang yang akan di-deploy (boleh override: BRANCH=staging ./deploy.sh) +BRANCH="${BRANCH:-master}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="$(dirname "$SCRIPT_DIR")" +cd "$REPO_DIR" + +LOG() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } + +LOG "Mula deploy untuk $REPO_DIR (branch: $BRANCH)" + +# Tarik kod terbaru — reset --hard supaya server sentiasa padan dengan remote. +git fetch --prune origin +git reset --hard "origin/${BRANCH}" + +# Bina & start semula container +docker compose up --build -d + +# Bersihkan image lama supaya disk tak penuh +docker image prune -f >/dev/null 2>&1 || true + +# Optional: jalankan migration (buang komen kalau perlu) +# docker compose exec -T app php artisan migrate --force + +LOG "Deploy selesai." diff --git a/deploy/hooks.json b/deploy/hooks.json new file mode 100644 index 0000000..fdd2253 --- /dev/null +++ b/deploy/hooks.json @@ -0,0 +1,27 @@ +[ + { + "id": "myansuran-deploy", + "execute-command": "/opt/myansuran/deploy/deploy.sh", + "command-working-directory": "/opt/myansuran", + "response-message": "Deploy myansuran dicetuskan.", + "include-command-output-in-response": false, + "trigger-rule": { + "and": [ + { + "match": { + "type": "payload-hmac-sha256", + "secret": "GANTI_DENGAN_SECRET_RAHSIA", + "parameter": { "source": "header", "name": "X-Gitea-Signature" } + } + }, + { + "match": { + "type": "value", + "value": "refs/heads/main", + "parameter": { "source": "payload", "name": "ref" } + } + } + ] + } + } +] diff --git a/deploy/myansuran-webhook.service b/deploy/myansuran-webhook.service new file mode 100644 index 0000000..aabbb75 --- /dev/null +++ b/deploy/myansuran-webhook.service @@ -0,0 +1,15 @@ +[Unit] +Description=myAnsuran git deploy webhook listener +After=network.target docker.service +Requires=docker.service + +[Service] +# User mesti ahli group 'docker' supaya boleh jalankan docker compose tanpa sudo. +User=deploy +WorkingDirectory=/opt/myansuran +ExecStart=/usr/bin/webhook -hooks /opt/myansuran/deploy/hooks.json -port 9000 -verbose -hotreload +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/docker/php-apache/Dockerfile b/docker/php-apache/Dockerfile index fe9dc6f..1d69b14 100644 --- a/docker/php-apache/Dockerfile +++ b/docker/php-apache/Dockerfile @@ -19,7 +19,14 @@ RUN apt-get update && apt-get install -y \ COPY --from=composer:2 /usr/bin/composer /usr/bin/composer COPY docker/php-apache/vhost.conf /etc/apache2/sites-available/000-default.conf +COPY docker/php-apache/entrypoint.sh /usr/local/bin/entrypoint.sh WORKDIR /var/www/html -RUN chown -R www-data:www-data /var/www/html +# Buang CR (kalau fail di-checkout dengan line ending Windows) dan jadikan executable +RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh \ + && chmod +x /usr/local/bin/entrypoint.sh \ + && chown -R www-data:www-data /var/www/html + +ENTRYPOINT ["entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/docker/php-apache/entrypoint.sh b/docker/php-apache/entrypoint.sh new file mode 100644 index 0000000..5ddd227 --- /dev/null +++ b/docker/php-apache/entrypoint.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -e + +# Bind mount (./src:/var/www/html) menindih ownership dari image, jadi kita +# betulkan permission storage setiap kali container start — bukan masa build. +mkdir -p \ + storage/framework/cache/laravel-excel \ + storage/framework/sessions \ + storage/framework/views \ + storage/logs \ + bootstrap/cache + +chown -R www-data:www-data storage bootstrap/cache +chmod -R 775 storage bootstrap/cache + +# Jalankan arahan utama container (apache2-foreground) +exec "$@"