WhatsMax DocumentationWhatsMax Documentation
Home
Getting Started
Deployment
Integrations
Platform Guide
FAQ
Home
Getting Started
Deployment
Integrations
Platform Guide
FAQ
  • Getting Started

    • Introduction
    • Requirements
    • Installation
    • Configuration
    • First Steps
  • Production Deployment

    • Production with PM2
    • Nginx & SSL
    • Updating
  • Integrations

    • WhatsApp Cloud API
    • WhatsApp QR
    • Telegram
    • WeChat
    • Social Media
    • Payment Gateways
    • AI Providers
    • E-commerce
    • Webhook Automation
    • SMS & Email
    • Realtime (Pusher)
  • Platform Guide

    • Platform Overview
    • Omnichannel Inbox
    • Templates & Auto Replies
    • Website Chat Widget
    • Contacts & Segments
    • Campaigns & Broadcasting
    • Automations
    • AI Chatbots
    • Social Planner
    • Leads & Pipeline
    • Reports & Analytics
    • Media Library
    • Workspaces & Team
    • Subscription & Support
    • Developer API
  • Admin Panel

    • Admin Panel
    • Clients & Subscriptions
    • Plans, Coupons & Tax
    • Content & Support
    • Configuration
    • System & Health
    • License Activation
  • Reference

    • FAQ
    • Troubleshooting
    • Changelog
    • Credits

Production Deployment

In production WhatsMax runs as two supervised processes plus one cron entry:

PieceCommandLifetime
Web appnext start -p 3000Long-lived, under PM2.
Queue workernode scripts/workerLong-lived, under PM2.
Schedulernode scripts/schedulerOne tick then exits — called every minute by cron.
WhatsApp QR gateway (optional)node scripts/gatewayLong-lived, under PM2, exactly one instance.

npm run worker and npm run scheduler are development commands

Both run under tsx watch, which restarts on file changes. In production use the extensionless launchers — node scripts/worker and node scripts/scheduler — as shown below.

Do not install with --omit=dev

The background launchers load TypeScript through tsx, which is a dev dependency. A production install must be a plain npm install.

1. Install PM2

sudo npm install -g pm2

2. Create the ecosystem file

Create ecosystem.config.cjs in the project root (/var/www/whatsmax):

module.exports = {
  apps: [
    {
      name: "whatsmax-web",
      script: "node_modules/next/dist/bin/next",
      args: "start -p 3000",
      cwd: __dirname,
      instances: 1,
      autorestart: true,
      max_memory_restart: "1G",
      env: { NODE_ENV: "production" },
    },
    {
      name: "whatsmax-worker",
      script: "scripts/worker",
      interpreter: "node",
      cwd: __dirname,
      autorestart: true,
      max_memory_restart: "1G",
      env: { NODE_ENV: "production" },
    },
    // Only if you enable the optional WhatsApp QR channel
    // (WHATSAPP_QR_ENABLED=true). Read the warning below first.
    {
      name: "whatsmax-gateway",
      script: "scripts/gateway",
      interpreter: "node",
      cwd: __dirname,
      instances: 1, // MUST stay 1 — see below
      autorestart: true,
      max_memory_restart: "1G",
      kill_timeout: 25000, // let sockets close and auth state flush
      env: { NODE_ENV: "production" },
    },
  ],
}

The scheduler does not belong here

scripts/scheduler runs one tick and exits by design. Put it under PM2 and PM2 will treat every normal exit as a crash and restart-loop it. It goes in cron — step 4.

The gateway process (WhatsApp QR only)

Skip it entirely unless you have set WHATSAPP_QR_ENABLED=true. The official WhatsApp Cloud API channel does not use it.

Unlike the web and worker processes, the gateway is stateful: it holds one live WhatsApp socket per linked number.

Run exactly one gateway

Never set instances above 1, and never run the gateway on more than one server. Two gateways racing for the same WhatsApp session kick each other off repeatedly — the inbox stops working, and the constant reconnects look like abuse to WhatsApp, which is how numbers get banned.

The process takes an ownership lock in Redis as a safety net for deploy overlap, but that is not a way to scale out.

The gateway also requires Redis. Every other part of WhatsMax degrades gracefully when Redis is unavailable; the gateway deliberately refuses to start, because without the ownership lock it cannot know whether another process already holds a session.

3. Start the supervised processes

cd /var/www/whatsmax
pm2 start ecosystem.config.cjs
pm2 status
┌────┬─────────────────────┬─────────┬─────────┐
│ id │ name                │ status  │ memory  │
├────┼─────────────────────┼─────────┼─────────┤
│ 0  │ whatsmax-web        │ online  │ 180 MB  │
│ 1  │ whatsmax-worker     │ online  │ 120 MB  │
└────┴─────────────────────┴─────────┴─────────┘

4. Add the scheduler cron entry

crontab -e

Add one line — adjust the path to your installation:

* * * * * cd /var/www/whatsmax && node scripts/scheduler >> /dev/null 2>&1

Every minute this runs the heartbeat plus any task whose cron expression matches that minute: scheduled campaigns, scheduled social posts, subscription reconciliation, cleanups.

Admin → System → Cron Setup shows the exact line for your installation (with your real path), a copy button, and a live scheduler heartbeat. Wait up to a minute after adding the entry and the heartbeat should flip to active.

5. Survive server reboots

pm2 save              # remember the current process list
pm2 startup           # prints a command — run the printed command with sudo

After running the printed sudo env PATH=... pm2 startup ... command, PM2 resurrects the web and worker processes on every reboot. The cron entry survives reboots on its own.

6. Day-to-day commands

pm2 status                       # health overview
pm2 logs whatsmax-web            # tail web logs
pm2 logs whatsmax-worker         # tail worker logs (campaign/AI jobs live here)
pm2 restart whatsmax-web         # restart one process
pm2 restart ecosystem.config.cjs # restart everything
pm2 monit                        # live CPU/memory dashboard

Log rotation

PM2 keeps logs forever by default. Install the rotation module once:

pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 14

7. Verify the background system

  • Admin → System → Queue — pending work draining, failed work not climbing, the queue list populated.
  • Admin → System → Cron Setup — the scheduler heartbeat recent, not Never run.

If either looks dead, check pm2 logs whatsmax-worker and confirm REDIS_URL is reachable (redis-cli ping should answer PONG). See System & Health.

Scaling notes

  • Web — set instances: 2 (or "max") with exec_mode: "cluster" once traffic grows. Sessions are stateless JWTs, so clustering is safe.
  • Worker — add more by duplicating the worker block under a new name. BullMQ distributes jobs automatically.
  • Scheduler — exactly one cron entry, on exactly one host. Two hosts running it means every scheduled campaign goes out twice.
  • Multiple app servers — require S3 storage (STORAGE_DRIVER=s3) plus shared Redis and MySQL.

Next: put Nginx and SSL in front — Nginx & SSL.

Next
Nginx & SSL