# Setup Redis + OPcache + PHP-FPM di aaPanel

> **Spesifikasi Server**: 2 CPU / 12GB RAM
>
> Dengan 12GB RAM, formula: `(12GB - 2GB untuk system/MySQL/Redis) / 30MB per process = ~330 max_children`
>
> Tapi dengan 2 CPU, rekomendasi **80-100 workers** (CPU jadi bottleneck, bukan RAM).

---

## Step 1: Install Redis Server

Di aaPanel dashboard:

1. **App Store** → cari **Redis** → **Install**
2. Setelah terinstall, Redis otomatis jalan di `127.0.0.1:6379`

### Konfigurasi Redis (Opsional, untuk performa maksimal)

Masuk ke **Redis** → **Settings** → **Config**, ubah:

```ini
# Memory limit (1GB cukup untuk beberapa aplikasi)
maxmemory 1gb

# Eviction policy: hapus key yang jarang diakses saat memory penuh
maxmemory-policy allkeys-lru

# Disable snapshot ke disk (lebih cepat, data session/cache ga perlu persist)
save ""

# TCP backlog (handle banyak koneksi)
tcp-backlog 511
```

---

## Step 2: Install Redis Extension PHP

1. **App Store** → klik **PHP 8.2** (yang terinstall) → **Settings**
2. Tab **Install Extension**
3. Cari **redis** → klik **Install**
4. Cari **opcache** → pastikan sudah **Installed** (biasanya sudah default)

---

## Step 3: Konfigurasi PHP-FPM (80 Workers)

> **Kenapa 80?** Dengan 2 CPU, setiap CPU optimal handle ~40 workers.
> 12GB RAM bisa support sampai 330 workers tapi CPU 2 core jadi bottleneck.
> 80 workers = sweet spot untuk 2 CPU / 12GB RAM.

1. **App Store** → **PHP 8.2** → **Settings**
2. Tab **FPM Config** atau **Performance Adjustment**
3. Ubah nilai berikut:

```ini
pm = dynamic

; === MAX CHILDREN ===
; 2 CPU × 40 workers/CPU = 80
; Bisa handle ~400 concurrent users
pm.max_children = 80

; Start dengan 10 workers langsung siap
pm.start_servers = 10

; Minimal 5 workers standby (siap terima request instant)
pm.min_spare_servers = 5

; Maksimal 20 workers idle (hemat memory saat sepi)
pm.max_spare_servers = 20

; Respawn worker setiap 500 request (cegah memory leak)
pm.max_requests = 500

; Kill worker yang stuck lebih dari 30 detik
request_terminate_timeout = 30

; Log request yang lambat lebih dari 5 detik (untuk debugging)
request_slowlog_timeout = 5
slowlog = /www/wwwlogs/php-slow.log
```

Atau edit file langsung via SSH:
```bash
nano /www/server/php/82/etc/php-fpm.d/www.conf
```

Lalu restart PHP:
```bash
/etc/init.d/php-fpm-82 restart
```

---

## Step 4: Konfigurasi OPcache

1. **PHP 8.2** → **Settings** → tab **Config File** (atau **php.ini**)
2. Cari section `[opcache]`, ubah menjadi:

```ini
[opcache]
; === AKTIFKAN ===
opcache.enable=1
opcache.enable_cli=0

; === MEMORY (RAM 12GB, bisa generous) ===
opcache.memory_consumption=256
opcache.interned_strings_buffer=32

; === FILE CACHE ===
opcache.max_accelerated_files=20000

; === PRODUCTION: jangan cek perubahan file ===
; Set ke 0 untuk production (max speed)
; Set ke 1 saat development/debugging
opcache.validate_timestamps=0
opcache.revalidate_freq=0

; === PERFORMANCE ===
opcache.fast_shutdown=1
opcache.optimization_level=0x7FFEBFFF

; === JIT (PHP 8.2+) ===
opcache.jit=tracing
opcache.jit_buffer_size=128M

; === FILE CACHE BACKUP ===
opcache.file_cache=/tmp/opcache
```

Atau edit via SSH:
```bash
nano /www/server/php/82/etc/php.ini
```

> ⚠️ **PENTING**: Karena `validate_timestamps=0`, setiap kali deploy kode baru, jalankan:
> ```bash
> # Reset OPcache agar membaca file baru
> /etc/init.d/php-fpm-82 restart
> ```

---

## Step 5: Konfigurasi php.ini Tambahan

Di **php.ini** yang sama, update juga:

```ini
; === MEMORY & EXECUTION ===
memory_limit = 512M
max_execution_time = 30
max_input_time = 60
max_input_vars = 5000

; === UPLOAD ===
upload_max_filesize = 50M
post_max_size = 55M

; === SESSION VIA REDIS ===
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?database=1"

; === SECURITY ===
expose_php = Off

; === REALPATH CACHE (bantu OPcache) ===
realpath_cache_size = 4096K
realpath_cache_ttl = 600

; === TIMEZONE ===
date.timezone = Asia/Jakarta
```

Restart PHP setelah edit:
```bash
/etc/init.d/php-fpm-82 restart
```

---

## Step 6: Update `.env` Laravel

Edit file `.env` project di server:

```bash
nano /www/wwwroot/cbt-ma-sayyid-ahmad.eduschool.my.id/.env
```

Ubah bagian ini:

```env
# =============================================
# Session → Redis (sebelumnya database)
# =============================================
SESSION_DRIVER=redis

# =============================================
# Cache → Redis (sebelumnya database)
# =============================================
CACHE_STORE=redis

# =============================================
# Queue → Redis (sebelumnya database)
# =============================================
QUEUE_CONNECTION=redis

# =============================================
# Redis Config
# =============================================
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
```

---

## Step 7: Clear & Cache Ulang Laravel

```bash
cd /www/wwwroot/cbt-ma-sayyid-ahmad.eduschool.my.id

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan queue:restart
```

---

## Step 8: Setup Queue Worker (Supervisor)

Install supervisor:
```bash
apt install supervisor -y
```

Buat config:
```bash
nano /etc/supervisor/conf.d/laravel-queue.conf
```

Isi:
```ini
[program:laravel-queue]
command=/www/server/php/82/bin/php /www/wwwroot/cbt-ma-sayyid-ahmad.eduschool.my.id/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 --memory=256
autostart=true
autorestart=true
numprocs=2
process_name=%(program_name)s_%(process_num)02d
user=www
stdout_logfile=/www/wwwlogs/queue.log
stderr_logfile=/www/wwwlogs/queue-error.log
stopwaitsecs=60
stopsignal=SIGTERM
```

Start:
```bash
supervisorctl reread
supervisorctl update
supervisorctl start laravel-queue:*
```

---

## Step 9: Optimasi Nginx (Opsional)

Di aaPanel → **Website** → klik site → **Config** (nginx config), tambahkan di dalam block `server {}`:

```nginx
# === GZIP ===
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;

# === STATIC ASSETS CACHE ===
location ~* \.(css|js|jpg|jpeg|gif|png|ico|svg|woff|woff2|webp)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

# === VITE BUILD ASSETS ===
location /build/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

# === SECURITY ===
location ~ /\. { deny all; }
```

---

## Step 10: Verifikasi

SSH ke server lalu jalankan:

```bash
# 1. Cek Redis extension
php -m | grep redis
# Output: redis ✅

# 2. Cek OPcache via FPM 
# Buat file dulu
echo "<?php echo json_encode(opcache_get_status(false));" > /www/wwwroot/cbt.mtsnjayapura.eduschool.my.id/public/opcache-check.php

# Baru curl (pakai domain)
curl -s https://cbt.mtsnjayapura.eduschool.my.id/opcache-check.php | head -c 200

# Hapus setelah selesai
rm /www/wwwroot/cbt.mtsnjayapura.eduschool.my.id/public/opcache-check.php

# Output: "opcache_enabled": true ✅

# 3. Cek FPM max_children
cat /www/server/php/82/etc/php-fpm.d/www.conf | grep pm.max_children
# Output: pm.max_children = 80 ✅

# 4. Cek Laravel drivers
cd /www/wwwroot/cbt.mtsnjayapura.eduschool.my.id
php artisan tinker --execute="
dump('Cache: ' . config('cache.default'));
dump('Session: ' . config('session.driver'));
dump('Queue: ' . config('queue.default'));
"
# Output: Cache: redis, Session: redis, Queue: redis ✅

# 5. Cek Redis connection
php artisan tinker --execute="dump(Illuminate\Support\Facades\Redis::ping());"
# Output: true ✅

# 6. Test Redis cache
php artisan tinker --execute="
Illuminate\Support\Facades\Cache::put('test', 'berhasil', 60);
dump(Illuminate\Support\Facades\Cache::get('test'));
"
# Output: "berhasil" ✅

# 7. Cek supervisor queue
supervisorctl status
# Output: laravel-queue:* RUNNING ✅
```

---

## Estimasi Performa (2 CPU / 12GB RAM)

| Metrik | Sebelum (Database) | Sesudah (Redis+OPcache) |
|--------|-------------------|------------------------|
| PHP-FPM Workers | 5-10 | **80** |
| Session lookup | ~5ms (MySQL) | **~0.1ms (Redis)** |
| Cache lookup | ~5ms (MySQL) | **~0.1ms (Redis)** |
| MySQL query/detik | ~715 | **~286 (−60%)** |
| Response time | 200-500ms | **15-50ms** |
| Max concurrent users | ~50 (lalu 522) | **~400** |
| CPU usage per request | Tinggi (compile PHP) | **Rendah (OPcache)** |

---

## Ringkasan

| Step | Apa yang Dilakukan | Dimana |
|------|-------------------|--------|
| 1 | Install Redis Server | aaPanel App Store |
| 2 | Install Redis PHP Extension | PHP Settings → Extensions |
| 3 | Ubah FPM max_children = **80** | PHP Settings → FPM Config |
| 4 | Konfigurasi OPcache + JIT | PHP Settings → php.ini |
| 5 | php.ini: memory, session redis | PHP Settings → php.ini |
| 6 | Ubah .env (session/cache/queue → redis) | File .env di project |
| 7 | Laravel cache commands | Terminal SSH |
| 8 | Setup Supervisor queue worker | Terminal SSH |
| 9 | Optimasi Nginx (gzip, cache) | Website → Config |
| 10 | Verifikasi semua aktif | Terminal SSH |

> ⚠️ **Penting**: Ganti `cbt-ma-sayyid-ahmad.eduschool.my.id` dengan path folder project kamu di aaPanel, dan `php-fpm-82` sesuai versi PHP yang terinstall.
>
> 💡 **Setelah deploy kode baru**, selalu jalankan:
> ```bash
> cd /www/wwwroot/cbt-ma-sayyid-ahmad.eduschool.my.id
> php artisan config:cache && php artisan route:cache && php artisan view:cache
> /etc/init.d/php-fpm-82 restart   # Reset OPcache
> ```