199 lines
6.6 KiB
Markdown
199 lines
6.6 KiB
Markdown
# 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 150–200 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` |
|