---
url: >-
  https://docs.corbitaltech.dev/products/whatsapp-qr-login-for-whatsmark-saas-bundle/node-gateway.md
description: >-
  A simple, step-by-step guide to install, run, and connect the Node.js gateway
  that powers the WhatsApp QR Login module.
---

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

::: danger ⛔ 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.

```bash
cd /path/to/your/WhatsMarkSaasBundle
```

Now go to the gateway folder and run command:

```bash
cd Modules/WhatsAppQrLogin/node-gateway
npm install
```

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

::: tip 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:

```bash
sudo apt update
sudo apt install supervisor -y
```

:::

**1. Create a Supervisor config file**

```bash
sudo nano /etc/supervisor/conf.d/whatsapp-qr-gateway.conf
```

**2. 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 use `root`.**

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:

```bash
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:

```bash id="3d6i8j"
which node
```

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

```ini
[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=30
```

**3. Reload Supervisor and start the gateway**

```bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start whatsapp-qr-gateway
```

**4. Check it's running**

```bash
sudo supervisorctl status whatsapp-qr-gateway
```

You should see:

```text
whatsapp-qr-gateway    RUNNING   pid 1234, uptime 0:00:05
```

That'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](/products/whatsmark-saas/advance-configuration/supervisor-setup-guide-for-laravel-horizon.md#step-6-auto-start-on-reboot) for details.

If you are already using Supervisor for [Laravel Horizon](/products/whatsmark-saas/advance-configuration/supervisor-setup-guide-for-laravel-horizon.md), you can use the same Supervisor setup to manage both Laravel Horizon and the WhatsApp gateway.

::: details Gateway shows FATAL or won't start?
Check the status and log output:

```bash
sudo supervisorctl status whatsapp-qr-gateway
sudo supervisorctl tail whatsapp-qr-gateway stderr
```

Then test the gateway directly, outside Supervisor, to see the real error:

```bash
cd {{PROJECT_PATH}}/Modules/WhatsAppQrLogin/node-gateway
node --env-file=.env server.js
```

If 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 {{PROJECT_PATH}}`) — 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:

```nginx
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.

::: tip 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:

```env
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.

::: tip 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-messages` queue, 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:

1. As a customer, open the WhatsApp QR page, scan the code, and wait for **Connected**.
2. Send a test message — it should appear **instantly** in the inbox (that confirms the WebSocket from Step 3).
3. Watch for the delivery **ticks** on the message (that confirms sending works).
4. 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](/products/whatsapp-qr-login-for-whatsmark-saas-bundle/troubleshooting.md) 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.txt` on the server.
* It is **not** something you put in `.env` by hand.
* If you ever need to rotate it (for example, after the server was compromised), an administrator with SSH access can run:
  ```bash
  php artisan whatsapp-qr:install --force
  ```
  This 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.

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

1. **Update your Supervisor config** so it points at the new folder path, then restart it.
2. **Reinstall the gateway's Node packages** in the new location — `node_modules/` is never copied along, so run `npm install` again inside `node-gateway/`.
3. **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.
4. **Double-check your `.env`** — copied or bundled `.env` files can carry the wrong `REDIS_PASSWORD`, `APP_KEY`, or `WHATSAPP_QR_WS_URL` for the new environment.
5. **Clear cached config** — run `php artisan optimize:clear` after the move.

::: danger ⛔ 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](/products/whatsapp-qr-login-for-whatsmark-saas-bundle/getting-started.md) for the customer-side flow, or [Managing Your Connection](/products/whatsapp-qr-login-for-whatsmark-saas-bundle/connection-management.md) for connection statuses and reconnects.*
