⚙️ Node Gateway Setup
The WhatsApp connection is handled by a small Node.js gateway that ships inside the module at Modules/WhatsAppQrLogin/node-gateway. It keeps your WhatsApp numbers connected, sends and receives messages, and pushes live updates to the chat inbox.
You only need to set up the gateway once on your server. After the setup is complete, the gateway runs automatically in the background.
If your server restarts, the gateway starts again automatically and reconnects your connected WhatsApp numbers.
⛔ BEFORE YOU START — PLEASE READ
- No shared hosting. You need a VPS or cloud server (e.g. CloudPanel). Shared/cPanel plans won't work.
- Redis is required. The gateway won't start without it.
This is a one-time server setup done over SSH by whoever manages your hosting. Your customers never see it — they only scan a QR code from their browser.
What You Need
Before you start, make sure your server has:
- Node.js 20 or higher
- Redis running and reachable (the gateway uses it internally)
- A domain with SSL/HTTPS already set up (e.g. through CloudPanel)
That's it. The gateway reuses your app's existing database and Redis settings automatically, so there's almost nothing to configure by hand.
Step 1 — Install
Open a terminal on your server and go to your WhatsMarkSaas Bundle project's root folder.
cd /path/to/your/WhatsMarkSaasBundleNow go to the gateway folder and run command:
cd Modules/WhatsAppQrLogin/node-gateway
npm installThis command installs all the packages the gateway needs to run. You only need to run it once during the initial setup. If you update the module later, run it again if the update includes new or changed packages.
Step 2 — Start the Gateway
The gateway includes a ready-to-use configuration file: node-gateway/.env. This file is created automatically when the gateway starts for the first time. For a normal setup, you do not need to edit this file.
We recommend using Supervisor for this. Supervisor keeps the gateway running automatically and starts it again if the server restarts.
SUPERVISOR IS SERVER-LEVEL, NOT PROJECT-LEVEL
Supervisor's configuration file is stored outside your project folder at:
/etc/supervisor/conf.d
Because this folder is managed by the server, you need administrator (sudo) access to create or edit the Supervisor configuration.
The gateway itself does not run as the administrator. It runs as your normal website user, which is set in the Supervisor configuration. This keeps the gateway files owned and accessible by the correct user.
Don't have Supervisor installed yet? Install it first:
sudo apt update
sudo apt install supervisor -y1. Create a Supervisor config file
sudo nano /etc/supervisor/conf.d/whatsapp-qr-gateway.conf2. Add the following configuration
Before saving it, replace these two values:
PROJECT_PATH— the full path to your project folder on the server.WEB_USER— the username used to run your website. Do not useroot.
For example, if your project is located at /home/example/public_html, use that path for PROJECT_PATH. Not sure which username to use?
Run this command from your project folder:
ls -ld .The username shown in the output is the user that owns the project folder. Use this username for WEB_USER.
Also check the location of Node.js.
Supervisor may not use the same settings as your normal server terminal, so we need to give Supervisor the correct Node.js path.
Run this command:
which nodeThe command will show the location where Node.js is installed. You will use this path in the Supervisor configuration.
If this returns something other than /usr/bin/node (e.g. a path under nvm), use that full path instead of plain node in the command= line below.
[program:whatsapp-qr-gateway]
directory={{PROJECT_PATH}}/Modules/WhatsAppQrLogin/node-gateway
command=/usr/bin/node --env-file=.env server.js
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user={{WEB_USER}}
numprocs=1
redirect_stderr=true
stdout_logfile=/dev/null
stderr_logfile=/dev/null
stopwaitsecs=303. Reload Supervisor and start the gateway
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start whatsapp-qr-gateway4. Check it's running
sudo supervisorctl status whatsapp-qr-gatewayYou should see:
whatsapp-qr-gateway RUNNING pid 1234, uptime 0:00:05That's all you need to do.
After Supervisor is set up, it will automatically restart the gateway if it stops or crashes. It will also start the gateway again automatically when the server reboots.
Your previously connected WhatsApp numbers will reconnect automatically. You do not need to scan the QR code again.
Supervisor is also configured to start automatically when the server reboots. See Step 6: Auto-start on reboot for details.
If you are already using Supervisor for Laravel Horizon, you can use the same Supervisor setup to manage both Laravel Horizon and the WhatsApp gateway.
Gateway shows FATAL or won't start?
Check the status and log output:
sudo supervisorctl status whatsapp-qr-gateway
sudo supervisorctl tail whatsapp-qr-gateway stderrThen test the gateway directly, outside Supervisor, to see the real error:
cd {{PROJECT_PATH}}/Modules/WhatsAppQrLogin/node-gateway
node --env-file=.env server.jsIf you see an error here too, the problem is with the gateway setup, such as Node.js, Redis, or the .env configuration, rather than Supervisor.
Seeing permission denied? Confirm the user= value in your config matches the folder owner (ls -ld ) — never set it to root.
Step 3 — Allow Live Chat (WebSocket over HTTPS)
The chat inbox receives new messages and updates automatically without refreshing the page. This uses a WebSocket connection, which keeps the chat connected to the gateway.
Because your website uses HTTPS, this connection must also be secure (wss://).
The easiest way to set this up is through CloudPanel using your existing domain. This allows the gateway to use the SSL certificate already installed on your website.
1. Open the Vhost editor
In CloudPanel, go to Sites → (your site) → Vhost. This is the site-level configuration for your WhatsMarksaas Bundle domain — not a global or server-wide file. Editing it here means the WebSocket automatically reuses the SSL certificate CloudPanel already issued for this site.
2. Add a WebSocket route
Inside that site's existing HTTPS server { … } block, add this location:
location /qr-ws/ {
proxy_pass http://127.0.0.1:3011/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}Save — CloudPanel reloads Nginx for you.
WHY PORT 3011?
The gateway uses port 3011 for the WebSocket connection by default.
The gateway also uses port 3010 for its regular requests. These are two different ports with different purposes.
Port 3011 is only available on the server itself. It is not open directly to the internet. CloudPanel/Nginx securely connects your website to this port.
Keep port 3011 as it is unless you have changed the WebSocket port in the gateway configuration.
3. Point the app at the WebSocket route
Add the following setting to your app's main .env file — the same .env file used by Laravel:
WHATSAPP_QR_WS_URL=wss://your-domain.com/qr-ws/Replace your-domain.com with your actual website domain.
Make sure the /qr-ws/ path is the same as the path you added in the Nginx configuration above.
The wss:// part is required because your website uses HTTPS. Do not change it to ws://.
This setting tells the chat inbox where to connect for live updates.
After this setup, the chat connects securely through your own domain. You do not need to open another port or create a separate SSL certificate.
WHY THIS STEP MATTERS
Without this setting, messages can still be sent and received, but new messages will not appear automatically in the inbox. You will need to refresh the page to see new messages.
This setup enables live updates, so new messages appear automatically without refreshing the page.
Step 4 — Confirm the Scheduler and Queue Are Running
The module relies on two things your server should already have running for the rest of WhatsMarkSaaS:
- Scheduler cron (
* * * * * php artisan schedule:run) — this runs two background jobs: one that clears out messages stuck in "Queued" every 5 minutes, and one that resets the daily number-warming counters just after midnight. - Queue worker (Horizon) — bulk sends and the number-warming feature are processed through the
whatsapp-messagesqueue, so Horizon must be running and healthy.
If you've already set up Horizon and the scheduler for the rest of WhatsMarkSaaS, there's nothing extra to do here.
Step 5 — Final Check
Confirm everything is working end to end:
- As a customer, open the WhatsApp QR page, scan the code, and wait for Connected.
- Send a test message — it should appear instantly in the inbox (that confirms the WebSocket from Step 3).
- Watch for the delivery ticks on the message (that confirms sending works).
- Reboot the server, then check
sudo supervisorctl status whatsapp-qr-gateway— it should come back RUNNING on its own, and previously connected numbers should reconnect without re-scanning.
If anything doesn't work, the Troubleshooting page lists the common symptoms and fixes, or see the Supervisor troubleshooting tips below.
The Gateway Secret
Laravel and the gateway authenticate to each other using a shared secret — you don't need to set this up yourself, but it helps to know how it works if something looks wrong:
- The secret is generated automatically and stored in your database (Settings), then copied to
Modules/WhatsAppQrLogin/node-gateway/secret.txton the server. - It is not something you put in
.envby hand. - If you ever need to rotate it (for example, after the server was compromised), an administrator with SSH access can run:bashThis immediately logs out every open chat page (they simply need a reload) and the gateway picks up the new secret within about 10 seconds — no downtime, no re-scanning of WhatsApp numbers.
php artisan whatsapp-qr:install --force
Moving or Renaming Your Server Folder
If you move the application to a new server, or rename its folder, connected WhatsApp numbers don't need to be re-scanned — but a few things need to move along with the application:
- Update your Supervisor config so it points at the new folder path, then restart it.
- Reinstall the gateway's Node packages in the new location —
node_modules/is never copied along, so runnpm installagain insidenode-gateway/. - Copy the
storage/app/whatsapp-qr/sessions/folder along with the rest of your storage — this holds the WhatsApp login keys for every connected number. - Double-check your
.env— copied or bundled.envfiles can carry the wrongREDIS_PASSWORD,APP_KEY, orWHATSAPP_QR_WS_URLfor the new environment. - Clear cached config — run
php artisan optimize:clearafter the move.
⛔ STOP THE OLD GATEWAY FIRST
Make sure the gateway on the old server/folder is stopped before starting the new one. If it keeps running after the folder was moved or renamed, it loses access to its session files, and every send on that connection starts failing with "WhatsApp service is unavailable."
With the gateway running, your customers can connect their numbers. Continue to Getting Started for the customer-side flow, or Managing Your Connection for connection statuses and reconnects.