This NestJS project keeps a headless WhatsApp Web client running on your server, exposes live connection status, serves the latest QR code for login, forwards inbound group messages to your webhook, and lets you send text messages on-demand.
- Tracks the WhatsApp session state with SSE so a status dashboard can react in real time.
- Publishes the most recent QR code (
/whatsapp/qr) so you can authenticate without opening developer tools on the server. - Forwards every incoming message (group
@g.usor otherwise) to your configured webhook while logging sender/group metadata. - Provides a REST endpoint for sending a WhatsApp text message:
/whatsapp/send-message. - Protects the root
/landing page (the dashboard, status, and QR preview) with basic auth.
- Node.js 20+ (or whichever version Nest 11 supports) and npm
- A machine where Chromium can run (the project uses
whatsapp-web.jswith Puppeteer) - Basic WhatsApp login credentials (via QR) and a stable internet connection for the headless session
- Install dependencies:
npm install
- Copy
.env.exampleto.envand supply the required secrets (see the next section). - Start the API in development mode:
npm run start:dev
| Name | Description | Required |
|---|---|---|
BASIC_AUTH_USERNAME |
Username protecting the / dashboard |
✅ |
BASIC_AUTH_PASSWORD |
Password for the dashboard | ✅ |
BASIC_AUTH_REALM |
Realm shown in the challenge dialog (defaults to WhatsApp Bot Status) |
✳️ |
EXTERNAL_API_URL |
If provided, inbound messages are POSTed here | ✳️ |
EXTERNAL_API_USER |
Basic auth username for the outbound webhook (defaults to TP#Wa129) |
✳️ |
EXTERNAL_API_PASS |
Basic auth password for the webhook (secret, special characters supported) | ✳️ |
SENDING_API_USER |
Basic auth username required to call POST /whatsapp/send-message |
✅ |
SENDING_API_PASS |
Basic auth password for POST /whatsapp/send-message |
✅ |
Environment variables commented out in .env.example (database credentials) are currently unused but kept for future expansion.
npm run start– launch Nest in production modenpm run start:dev– watch mode for active developmentnpm run start:prod– serve the compileddistbundlenpm run build– compile the projectnpm run lint– run ESLint with auto-fixnpm run test/test:watch/test:cov– Jest-powered unit tests and coverage
| Method | Path | Description |
|---|---|---|
GET /whatsapp/qr |
/whatsapp/qr |
PNG image of the latest WhatsApp QR code; useful for remote machines |
GET /whatsapp/status |
/whatsapp/status |
Returns JSON with status, active, and lastChanged |
POST /whatsapp/send-message |
/whatsapp/send-message |
Send { number: string, message: string } to any WhatsApp contact (pan-India format with digits only); requires Basic Auth (SENDING_API_*). |
GET /whatsapp/events |
/whatsapp/events |
Server-Sent Events stream emitting status updates and qr payloads for dashboards |
All endpoints under /whatsapp are unprotected, so place them behind your own API gateway or firewall if needed. The root / endpoint is protected by Basic Auth to keep the live dashboard private.
When enabled, every WhatsApp message triggers a POST request to EXTERNAL_API_URL. The JSON payload contains:
groupName,receivedNumber, andmessageBodyimage– base64 data if the message carried an image (fallback to text body)inputData– raw snapshot of thewhatsapp-web.jsmessage objectaddedDate– ISO timestamp when the message was processed
Outgoing webhook requests include the configured basic auth headers.
- The client stores session data via
LocalAuth, so re-scanning is unnecessary once logged in. - Keep the dashboard tab open to see real-time QR/status updates (refreshing will reconnect via SSE).
- Monitor logs for reconnection attempts and authentication failures—Puppeteer runs with
--no-sandbox --disable-setuid-sandboxfor production readiness.
If you need additional tooling (database persistence, advanced routing), expand the WhatsappService and the /whatsapp controllers accordingly.
This section covers deploying the tp-communications container to a production server with Nginx reverse proxy and SSL.
On your production server (Ubuntu/Debian):
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo apt install docker-compose-plugin -y
# Install Nginx and Certbot
sudo apt install nginx certbot python3-certbot-nginx -y# Clone your repository
git clone <your-repo-url> /opt/tp-communications
cd /opt/tp-communications
# Create production .env file
cp .env.example .env
nano .env # Fill in your production secrets# Build and start in detached mode
docker compose up -d --build
# Verify the container is running
docker compose ps
docker compose logs -f whatsapp-botPoint your domain to your server's IP address:
| Type | Name | Value |
|---|---|---|
| A | whatsapp.yourdomain.com | YOUR_SERVER_IP |
Wait for DNS propagation (can take up to 24 hours, usually minutes).
Create the Nginx site configuration:
sudo nano /etc/nginx/sites-available/tp-communicationsAdd the following configuration:
server {
listen 80;
server_name whatsapp.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
proxy_read_timeout 86400; # SSE connections need long timeout
}
}Enable the site:
sudo ln -s /etc/nginx/sites-available/tp-communications /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxsudo certbot --nginx -d whatsapp.yourdomain.comCertbot will automatically update your Nginx config to handle HTTPS and set up auto-renewal.
Verify auto-renewal:
sudo certbot renew --dry-runsudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable# View logs
docker compose logs -f
# Restart container
docker compose restart
# Stop container
docker compose down
# Update and redeploy
git pull
docker compose up -d --build
# Check container health
docker compose psThe WhatsApp session is persisted in Docker volumes (bot_sessions and bot_cache). To backup:
# Backup volumes
docker run --rm -v tp-communications_bot_sessions:/data -v $(pwd):/backup alpine tar czf /backup/sessions-backup.tar.gz -C /data .
# Restore volumes
docker run --rm -v tp-communications_bot_sessions:/data -v $(pwd):/backup alpine tar xzf /backup/sessions-backup.tar.gz -C /data- Strong passwords set for
BASIC_AUTH_PASSWORDandSENDING_API_PASS -
EXTERNAL_API_URLconfigured for webhook forwarding - SSL certificate installed and auto-renewal verified
- Firewall configured (only ports 80, 443, 22 open)
- Container set to restart automatically (
restart: unless-stopped) - Monitoring/alerting configured for container health
- Regular backups of session volumes scheduled