Dittofeed is an open-source customer engagement platform — think Braze or Customer.io, but self-hosted and fully under your control. Its message worker service dispatches emails, push notifications, and SMS based on user journeys. When that worker silently stalls, customers stop receiving messages without any visible error in your app. Vigilmon catches these silent failures before they become customer complaints. In this tutorial you'll set up monitoring for the API health endpoint, web dashboard, message worker heartbeat, and SSL certificate.
What You'll Build
- A Vigilmon HTTP monitor for Dittofeed's API health endpoint
- A web dashboard availability check
- A heartbeat monitor for the message worker service
- SSL certificate expiry alerts
- Slack and email alert channels
Prerequisites
- A running Dittofeed instance (Docker Compose is the standard deployment)
- Dittofeed accessible at a public or VPN-routable URL
- A free Vigilmon account
Step 1: Monitor the API Health Endpoint
Dittofeed exposes a health endpoint on its API service. By default the API runs on port 3001 and responds at /api/public/health with a JSON payload.
curl https://dittofeed.yourdomain.com/api/public/health
# {"status":"ok"}
In Vigilmon, create a new HTTP Monitor:
| Field | Value |
|---|---|
| URL | https://dittofeed.yourdomain.com/api/public/health |
| Method | GET |
| Check interval | 60 seconds |
| Expected status | 200 |
| Keyword match | "ok" |
| Timeout | 10 seconds |
| Regions | 2–3 for triangulation |
The keyword match on "ok" guards against the endpoint returning 200 with an error body — a subtle failure mode that a status-only check misses. If the API service crashes or its database connection drops, this monitor fires within one check cycle.
Step 2: Web Dashboard Availability Check
The Dittofeed web dashboard (Lite UI) runs as a separate Next.js service, typically on port 3000. A healthy API doesn't guarantee the dashboard is reachable — they're separate processes.
Create a second HTTP monitor:
| Field | Value |
|---|---|
| URL | https://dittofeed.yourdomain.com |
| Method | GET |
| Expected status | 200 |
| Keyword match | Dittofeed |
| Check interval | 5 minutes |
This validates that:
- The Next.js dashboard process is running
- Your reverse proxy is routing traffic correctly
- Static assets are being served
If you've restricted the dashboard behind VPN or basic auth, you can skip this check or configure the monitor with an Authorization header.
Step 3: Heartbeat Monitor for the Message Worker
The message worker is Dittofeed's most critical service — it reads journey steps, evaluates user segments, and dispatches messages to email/SMS/push providers. If this worker crashes, user journeys freeze silently.
In Vigilmon, go to Heartbeat Monitors → New:
| Field | Value |
|---|---|
| Name | Dittofeed Message Worker |
| Expected interval | 5 minutes |
| Grace period | 2 minutes |
Copy the ping URL:
https://vigilmon.online/api/heartbeats/YOUR-UUID/ping
Dittofeed's worker service is a Node.js process. Add a periodic ping to your worker's main loop or use a lightweight cron inside the worker container. The simplest approach is a sidecar cron job in your Docker Compose setup:
# docker-compose.yml (add this service alongside your existing ones)
services:
# ... your existing dittofeed services ...
worker-heartbeat:
image: curlimages/curl:latest
restart: unless-stopped
environment:
- VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeats/YOUR-UUID/ping
command: >
sh -c "while true; do
if wget -q --spider http://worker:9090/health 2>/dev/null; then
curl -s $$VIGILMON_HEARTBEAT_URL > /dev/null;
fi;
sleep 300;
done"
depends_on:
- worker
This pattern checks the worker's internal health port (9090 is Dittofeed's default metrics/health port for the worker) before pinging Vigilmon — so silence always means the worker is unhealthy, not just that the sidecar failed.
If you prefer a pure environment variable approach without a sidecar, add this to your worker's startup script:
#!/bin/sh
# entrypoint.sh — wrap the worker with a heartbeat loop
(
while true; do
sleep 300
curl -sf "$VIGILMON_HEARTBEAT_URL" > /dev/null 2>&1 || true
done
) &
exec node dist/worker.js
Step 4: SSL Certificate Expiry Alerts
Edit the API health monitor in Vigilmon and enable SSL Certificate Monitoring:
| Field | Value | |---|---| | Alert when expiry < | 21 days | | Alert again at | 7 days |
Customer engagement platforms handle user PII — a lapsed certificate doesn't just cause downtime, it can trigger compliance incidents. This alert fires even if your Let's Encrypt auto-renewal is set up, catching the case where renewal silently fails.
Step 5: Alert Routing
Vigilmon → Alert Channels → Email → assign to all monitors.
Slack
- Create a Slack incoming webhook for your
#opsor#alertschannel - Vigilmon → Alert Channels → Add Channel → Webhook → paste the Slack URL
- Assign to all monitors
Effective alert message structure:
🔴 *Dittofeed Message Worker* heartbeat expired
Last ping: 8 minutes ago (window: 7 minutes)
Check worker container: docker logs dittofeed-worker
Production Checklist
- [ ] API health monitor with keyword match on
"ok" - [ ] Dashboard availability check every 5 minutes
- [ ] Message worker heartbeat with 7-minute window
- [ ]
VIGILMON_HEARTBEAT_URLinjected into worker container - [ ] SSL expiry alert at 21 days
- [ ] Alert channels assigned to all monitors and tested
Wrapping Up
Dittofeed's architecture separates the API, dashboard, and worker into independent processes — which means each can fail independently without taking the others down. Vigilmon covers all three:
- API health: polled every 60 seconds, keyword-validated
- Dashboard: UI availability checked every 5 minutes
- Message worker: heartbeat confirms journey processing is alive
- SSL: expiry alerts before certs lapse
With these monitors in place, a crashed message worker triggers an alert within 7 minutes — before your users notice that their onboarding emails stopped arriving.
Sign up for Vigilmon — free tier includes multiple monitors and heartbeat checks with no credit card required.