# 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 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.