When running a Node.js WhatsApp bot on a headless VPS (like an Oracle Ampere instance), you have no GUI. If you want to check if the bot is connected or if you need to scan a new QR code, SSH-ing into the server to read PM2 logs is tedious.
The standard solution is to mount a tiny Express.js server alongside your Baileys instance to serve a web-based "Command Center".
However, the moment you open port 3000 on your VPS firewall, your dashboard is live to the entire internet. Anyone who types your IP address into their browser can view your QR codes, session status, or API health.
In this short security guide, we'll implement HTTP Basic Authentication to lock down your utility dashboard.
1. The Vulnerability
A typical bare-minimum Express status page looks like this:
app.get('/api/status', (req, res) => {
res.json({
status: botStatus,
uptime: process.uptime(),
totalMessages: messagesProcessed
});
});
Because there is no authentication, automated internet scanners (like Shodan) will index this endpoint.
2. Implementing Basic Auth Middleware
We don't need a complex JWT or OAuth setup for a simple utility dashboard. HTTP Basic Auth is perfect because the browser natively handles the UI (the classic popup box asking for a username and password).
First, define your credentials securely in your .env file on the VPS:
# .env
DASHBOARD_USERNAME=admin
DASHBOARD_PASSWORD=super_secret_password_2026
Next, create the middleware function in your Node.js application:
const DASHBOARD_USER = process.env.DASHBOARD_USERNAME;
const DASHBOARD_PASS = process.env.DASHBOARD_PASSWORD;
function basicAuth(req, res, next) {
// 1. Skip auth if no password is set (useful for local development)
if (!DASHBOARD_PASS) return next();
// 2. Check for the Authorization header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Basic ')) {
// Trigger the browser's native login popup
res.setHeader('WWW-Authenticate', 'Basic realm="Bot Command Center"');
return res.status(401).send('Authentication required.');
}
// 3. Decode the Base64 credentials
const decoded = Buffer.from(authHeader.slice(6), 'base64').toString();
const colonIdx = decoded.indexOf(':');
const user = decoded.slice(0, colonIdx);
const pass = decoded.slice(colonIdx + 1);
// 4. Verify
if (user !== DASHBOARD_USER || pass !== DASHBOARD_PASS) {
res.setHeader('WWW-Authenticate', 'Basic realm="Bot Command Center"');
return res.status(401).send('Invalid credentials.');
}
// 5. Success
next();
}
3. Protecting the Routes
Apply the middleware globally to your Express app before defining your routes. This guarantees that no endpoint is accidentally left exposed.
const express = require('express');
const app = express();
// Apply auth to EVERYTHING
app.use(basicAuth);
app.get('/', (req, res) => {
res.send(`<h1>Command Center</h1>`);
});
app.get('/api/status', (req, res) => {
// ...
});
Summary
Security by obscurity (hoping nobody finds your IP address) is not a strategy. Adding 20 lines of Basic Auth middleware guarantees that your sensitive WhatsApp operational data remains entirely private, while still granting you the convenience of a web-based dashboard.