Files
cabutan-bertuah-koipb/DEPLOYMENT.md
2026-06-24 20:35:01 +08:00

199 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DEPLOYMENT.md — Sistem MAT KOIPB (Docker · Ubuntu Server)
Panduan deploy aplikasi **Kehadiran & Cabutan Bertuah MAT KOIPB** menggunakan Docker pada server Ubuntu. Stack: **Nginx + PHP 8.4-FPM (Laravel) + MariaDB 11** — semua dalam container, tiada pemasangan PHP/DB pada host.
> **Kenapa MariaDB, bukan MySQL 8?** Imej `mysql:8` (Oracle Linux) memerlukan CPU aras **x86-64-v2** dan akan crash (`Fatal glibc error: CPU does not support x86-64-v2`) pada CPU/VM lama atau jenis CPU VM generik (`qemu64`/`kvm64`). MariaDB serasi penuh dengan Laravel (`DB_CONNECTION=mysql` kekal) dan berjalan pada CPU lama.
> UI guna CDN + CSS statik (`public/css/koipb.css`) — **tiada langkah build Node/Vite**.
---
## Keperluan Server
| Komponen | Minimum | Disyorkan |
|---|---|---|
| OS | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| CPU | 2 core | 4 core |
| RAM | 2 GB | 4 GB |
| Storage | 10 GB | 20 GB |
| Docker | 24.x | Latest stable |
| Docker Compose | 2.x | Latest stable |
Untuk 150200 peserta, server kecil sudah memadai.
---
## Struktur Fail Docker
```
/srv/koipb/
├── .env.docker # disalin dari .env.docker.example (JANGAN commit)
├── .env.docker.example # templat
├── Dockerfile # imej PHP-FPM (Laravel)
├── docker-compose.yml # dev (nginx + app + mysql)
├── docker-compose.prod.yml # override production
├── docker/
│ ├── entrypoint.sh # wait-db, composer, key:generate, migrate, seed, cache
│ ├── nginx/default.conf
│ └── php/{php.ini, php-dev.ini, php-prod.ini}
└── ... (kod Laravel)
```
---
## Langkah Deployment Pertama Kali
### 1. Persediaan server
```bash
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker --version && docker compose version
```
### 2. Dapatkan kod
```bash
sudo mkdir -p /srv/koipb && sudo chown $USER:$USER /srv/koipb
cd /srv/koipb
git clone <repo-url> .
```
### 3. Konfigurasi environment
```bash
cp .env.docker.example .env.docker
nano .env.docker
```
> Guna nama fail **`.env.docker`** (bukan `.env`) supaya tidak berlanggar dengan `.env` tempatan untuk `php artisan serve`.
Wajib tukar:
| Pemboleh ubah | Nota |
|---|---|
| `APP_KEY` | Biar kosong — entrypoint jana automatik kali pertama |
| `APP_URL` | cth `https://mat.koipb.gov.my` |
| `APP_PORT` | Port loopback unik (cth `8009`) — host nginx reverse-proxy ke sini. Elak langgar projek lain (spr2026=8007, taklimat=8008) |
| `DB_PASSWORD` **dan** `MYSQL_PASSWORD` | password user `koipb`**mesti sama** |
| `MYSQL_ROOT_PASSWORD` | password root MySQL container |
| `SEED_DEMO` | `true` = isi 200 anggota + 21 hadiah contoh; `false` = data kosong (import sendiri) |
> `DB_HOST`/`MYSQL_*` jangan diubah namanya. `MYSQL_USER` mesti `koipb` (BUKAN `root` — MySQL menolaknya).
### 4. Logo
```bash
# Letak logo sebenar (kalau belum):
cp /path/ke/logo.jpg public/images/logo-koipb.jpg
```
### 5. Bina & jalankan (production)
```bash
docker compose --env-file .env.docker \
-f docker-compose.yml -f docker-compose.prod.yml up -d --build
```
Entrypoint akan automatik: tunggu MySQL → composer install → `key:generate``migrate --force` → seed peranan/pengguna (+ demo jika `SEED_DEMO=true`) → cache config/route/view.
Semak:
```bash
docker compose ps
docker compose logs -f app # tunggu "✅ Aplikasi bersedia."
```
Buka `http://<IP-server>` (atau `APP_URL`).
---
## Login Default
Kata laluan semua: **`password`** — **WAJIB tukar selepas log masuk pertama** (atau ubah dalam `RoleUserSeeder` sebelum deploy).
| Peranan | E-mel |
|---|---|
| Admin | `admin@koipb.test` |
| Petugas Kaunter | `kaunter@koipb.test` |
| Petugas Cabutan | `cabutan@koipb.test` |
---
## Operasi Harian
```bash
# Status / log
docker compose ps
docker compose logs -f app
# Masuk shell artisan
docker compose exec app php artisan <command>
# Backup database (penting sebelum & selepas event!)
docker compose exec mysql sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" koipb_mat' > backup-$(date +%F-%H%M).sql
# Restore
cat backup.sql | docker compose exec -T mysql sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD" koipb_mat'
# Henti / mula semula
docker compose --env-file .env.docker -f docker-compose.yml -f docker-compose.prod.yml down
docker compose --env-file .env.docker -f docker-compose.yml -f docker-compose.prod.yml up -d
```
> Data MySQL kekal dalam named volume **`koipb_db_data`** walaupun container dipadam. `docker compose down` (tanpa `-v`) **tidak** memadam data. **Jangan** guna `down -v` semasa event.
---
## Kemaskini Versi (Redeploy)
```bash
cd /srv/koipb
git pull
docker compose --env-file .env.docker -f docker-compose.yml -f docker-compose.prod.yml up -d --build
# Entrypoint akan migrate + cache semula automatik.
```
---
## Reverse Proxy + HTTPS (host nginx)
Server ini sudah ada **host nginx** yang dedah domain awam dan proksi ke port loopback setiap projek (spr2026 → 8007, taklimat → 8008). KOIPB guna **8009** (`APP_PORT=8009`, diikat `127.0.0.1:8009:80`).
Tambah vhost host nginx (cth `/etc/nginx/sites-available/koipb.conf`):
```nginx
server {
server_name mat.koipb.gov.my;
location / {
proxy_pass http://127.0.0.1:8009;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
Kemudian:
```bash
sudo ln -s /etc/nginx/sites-available/koipb.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d mat.koipb.gov.my # HTTPS
```
---
## Penyelesaian Masalah
| Masalah | Tindakan |
|---|---|
| `address already in use` (port) | Port `APP_PORT` dah diguna projek lain. Tukar ke port loopback bebas dalam `.env.docker` (cth `8009`) & `up` semula |
| MySQL `CPU does not support x86-64-v2` | Guna `mariadb:11.4` (sudah ditetapkan), bukan `mysql:8` |
| `app` asyik restart | `docker compose logs app` — biasanya DB belum sedia, `.env.docker` salah, atau cache `bootstrap/cache/config.php` basi |
| `419 Page Expired` / log masuk gagal | `APP_KEY` kosong — `docker compose exec app php artisan key:generate --force` lalu `docker compose restart app` |
| 502 Bad Gateway | container `app` belum naik / belum siap `composer install`; tunggu log "Aplikasi bersedia" |
| Tukar `.env` tak berkesan | `docker compose exec app php artisan config:clear` dan restart |
| Reset data untuk event baharu | Log masuk admin → **Tetapan & Reset**, atau `docker compose exec app php artisan migrate:fresh --seed --force` |