351 lines
7.6 KiB
Markdown
351 lines
7.6 KiB
Markdown
# Production Server Checklist BizOne Portal
|
|
|
|
Panduan ini berisi langkah production `1-7` yang perlu dilakukan di server sebelum aplikasi BizOne Portal dipakai live.
|
|
|
|
Asumsi deployment:
|
|
|
|
- Domain: `portal.bizone.id`
|
|
- App path: `/srv/bizone-web`
|
|
- Backend: `127.0.0.1:3001`
|
|
- Frontend: `127.0.0.1:3000`
|
|
- PostgreSQL dan Redis memakai Docker Compose dari `deploy/debian12/docker-compose.infra.yml`
|
|
|
|
## 1. Bersihkan real secret dari repo dan rotate secret
|
|
|
|
File berikut tidak boleh berisi credential asli:
|
|
|
|
- `.env.example`
|
|
- `deploy/debian12/app.env.example`
|
|
- `README.md`
|
|
|
|
Isi semua secret di file example cukup memakai placeholder:
|
|
|
|
```dotenv
|
|
DATABASE_URL=postgresql://bizone:change-this-password@127.0.0.1:5432/wa_dashboard
|
|
JWT_SECRET=replace-with-32-plus-char-random-secret
|
|
JWT_REFRESH_SECRET=replace-with-32-plus-char-random-refresh-secret
|
|
WEBHOOK_VERIFY_TOKEN=replace-with-32-plus-char-random-token
|
|
WEBHOOK_SHARED_SECRET=replace-with-32-plus-char-random-secret
|
|
META_WEBHOOK_APP_SECRET=replace-with-real-meta-app-secret
|
|
MAIL_PASSWORD=replace-with-real-smtp-password
|
|
```
|
|
|
|
Di server, generate secret baru:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
openssl rand -hex 32
|
|
openssl rand -hex 32
|
|
openssl rand -hex 32
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
Gunakan hasil berbeda untuk:
|
|
|
|
- `JWT_SECRET`
|
|
- `JWT_REFRESH_SECRET`
|
|
- `WEBHOOK_VERIFY_TOKEN`
|
|
- `WEBHOOK_SHARED_SECRET`
|
|
- `META_WEBHOOK_APP_SECRET`
|
|
|
|
Jika secret lama pernah masuk repo, anggap bocor dan jangan dipakai lagi.
|
|
|
|
## 2. Siapkan `.env` production langsung di server
|
|
|
|
Masuk server:
|
|
|
|
```bash
|
|
ssh user@SERVER_IP
|
|
cd /srv/bizone-web
|
|
nano .env
|
|
```
|
|
|
|
Isi minimal seperti ini:
|
|
|
|
```dotenv
|
|
NODE_ENV=production
|
|
|
|
DATABASE_URL=postgresql://bizone:ISI_PASSWORD_DB_URL_ENCODED@127.0.0.1:5432/wa_dashboard
|
|
REDIS_URL=redis://127.0.0.1:6379
|
|
|
|
PORT=3001
|
|
FRONTEND_ORIGIN=https://portal.bizone.id
|
|
PUBLIC_API_URL=https://portal.bizone.id
|
|
INTERNAL_API_URL=http://127.0.0.1:3001/api
|
|
NEXT_PUBLIC_API_URL=https://portal.bizone.id/backend-api
|
|
|
|
JWT_SECRET=ISI_SECRET_BARU
|
|
JWT_EXPIRES_IN=1d
|
|
JWT_REFRESH_SECRET=ISI_REFRESH_SECRET_BARU
|
|
JWT_REFRESH_EXPIRES_IN=30d
|
|
|
|
WEBHOOK_VERIFY_TOKEN=ISI_VERIFY_TOKEN_BARU
|
|
WEBHOOK_SHARED_SECRET=ISI_SHARED_SECRET_BARU
|
|
META_WEBHOOK_APP_SECRET=ISI_META_APP_SECRET_BARU
|
|
WEBHOOK_ALLOW_UNSIGNED=false
|
|
|
|
MAIL_HOST=mail.bizone.id
|
|
MAIL_PORT=465
|
|
MAIL_SECURE=true
|
|
MAIL_USER=no-reply@bizone.id
|
|
MAIL_PASSWORD=ISI_PASSWORD_SMTP
|
|
MAIL_FROM=BizOne Portal <no-reply@bizone.id>
|
|
|
|
AUTH_LOGIN_MAX_ATTEMPTS=5
|
|
AUTH_LOGIN_WINDOW_MINUTES=15
|
|
AUTH_2FA_MAX_ATTEMPTS=5
|
|
AUTH_2FA_WINDOW_MINUTES=10
|
|
AUTH_PASSWORD_RESET_MAX_ATTEMPTS=3
|
|
AUTH_PASSWORD_RESET_WINDOW_MINUTES=30
|
|
```
|
|
|
|
Amankan permission file `.env`:
|
|
|
|
```bash
|
|
sudo chown bizone:bizone /srv/bizone-web/.env
|
|
sudo chmod 600 /srv/bizone-web/.env
|
|
```
|
|
|
|
Load env untuk command manual:
|
|
|
|
```bash
|
|
cd /srv/bizone-web
|
|
set -a
|
|
source .env
|
|
set +a
|
|
```
|
|
|
|
## 3. Jalankan build backend dan frontend
|
|
|
|
Install dependency root untuk Prisma:
|
|
|
|
```bash
|
|
cd /srv/bizone-web
|
|
npm install
|
|
```
|
|
|
|
Build backend:
|
|
|
|
```bash
|
|
cd /srv/bizone-web/backend
|
|
npm install
|
|
npm run db:generate
|
|
npm run build
|
|
```
|
|
|
|
Build frontend:
|
|
|
|
```bash
|
|
cd /srv/bizone-web/frontend
|
|
npm install
|
|
npm run build
|
|
```
|
|
|
|
Jika build gagal, jangan lanjut deploy. Bereskan error terlebih dahulu.
|
|
|
|
## 4. Jalankan database migration deploy
|
|
|
|
Pastikan PostgreSQL dan Redis hidup:
|
|
|
|
```bash
|
|
cd /srv/bizone-web/deploy/debian12
|
|
docker compose -f docker-compose.infra.yml up -d
|
|
docker compose -f docker-compose.infra.yml ps
|
|
```
|
|
|
|
Jalankan migration:
|
|
|
|
```bash
|
|
cd /srv/bizone-web
|
|
set -a
|
|
source .env
|
|
set +a
|
|
|
|
cd backend
|
|
npm run db:migrate:deploy
|
|
```
|
|
|
|
Jika database masih kosong dan butuh admin awal:
|
|
|
|
```bash
|
|
npm run seed:admin
|
|
```
|
|
|
|
Setelah login pertama, langsung ganti password admin dan aktifkan 2FA.
|
|
|
|
## 5. Tambahkan nginx security headers
|
|
|
|
Edit config nginx:
|
|
|
|
```bash
|
|
sudo nano /etc/nginx/sites-available/portal.bizone.id
|
|
```
|
|
|
|
Di dalam blok `server { ... }`, tambahkan:
|
|
|
|
```nginx
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
```
|
|
|
|
Pastikan route penting tetap seperti ini:
|
|
|
|
```nginx
|
|
location = /api/health {
|
|
proxy_pass http://127.0.0.1:3001/api/health;
|
|
proxy_http_version 1.1;
|
|
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;
|
|
}
|
|
|
|
location /api/webhooks/ {
|
|
proxy_pass http://127.0.0.1:3001/api/webhooks/;
|
|
proxy_http_version 1.1;
|
|
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;
|
|
}
|
|
|
|
location /backend-api/ {
|
|
proxy_pass http://127.0.0.1:3001/api/;
|
|
proxy_http_version 1.1;
|
|
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;
|
|
}
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3000;
|
|
proxy_http_version 1.1;
|
|
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;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
```
|
|
|
|
Test dan reload nginx:
|
|
|
|
```bash
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
## 6. Deploy via systemd
|
|
|
|
Copy service files:
|
|
|
|
```bash
|
|
sudo cp /srv/bizone-web/deploy/debian12/bizone-backend.service /etc/systemd/system/
|
|
sudo cp /srv/bizone-web/deploy/debian12/bizone-frontend.service /etc/systemd/system/
|
|
```
|
|
|
|
Reload systemd:
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
```
|
|
|
|
Enable service:
|
|
|
|
```bash
|
|
sudo systemctl enable bizone-backend
|
|
sudo systemctl enable bizone-frontend
|
|
```
|
|
|
|
Start atau restart service:
|
|
|
|
```bash
|
|
sudo systemctl restart bizone-backend
|
|
sudo systemctl restart bizone-frontend
|
|
```
|
|
|
|
Cek status:
|
|
|
|
```bash
|
|
sudo systemctl status bizone-backend
|
|
sudo systemctl status bizone-frontend
|
|
```
|
|
|
|
Lihat log kalau ada error:
|
|
|
|
```bash
|
|
sudo journalctl -u bizone-backend -f
|
|
sudo journalctl -u bizone-frontend -f
|
|
```
|
|
|
|
## 7. Smoke test production
|
|
|
|
Cek backend health:
|
|
|
|
```bash
|
|
curl https://portal.bizone.id/api/health
|
|
curl https://portal.bizone.id/backend-api/health
|
|
```
|
|
|
|
Response ideal:
|
|
|
|
```json
|
|
{"status":"ok","service":"wa-dashboard-backend","database":"ok"}
|
|
```
|
|
|
|
Cek frontend:
|
|
|
|
```bash
|
|
curl -I https://portal.bizone.id
|
|
```
|
|
|
|
Cek service:
|
|
|
|
```bash
|
|
sudo systemctl is-active bizone-backend
|
|
sudo systemctl is-active bizone-frontend
|
|
docker compose -f /srv/bizone-web/deploy/debian12/docker-compose.infra.yml ps
|
|
```
|
|
|
|
Test manual dari browser:
|
|
|
|
1. Buka `https://portal.bizone.id`.
|
|
2. Login admin.
|
|
3. Ganti password admin default.
|
|
4. Aktifkan 2FA.
|
|
5. Buka dashboard.
|
|
6. Buka `Settings > WhatsApp API Setting`.
|
|
7. Pastikan secret tidak tampil sebagai plain text di production.
|
|
8. Buka `Webhook Logs`.
|
|
9. Test webhook verification dari Meta.
|
|
10. Kirim pesan WhatsApp ke nomor bisnis.
|
|
11. Pastikan pesan masuk di Conversations.
|
|
12. Balas dari dashboard jika token Meta dan phone number ID sudah benar.
|
|
|
|
Meta callback production:
|
|
|
|
```text
|
|
https://portal.bizone.id/api/webhooks/whatsapp
|
|
```
|
|
|
|
Verify token:
|
|
|
|
```text
|
|
Pakai nilai WEBHOOK_VERIFY_TOKEN dari .env production.
|
|
```
|
|
|
|
## Catatan setelah smoke test
|
|
|
|
Jika semua smoke test lolos, lanjutkan dengan hardening tambahan:
|
|
|
|
- Setup backup PostgreSQL terjadwal.
|
|
- Setup monitor uptime ke `/api/health`.
|
|
- Setup log retention `journald`.
|
|
- Audit dependency dengan `npm audit` di root, backend, dan frontend.
|
|
- Rotate admin password dan wajibkan 2FA untuk akun admin.
|