Files
whatsapp-inbox-platform/INSTALL-UBUNTU-APP-ZAPPCARE.md
Wira Basalamah adde003fba
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
chore: initial project import
2026-04-21 09:29:29 +07:00

11 KiB

Panduan Install WhatsApp Inbox di Ubuntu (Domain: app.zappcare.id)

Dokumen ini menyusun langkah deployment lengkap untuk server Ubuntu dengan kondisi:

  • PostgreSQL sudah terinstall
  • Nginx sudah terinstall
  • Gitea berjalan di port 3001
  • Aplikasi ini tidak boleh pakai port 3000 karena dipakai layanan lain

Pada panduan ini, aplikasi akan jalan di port 3002 di loopback (127.0.0.1:3002) dan di-serve via Nginx ke domain app.zappcare.id.

1) Prasyarat

Pastikan server sudah memenuhi:

  • Ubuntu 22.04/24.04 (sesuaikan)
  • User dengan sudo
  • PostgreSQL aktif
  • Nginx aktif
  • Node.js 20.x + npm
  • Git
  • domain app.zappcare.id mengarah ke IP server (DNS A record)

2) Install runtime (jika belum)

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl ca-certificates git nginx postgresql postgresql-contrib

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

node -v
npm -v

3) Buat database PostgreSQL

Masuk psql:

sudo -u postgres psql

Jalankan:

CREATE USER whatsapp_inbox WITH PASSWORD 'GANTI_PASSWORD_KUAT';
CREATE DATABASE whatsapp_inbox OWNER whatsapp_inbox;
\q

4) Setup user deploy

sudo useradd --system --home /var/www/whatsapp-inbox --shell /usr/sbin/nologin whatsapp-inbox || true
sudo mkdir -p /var/www/whatsapp-inbox
sudo chown -R whatsapp-inbox:whatsapp-inbox /var/www/whatsapp-inbox

5) Clone source & install dependency

sudo -u whatsapp-inbox git clone <REPO_URL> /var/www/whatsapp-inbox
cd /var/www/whatsapp-inbox
sudo -u whatsapp-inbox npm ci

Ganti <REPO_URL> dengan URL repo Anda.

6) Buat .env production

Buat file dari template:

sudo cp /var/www/whatsapp-inbox/.env.example /var/www/whatsapp-inbox/.env
sudo chown whatsapp-inbox:whatsapp-inbox /var/www/whatsapp-inbox/.env
sudo -u whatsapp-inbox nano /var/www/whatsapp-inbox/.env

Isi .env yang wajib:

NODE_ENV=production
PORT=3002
HOST=127.0.0.1

DATABASE_URL="postgresql://whatsapp_inbox:GANTI_PASSWORD_KUAT@127.0.0.1:5432/whatsapp_inbox?schema=public"
AUTH_SECRET="ganti_secret_acak_minimal_32_karakter"

APP_URL="https://app.zappcare.id"
NEXT_PUBLIC_APP_URL="https://app.zappcare.id"
OPS_BASE_URL="https://app.zappcare.id"

CAMPAIGN_RETRY_JOB_URL="https://app.zappcare.id"
CAMPAIGN_RETRY_JOB_TOKEN="ganti_token_acak"
HEALTHCHECK_TOKEN="ganti_token_health"

WHATSAPP_WEBHOOK_VERIFY_TOKEN="token_verify_webhook_anda"
WHATSAPP_WEBHOOK_SECRET="webhook_secret_anda"
WHATSAPP_API_TOKEN="meta_whatsapp_api_token"
WHATSAPP_API_VERSION="v22.0"
WHATSAPP_ALLOW_SIMULATED_SEND="false"

CAMPAIGN_RETRY_BATCH_SIZE="100"
CAMPAIGN_RETRY_MAX_CAMPAIGNS="20"
CAMPAIGN_RETRY_JOB_LOCK_TTL_SECONDS="300"
CAMPAIGN_RETRY_DAEMON_INTERVAL_SECONDS="300"
CAMPAIGN_RETRY_DAEMON_TIMEOUT_MS="30000"
CAMPAIGN_RETRY_ALERT_ON_FAILURE="true"
CAMPAIGN_RETRY_ALERT_WEBHOOK_URL=""

WEBHOOK_FAILURE_RATE_THRESHOLD_PER_HOUR="20"
RETRY_WORKER_STALE_MINUTES="30"
LOGIN_RATE_LIMIT_ATTEMPTS="10"
LOGIN_RATE_LIMIT_WINDOW_MS="900000"
CAMPAIGN_RETRY_JOB_RATE_LIMIT_GET="60"
CAMPAIGN_RETRY_JOB_RATE_LIMIT_POST="20"
CAMPAIGN_RETRY_JOB_RATE_LIMIT_WINDOW_MS="60000"
WHATSAPP_WEBHOOK_RATE_LIMIT_GET="60"
WHATSAPP_WEBHOOK_RATE_LIMIT_POST="120"
WHATSAPP_WEBHOOK_RATE_LIMIT_WINDOW_MS="60000"

AUTH_TOKEN_CONSUMED_RETENTION_HOURS="24"
CAMPAIGN_RETRY_STALE_LOCK_MINUTES="120"
WEBHOOK_EVENT_RETENTION_DAYS="30"
AUDIT_LOG_RETENTION_DAYS="365"

Pastikan nilai DATABASE_URL sesuai username/password/password database Anda.

7) Pastikan Prisma pakai PostgreSQL

Cek schema.prisma

Buka prisma/schema.prisma dan pastikan datasource:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

Jika masih sqlite, migrasi ke Postgres harus dibangun ulang.
Catatan: perubahan provider dan migration bisa dilakukan di environment staging/dev sebelum deploy production.

Jalankan migration + seed

cd /var/www/whatsapp-inbox
sudo -u whatsapp-inbox npm run db:deploy
sudo -u whatsapp-inbox npm run db:seed

8) Build & verifikasi

cd /var/www/whatsapp-inbox
sudo -u whatsapp-inbox npm run ci:verify

Jika berhasil, lanjut ke service.

9) Test manual port 3002

cd /var/www/whatsapp-inbox
sudo -u whatsapp-inbox npm run start -- --hostname 127.0.0.1 --port 3002

Di terminal lain:

curl -I http://127.0.0.1:3002
curl -s http://127.0.0.1:3002/api/health

10) Buat service systemd (Next.js app)

Buat file /etc/systemd/system/whatsapp-inbox.service:

[Unit]
Description=WhatsApp Inbox (Next.js App)
After=network.target postgresql.service

[Service]
Type=simple
User=whatsapp-inbox
Group=whatsapp-inbox
WorkingDirectory=/var/www/whatsapp-inbox
EnvironmentFile=/var/www/whatsapp-inbox/.env
ExecStart=/usr/bin/npm run start -- --hostname 127.0.0.1 --port 3002
Restart=always
RestartSec=5
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

Enable dan start:

sudo systemctl daemon-reload
sudo systemctl enable --now whatsapp-inbox
sudo systemctl status whatsapp-inbox

11) Service retry worker (daemon)

Buat file /etc/systemd/system/whatsapp-inbox-retry.service:

[Unit]
Description=WhatsApp Inbox Campaign Retry Daemon
After=network.target whatsapp-inbox.service

[Service]
Type=simple
User=whatsapp-inbox
Group=whatsapp-inbox
WorkingDirectory=/var/www/whatsapp-inbox
EnvironmentFile=/var/www/whatsapp-inbox/.env
ExecStart=/usr/bin/npm run job:campaign-retry:daemon
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now whatsapp-inbox-retry
sudo systemctl status whatsapp-inbox-retry

12) Konfigurasi Nginx reverse proxy

Buat file /etc/nginx/sites-available/app.zappcare.id:

server {
  listen 80;
  server_name app.zappcare.id;

  location /.well-known/acme-challenge/ {
    root /var/www/html;
  }

  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 443 ssl http2;
  server_name app.zappcare.id;

  client_max_body_size 20m;
  proxy_buffering off;

  ssl_certificate     /etc/letsencrypt/live/app.zappcare.id/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/app.zappcare.id/privkey.pem;

  location / {
    proxy_pass         http://127.0.0.1:3002;
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    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   X-Forwarded-Host $host;
    proxy_read_timeout 120s;
    proxy_send_timeout 120s;
  }
}

Aktifkan site dan reload:

sudo ln -s /etc/nginx/sites-available/app.zappcare.id /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

13) Install SSL (Let's Encrypt)

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app.zappcare.id

14) Cek akhir deployment

curl -I https://app.zappcare.id
curl -I https://app.zappcare.id/api/health
curl -s https://app.zappcare.id/api/health | jq

Ops check:

APP_URL=https://app.zappcare.id NEXT_PUBLIC_APP_URL=https://app.zappcare.id OPS_BASE_URL=https://app.zappcare.id npm run ops:readiness
APP_URL=https://app.zappcare.id NEXT_PUBLIC_APP_URL=https://app.zappcare.id OPS_BASE_URL=https://app.zappcare.id npm run ops:smoke

15) Update rutin

cd /var/www/whatsapp-inbox
git pull origin main
sudo -u whatsapp-inbox npm ci
sudo -u whatsapp-inbox npm run ci:verify
sudo -u whatsapp-inbox npm run db:deploy
sudo systemctl restart whatsapp-inbox
sudo systemctl restart whatsapp-inbox-retry

16) Rollback cepat

cd /var/www/whatsapp-inbox
git log --oneline -n 10
git checkout <commit-sebelumnya>
sudo systemctl restart whatsapp-inbox

17) Hal penting untuk environment produksi

  • Pastikan semua token tidak lagi change-me/your-*.
  • Monitor ops:readiness + ops:smoke tiap hari / saat deploy.
  • Jalankan ops:maintenance berkala (cron harian/mingguan).
  • Pastikan job retry tetap hidup:
    • sudo systemctl status whatsapp-inbox-retry
sudo systemctl status whatsapp-inbox
sudo systemctl status whatsapp-inbox-retry
journalctl -u whatsapp-inbox -f
journalctl -u whatsapp-inbox-retry -f

18) Troubleshooting cepat

18.1 Domain menjawab 502 Bad Gateway

sudo systemctl status whatsapp-inbox
sudo ss -ltnp | rg "127.0.0.1:3002"
sudo nginx -t
sudo systemctl reload nginx
  • Jika service app tidak jalan, cek log: journalctl -u whatsapp-inbox -n 200 --no-pager
  • Pastikan Nginx proxy ke 127.0.0.1:3002 (bukan 3000/3001).
  • Jika app jalan, cek .env dan PORT=3002.

18.2 Halaman health 500 / tidak bisa start

cd /var/www/whatsapp-inbox
sudo -u whatsapp-inbox npm run ops:readiness
  • Jika DATABASE_URL error:
    • cek service PostgreSQL: sudo systemctl status postgresql
    • cek koneksi manual: psql "postgresql://whatsapp_inbox:GANTI_PASSWORD_KUAT@127.0.0.1:5432/whatsapp_inbox?schema=public" -c '\dt'
  • Jika token/secret bermasalah:
    • cek value AUTH_SECRET, CAMPAIGN_RETRY_JOB_TOKEN, WHATSAPP_WEBHOOK_SECRET
    • jangan ada placeholder seperti change-me, your-*

18.3 Retry job tidak berjalan

sudo systemctl status whatsapp-inbox-retry
sudo -u whatsapp-inbox npm run job:campaign-retry
  • Cek token pada .env (CAMPAIGN_RETRY_JOB_TOKEN) dan endpoint:
    • https://app.zappcare.id/api/jobs/campaign-retry?token=<token>
  • Jika lock stuck, jalankan:
    • sudo -u whatsapp-inbox npm run job:campaign-retry
    • restart service: sudo systemctl restart whatsapp-inbox-retry

18.4 Webhook tidak terima event

curl -i https://app.zappcare.id/api/webhooks/whatsapp
  • Pastikan URL di Meta adalah:
    • https://app.zappcare.id/api/webhooks/whatsapp
  • Untuk validasi:
    • cek WHATSAPP_WEBHOOK_VERIFY_TOKEN
    • cek WHATSAPP_WEBHOOK_SECRET
    • cek Signature header dari provider sesuai konfigurasi

18.5 Port bentrok / service lain

sudo lsof -i :3000
sudo lsof -i :3001
sudo lsof -i :3002
  • Jika app tidak boleh pakai 3000/3001, pastikan .env dan service tetap di 3002.
  • Jika ada proses yang tidak dikenal, stop service itu atau pindahkan port dengan service systemd yang benar.

18.6 Cek cepat setelah reboot atau deploy

sudo systemctl restart whatsapp-inbox
sudo systemctl restart whatsapp-inbox-retry
sudo systemctl status whatsapp-inbox whatsapp-inbox-retry --no-pager
curl -s https://app.zappcare.id/api/health | cat

Jika masih ada masalah:

APP_URL=https://app.zappcare.id NEXT_PUBLIC_APP_URL=https://app.zappcare.id OPS_BASE_URL=https://app.zappcare.id npm run ops:readiness
APP_URL=https://app.zappcare.id NEXT_PUBLIC_APP_URL=https://app.zappcare.id OPS_BASE_URL=https://app.zappcare.id npm run ops:smoke