WAHA — Operations Workbook
WAHA NOWEB WhatsApp gateway running on Hostinger VPS (vps-h1). Manages the DE WhatsApp number (+49 1578 5573196) — receives driver/fleet messages, forwards to n8n for routing and AI processing.
Architecture
Hostinger VPS (72.60.32.61)
└── Container: waha image: devlikeapro/waha-plus (NOWEB)
├── port 13000 WAHA API (internal)
├── volume: waha_data WhatsApp session state (auth keys, etc.)
└── environment:
├── WHATSAPP_DEFAULT_ENGINE=NOWEB
├── WAHA_API_KEY API authentication key
└── WAHA_HOOK_EVENTS Webhook event subscriptions
WhatsApp Cloud ──→ WAHA :13000 ──→ n8n webhook ──→ wa-router workflow
(HTTP POST)
Public HTTPS: waha2.vps-h1.infra.zintegrowana.onlinePublic URL: https://waha2.vps-h1.infra.zintegrowana.online
Compose file on server: /root/docker-compose.yml
Compose file in repo: hostinger/docker-compose.yml
Config Management
| File | Location | In repo? | Contains secrets? |
|---|---|---|---|
docker-compose.yml | /root/docker-compose.yml | ✅ hostinger/docker-compose.yml | No |
waha_data volume | Docker volume on vps-h1 | ❌ | Yes (WhatsApp session keys) |
.env | /root/.env on vps-h1 | ❌ .env.example only | Yes |
Key environment variables
| Variable | Purpose |
|---|---|
WAHA_API_KEY | All API requests must include X-Api-Key: ${WAHA_API_KEY} |
WAHA_HMAC_SECRET | HMAC secret for webhook signature verification in n8n |
Deployment
Fresh install
# On vps-h1
docker compose -f /root/docker-compose.yml up -d wahaLink WhatsApp account (first time or after session loss)
# 1. Generate QR code
curl -X POST https://waha2.vps-h1.infra.zintegrowana.online/api/sessions/default/start \
-H "X-Api-Key: ${WAHA_API_KEY}"
# 2. Get QR code (base64 image)
curl https://waha2.vps-h1.infra.zintegrowana.online/api/screenshot \
-H "X-Api-Key: ${WAHA_API_KEY}" -o /tmp/qr.png
# 3. Scan QR with +49 1578 5573196 WhatsApp app
# 4. Verify session status
curl https://waha2.vps-h1.infra.zintegrowana.online/api/sessions/default \
-H "X-Api-Key: ${WAHA_API_KEY}"
# Expected: {"name":"default","status":"WORKING"}Backup
What needs backing up
| Data | Method | Schedule | Destination |
|---|---|---|---|
waha_data volume (session keys) | backup-hstgr.sh → Wasabi | Nightly 02:30 UTC | s3://p24-infra/waha/waha-session-YYYY-MM-DD.tar.gz.age |
Note: If session backup is lost, a new QR scan is required (re-linking WhatsApp). This is a 5-minute manual operation but causes a brief service interruption.
Manual backup
# On vps-h1
docker compose -f /root/docker-compose.yml stop waha
docker run --rm -v waha_data:/data -v /tmp:/backup alpine \
tar czf /backup/waha-data-$(date +%F).tar.gz -C /data .
docker compose -f /root/docker-compose.yml start waha
# Upload /tmp/waha-data-*.tar.gz to Wasabi manuallyRestore
Target RTO: 15 minutes (mostly QR scan if session is lost)
Scenario 1: Container crash (session intact)
docker compose -f /root/docker-compose.yml up -d waha
# waha_data preserved — session resumes automaticallyScenario 2: Restore session from backup
# 1. Download latest session backup
aws s3 cp s3://p24-infra/waha/waha-session-YYYY-MM-DD.tar.gz.age /tmp/ \
--endpoint-url https://s3.eu-central-2.wasabisys.com
# 2. Decrypt
age --decrypt -i ~/.config/age/key.txt /tmp/waha-session-YYYY-MM-DD.tar.gz.age \
| tar xz -C /tmp/waha-restore/
# 3. Stop WAHA
docker compose -f /root/docker-compose.yml stop waha
# 4. Restore volume
docker run --rm -v waha_data:/data alpine rm -rf /data/*
docker run --rm -v waha_data:/data -v /tmp/waha-restore:/backup alpine \
tar xzf /backup/waha-session-YYYY-MM-DD.tar.gz -C /data
# 5. Start WAHA
docker compose -f /root/docker-compose.yml start waha
# 6. Verify session WORKING
curl https://waha2.vps-h1.infra.zintegrowana.online/api/sessions/default \
-H "X-Api-Key: ${WAHA_API_KEY}"Scenario 3: Session expired / QR needed
# Stop and wipe session data
docker compose -f /root/docker-compose.yml stop waha
docker run --rm -v waha_data:/data alpine rm -rf /data/*
docker compose -f /root/docker-compose.yml start waha
# Then follow fresh QR scan procedure aboveHealthcheck
Docker healthcheck: GET http://localhost:13000/api/health — defined in hostinger/docker-compose.yml
External probe: https://waha2.vps-h1.infra.zintegrowana.online/api/health via health-check.yml GH Action.
Manual check:
curl -H "X-Api-Key: ${WAHA_API_KEY}" \
https://waha2.vps-h1.infra.zintegrowana.online/api/sessions/default
# Session status should be "WORKING"Session status alert: health-check.yml checks WAHA /api/health — auto-opens GitHub issue if down.
Password Rotation
WAHA_API_KEY
# 1. Generate new key
NEW_KEY=$(openssl rand -hex 32)
# 2. Update /root/.env on vps-h1
ssh root@72.60.32.61 "sed -i 's/WAHA_API_KEY=.*/WAHA_API_KEY=${NEW_KEY}/' /root/.env"
# 3. Restart WAHA
docker compose -f /root/docker-compose.yml restart waha
# 4. Update GH Secret
gh secret set WAHA_API_KEY -b "${NEW_KEY}" -R radieu/p24-infra
# 5. Update .env.local on local workstation
# 6. Verify health-check.yml still works (it uses GH Secret WAHA_API_KEY)
# 7. Log rotation in docs/secrets-rotation-log.mdTroubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Session status STOPPED or FAILED | WhatsApp session expired | Re-scan QR code |
| No messages arriving | Webhook URL wrong in WAHA | Verify WAHA_HOOK_URL points to n8n |
403 Forbidden on API calls | WAHA_API_KEY mismatch | Verify key in /root/.env and caller |
| Container OOM | Too many concurrent sessions | Increase container memory limit |
/api/sessions shows no sessions | WAHA started but no session created | POST /api/sessions/default/start |