Files
BizOne-portal/docs/production-server-checklist.md

7.6 KiB

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:

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:

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:

ssh user@SERVER_IP
cd /srv/bizone-web
nano .env

Isi minimal seperti ini:

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:

sudo chown bizone:bizone /srv/bizone-web/.env
sudo chmod 600 /srv/bizone-web/.env

Load env untuk command manual:

cd /srv/bizone-web
set -a
source .env
set +a

3. Jalankan build backend dan frontend

Install dependency root untuk Prisma:

cd /srv/bizone-web
npm install

Build backend:

cd /srv/bizone-web/backend
npm install
npm run db:generate
npm run build

Build frontend:

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:

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:

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:

npm run seed:admin

Setelah login pertama, langsung ganti password admin dan aktifkan 2FA.

5. Tambahkan nginx security headers

Edit config nginx:

sudo nano /etc/nginx/sites-available/portal.bizone.id

Di dalam blok server { ... }, tambahkan:

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:

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:

sudo nginx -t
sudo systemctl reload nginx

6. Deploy via systemd

Copy service files:

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:

sudo systemctl daemon-reload

Enable service:

sudo systemctl enable bizone-backend
sudo systemctl enable bizone-frontend

Start atau restart service:

sudo systemctl restart bizone-backend
sudo systemctl restart bizone-frontend

Cek status:

sudo systemctl status bizone-backend
sudo systemctl status bizone-frontend

Lihat log kalau ada error:

sudo journalctl -u bizone-backend -f
sudo journalctl -u bizone-frontend -f

7. Smoke test production

Cek backend health:

curl https://portal.bizone.id/api/health
curl https://portal.bizone.id/backend-api/health

Response ideal:

{"status":"ok","service":"wa-dashboard-backend","database":"ok"}

Cek frontend:

curl -I https://portal.bizone.id

Cek service:

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:

https://portal.bizone.id/api/webhooks/whatsapp

Verify token:

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.