chore: update gitignore and add root docs and tooling
This commit is contained in:
@@ -0,0 +1,478 @@
|
||||
# Deployment Guide
|
||||
|
||||
Panduan instalasi aplikasi di server produksi **Ubuntu 22.04+**.
|
||||
|
||||
---
|
||||
|
||||
## Spesifikasi Server
|
||||
|
||||
| Komponen | Minimum | Rekomendasi |
|
||||
|----------|---------|-------------|
|
||||
| CPU | 2 core | 4 core |
|
||||
| RAM | 4 GB | 8 GB |
|
||||
| Storage | 40 GB SSD | 100 GB SSD |
|
||||
| OS | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
|
||||
|
||||
---
|
||||
|
||||
## Langkah 1 — Install Dependensi
|
||||
|
||||
```bash
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# PHP 8.3 + ekstensi
|
||||
sudo add-apt-repository ppa:ondrej/php -y
|
||||
sudo apt install -y php8.3 php8.3-fpm php8.3-pgsql php8.3-redis \
|
||||
php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip php8.3-gd \
|
||||
php8.3-bcmath php8.3-intl php8.3-readline
|
||||
|
||||
# PostgreSQL, Redis, Nginx, Supervisor
|
||||
sudo apt install -y postgresql postgresql-contrib redis-server nginx supervisor
|
||||
sudo systemctl enable redis-server
|
||||
|
||||
# Node.js 20
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
|
||||
# Composer
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
sudo mv composer.phar /usr/local/bin/composer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 2 — Setup Database
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE USER biiproject WITH PASSWORD 'password_kuat_anda';
|
||||
CREATE DATABASE biiproject_db OWNER biiproject;
|
||||
GRANT ALL PRIVILEGES ON DATABASE biiproject_db TO biiproject;
|
||||
\q
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 3 — Deploy Aplikasi
|
||||
|
||||
```bash
|
||||
cd /var/www
|
||||
sudo git clone <repo-url> html
|
||||
sudo chown -R $USER:www-data html
|
||||
cd html
|
||||
|
||||
composer install --no-dev --optimize-autoloader
|
||||
npm install && npm run build
|
||||
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
```
|
||||
|
||||
### Edit `.env`
|
||||
|
||||
```env
|
||||
APP_NAME="biiproject"
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_URL=https://domain.com
|
||||
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=biiproject_db
|
||||
DB_USERNAME=biiproject
|
||||
DB_PASSWORD=password_kuat_anda
|
||||
|
||||
CACHE_STORE=redis
|
||||
SESSION_DRIVER=redis
|
||||
QUEUE_CONNECTION=redis
|
||||
BROADCAST_CONNECTION=reverb
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
|
||||
REVERB_APP_ID=your-app-id
|
||||
REVERB_APP_KEY=your-app-key
|
||||
REVERB_APP_SECRET=your-app-secret
|
||||
REVERB_HOST=domain.com
|
||||
REVERB_PORT=8080
|
||||
REVERB_SCHEME=https
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
# Opsional — Error monitoring
|
||||
SENTRY_LARAVEL_DSN=https://xxxx@sentry.io/xxxx
|
||||
SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||
SENTRY_PROFILES_SAMPLE_RATE=0.1
|
||||
```
|
||||
|
||||
### Migrasi, Seed & Optimisasi
|
||||
|
||||
```bash
|
||||
php artisan migrate --force
|
||||
php artisan db:seed --force
|
||||
php artisan cache:clear # wajib setelah seeder
|
||||
php artisan storage:link
|
||||
php artisan optimize
|
||||
php artisan l5-swagger:generate # regen API docs
|
||||
```
|
||||
|
||||
### Post-Deploy Verification
|
||||
|
||||
```bash
|
||||
# Quality gate — pastikan tidak ada regresi
|
||||
./vendor/bin/phpstan analyse --memory-limit=1G
|
||||
./vendor/bin/pint --test
|
||||
composer audit --no-dev
|
||||
|
||||
# Health check
|
||||
curl -sf https://domain.com/api/health | jq .
|
||||
# expect: {"status":"healthy","timestamp":"...","checks":{...}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 4 — Konfigurasi Nginx
|
||||
|
||||
`/etc/nginx/sites-available/biiproject`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name domain.com;
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# WebSocket Reverb
|
||||
location /app {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location ~ /\.(?!well-known) { deny all; }
|
||||
}
|
||||
```
|
||||
|
||||
> **Catatan keamanan:** Laravel mengirim header `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, dan `Permissions-Policy` dari middleware `SecurityHeaders`. Tidak perlu duplikasi di Nginx — biarkan aplikasi yang kontrol (lebih mudah di-update via setting).
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/biiproject /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 5 — SSL (Let's Encrypt)
|
||||
|
||||
```bash
|
||||
sudo apt install -y certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d domain.com
|
||||
```
|
||||
|
||||
Setelah HTTPS aktif, **aktifkan HSTS** dari admin panel: Global Settings → Login Security → `HSTS Enabled`. Aplikasi akan mengirim header `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.
|
||||
|
||||
---
|
||||
|
||||
## Langkah 6 — Background Workers (Supervisor)
|
||||
|
||||
### Queue Worker
|
||||
|
||||
`/etc/supervisor/conf.d/biiproject-worker.conf`:
|
||||
|
||||
```ini
|
||||
[program:biiproject-worker]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
numprocs=2
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/www/html/storage/logs/worker.log
|
||||
```
|
||||
|
||||
### Reverb (WebSocket)
|
||||
|
||||
`/etc/supervisor/conf.d/biiproject-reverb.conf`:
|
||||
|
||||
```ini
|
||||
[program:biiproject-reverb]
|
||||
command=php /var/www/html/artisan reverb:start --host=0.0.0.0 --port=8080
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/www/html/storage/logs/reverb.log
|
||||
```
|
||||
|
||||
### Scheduler (Cron)
|
||||
|
||||
```bash
|
||||
echo "* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1" \
|
||||
| sudo crontab -u www-data -
|
||||
```
|
||||
|
||||
> Scheduler menjalankan `dashboard:broadcast-stats` setiap menit — membutuhkan queue worker dan Reverb **sudah berjalan** agar broadcast terkirim ke browser. Pastikan keduanya distart via Supervisor sebelum mengaktifkan cron.
|
||||
|
||||
### Aktifkan
|
||||
|
||||
```bash
|
||||
sudo supervisorctl reread
|
||||
sudo supervisorctl update
|
||||
sudo supervisorctl start all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 7 — Permission File
|
||||
|
||||
```bash
|
||||
sudo chown -R www-data:www-data /var/www/html
|
||||
sudo chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Langkah 8 — Konfigurasi Pasca-Deploy
|
||||
|
||||
### A. Global Settings
|
||||
|
||||
Login sebagai Super Admin → System Settings → Global Settings. Pastikan:
|
||||
|
||||
- [ ] `Password Policy`: min 12, charset mixed-case + digit + symbol, expiry & history sesuai kebijakan
|
||||
- [ ] `Login Security`: max attempts 5, lockout duration, 2FA toggle, captcha jika perlu
|
||||
- [ ] `IP & Access`: whitelist admin (IP kantor/VPN), auto-block on burst
|
||||
- [ ] `HSTS Enabled`: ON (setelah SSL aktif)
|
||||
- [ ] `Single Session`: ON jika kebijakan satu-device-per-akun
|
||||
|
||||
### B. Verifikasi Quality Gate
|
||||
|
||||
```bash
|
||||
# Pastikan dependencies aman
|
||||
composer audit --no-dev --abandoned=ignore
|
||||
|
||||
# Pastikan tidak ada regresi
|
||||
php artisan test --parallel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layanan Eksternal (Opsional)
|
||||
|
||||
Sebagian besar bisa diatur via **Global Settings** di admin panel — tidak perlu edit `.env`.
|
||||
|
||||
### Email SMTP
|
||||
|
||||
```env
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailgun.org
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=postmaster@domain.com
|
||||
MAIL_PASSWORD=xxxxxxxx
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=noreply@domain.com
|
||||
MAIL_FROM_NAME="biiproject"
|
||||
```
|
||||
|
||||
### Sentry (Error Monitoring)
|
||||
|
||||
```env
|
||||
SENTRY_LARAVEL_DSN=https://xxxx@o0.ingest.sentry.io/xxxx
|
||||
SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||
```
|
||||
|
||||
Buat project di [sentry.io](https://sentry.io), pilih platform **Laravel**, dan salin DSN-nya.
|
||||
|
||||
### Telegram Bot
|
||||
|
||||
1. Chat `@BotFather` → `/newbot` → simpan **Token**
|
||||
2. Kirim pesan ke bot, buka `https://api.telegram.org/bot<TOKEN>/getUpdates` → simpan **Chat ID**
|
||||
3. Masukkan via Global Settings → Notifications
|
||||
|
||||
> **Catatan:** `IpAccessControl` middleware mengirim alert otomatis ke Telegram saat sebuah IP di-auto-block karena burst — pastikan token + chat id valid.
|
||||
|
||||
### Google Drive Backup
|
||||
|
||||
1. Google Cloud Console → buat project → enable **Google Drive API**
|
||||
2. Buat **OAuth 2.0 Client ID** (Desktop app)
|
||||
3. Dapatkan **Refresh Token** via OAuth Playground
|
||||
4. Masukkan Client ID, Client Secret, Refresh Token, dan nama folder via Global Settings → Backup
|
||||
|
||||
### Amazon S3
|
||||
|
||||
1. Buat IAM user dengan policy `AmazonS3FullAccess`
|
||||
2. Buat S3 bucket
|
||||
3. Masukkan Access Key, Secret, Bucket, Region (dan endpoint opsional) via Global Settings → Backup
|
||||
|
||||
### Firebase Cloud Messaging (Push Notification Mobile)
|
||||
|
||||
1. Buat project di Firebase Console → Project Settings → Cloud Messaging
|
||||
2. Unduh `google-services.json` (Android) atau `GoogleService-Info.plist` (iOS)
|
||||
3. Letakkan di direktori mobile app sesuai panduan Expo
|
||||
4. Device token diregistrasikan otomatis via API `/api/v1/devices/register`
|
||||
|
||||
---
|
||||
|
||||
## CI/CD
|
||||
|
||||
Workflow di `.github/workflows/ci.yml`. Setiap push ke `main`/`develop`/`config`/`advanced` dan setiap PR ke `main`/`develop` menjalankan:
|
||||
|
||||
1. **Test** — `php artisan test --parallel` (Postgres 15 + Redis 7 service containers)
|
||||
2. **Lint** — `pint --test` + `composer audit --abandoned=ignore` + `permissions:audit`
|
||||
3. **Static Analysis** — `phpstan analyse --memory-limit=1G`
|
||||
|
||||
Branch protection: PR tidak bisa di-merge kalau salah satu job gagal.
|
||||
|
||||
---
|
||||
|
||||
## Update Aplikasi
|
||||
|
||||
Cara tercepat dan teraman untuk memperbarui aplikasi adalah menggunakan skrip deployment otomatis yang sudah disediakan:
|
||||
|
||||
```bash
|
||||
cd /var/www/html
|
||||
sudo chmod +x deploy.sh
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
Skrip ini akan melakukan:
|
||||
|
||||
1. Masuk ke Maintenance Mode.
|
||||
2. Update dependencies (Composer & NPM).
|
||||
3. Build assets (Vite).
|
||||
4. Run migrations.
|
||||
5. Optimasi cache & pembersihan log.
|
||||
6. Restart background workers (Queue & Reverb).
|
||||
7. Verifikasi kesehatan sistem.
|
||||
8. Keluar dari Maintenance Mode.
|
||||
|
||||
### Update Manual
|
||||
|
||||
```bash
|
||||
cd /var/www/html
|
||||
git pull origin main
|
||||
php artisan down --secret="your-bypass-key"
|
||||
|
||||
composer install --no-dev --optimize-autoloader
|
||||
npm ci && npm run build
|
||||
|
||||
php artisan migrate --force
|
||||
php artisan cache:clear
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
php artisan event:cache
|
||||
php artisan l5-swagger:generate
|
||||
|
||||
sudo supervisorctl restart biiproject-worker:*
|
||||
sudo supervisorctl restart biiproject-reverb
|
||||
|
||||
# Verifikasi
|
||||
curl -sf https://domain.com/api/health | jq -e '.checks.database.status == "ok"'
|
||||
|
||||
php artisan up
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment via Docker (alternatif)
|
||||
|
||||
```bash
|
||||
git clone <repo-url> Project
|
||||
cd Project
|
||||
cp .env.example .env
|
||||
|
||||
# Edit .env:
|
||||
# DB_HOST=pgsql (nama service Docker, bukan 127.0.0.1)
|
||||
# REDIS_HOST=redis
|
||||
|
||||
./vendor/bin/sail up -d
|
||||
./vendor/bin/sail artisan migrate --seed --force
|
||||
./vendor/bin/sail artisan cache:clear
|
||||
./vendor/bin/sail artisan optimize
|
||||
```
|
||||
|
||||
> **Penting:** Semua perintah `php artisan` di lingkungan Docker **harus** dijalankan via `./vendor/bin/sail artisan`, bukan langsung. Host `pgsql` hanya bisa di-resolve dari dalam Docker network.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Masalah | Solusi |
|
||||
|---------|--------|
|
||||
| 502 Bad Gateway | `sudo systemctl status php8.3-fpm` |
|
||||
| Queue tidak jalan | `sudo supervisorctl status` |
|
||||
| Permission denied | `sudo chown -R www-data:www-data storage bootstrap/cache` |
|
||||
| Cache error setelah update | `php artisan optimize:clear && php artisan optimize` |
|
||||
| Settings tidak muncul setelah seeder | `php artisan cache:clear` (settings di-cache 60 menit) |
|
||||
| WebSocket gagal connect | `sudo supervisorctl status biiproject-reverb` + cek port 8080 di firewall |
|
||||
| `pgsql` host tidak resolve | Pastikan `DB_HOST=127.0.0.1` (bukan `pgsql`) di server non-Docker |
|
||||
| Telescope/log tidak ditemukan | Cek `storage/logs/laravel.log` & menu System Monitoring → Logs |
|
||||
| Error monitoring tidak aktif | Pastikan `SENTRY_LARAVEL_DSN` sudah diset di `.env` |
|
||||
| `/api/health` return 503 | Cek setiap field `checks.*.status` — yang `fail` mengindikasikan masalah. `warn` (storage >90%) tetap 200 by design. |
|
||||
| OAuth callback 404 | Pastikan route order: `/auth/callback` HARUS sebelum `/auth/{provider}` di `routes/web.php`. |
|
||||
| `column "google_id" does not exist` | Pastikan migrasi `2026_05_12_120000_add_social_columns_to_users_table` sudah jalan. |
|
||||
| Dashboard stats tidak update real-time | Cek Reverb berjalan (`supervisorctl status biiproject-reverb`), queue worker aktif, dan `BROADCAST_CONNECTION=reverb` di `.env`. |
|
||||
| Dashboard widget tidak tersimpan | Pastikan migrasi `2026_05_16_220000_create_dashboard_widget_preferences_table` sudah dijalankan. |
|
||||
|
||||
---
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### PHP-FPM
|
||||
|
||||
`/etc/php/8.3/fpm/pool.d/www.conf`:
|
||||
|
||||
```ini
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 10
|
||||
pm.min_spare_servers = 5
|
||||
pm.max_spare_servers = 20
|
||||
```
|
||||
|
||||
### OPcache
|
||||
|
||||
`/etc/php/8.3/fpm/php.ini`:
|
||||
|
||||
```ini
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=256
|
||||
opcache.interned_strings_buffer=16
|
||||
opcache.max_accelerated_files=20000
|
||||
opcache.validate_timestamps=0 ; production only
|
||||
opcache.preload=/var/www/html/bootstrap/cache/preload.php
|
||||
opcache.preload_user=www-data
|
||||
```
|
||||
|
||||
### Redis Tuning
|
||||
|
||||
`/etc/redis/redis.conf`:
|
||||
|
||||
```
|
||||
maxmemory 1gb
|
||||
maxmemory-policy allkeys-lru
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
Tambah index recommendation: sudah ada (lihat migrasi `2026_05_14_100000_add_performance_indexes`). Untuk dataset besar (>10M rows pada `activity_log`), pertimbangkan `pg_partman` untuk partisi bulanan.
|
||||
Reference in New Issue
Block a user