Balena lets you deploy and update containerised applications to thousands of IoT edge devices with a single git push — but when the openBalena server goes down, every device in your fleet loses its update channel and OTA deployments silently halt. Vigilmon fills that gap, watching the openBalena API, VPN server, Docker registry, and fleet-level health metrics so you know about problems before your devices do.
What You'll Set Up
- openBalena API server uptime monitor
- VPN server health check (the backbone of device connectivity)
- Docker registry availability monitor
- Fleet device online percentage via heartbeat cron
- OTA update success rate alerting
- PostgreSQL database connectivity check
Prerequisites
- openBalena deployed (self-hosted) or balenaCloud account
- openBalena API accessible on port 443
- A free Vigilmon account
Step 1: Monitor the openBalena API Server
The openBalena API is the single point through which devices register, report telemetry, and receive OTA update commands. If it goes down, devices queue updates locally but can't receive new releases.
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your openBalena API URL:
https://api.youropenbalena.example.com/ping - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Click Save.
The /ping endpoint is a built-in health probe in openBalena that returns OK when the API process is healthy. If this monitor fires, devices are immediately cut off from the fleet management server — treat this as a P1 alert.
Step 2: Monitor the openBalena VPN Server
openBalena uses an OpenVPN-based overlay to maintain persistent tunnels to every online device, enabling SSH access, log streaming, and remote debugging even behind NAT. If the VPN server crashes, all device tunnels drop simultaneously and operators lose the ability to SSH into any device.
- Add a new monitor → TCP Port.
- Set Host to
vpn.youropenbalena.example.com. - Set Port to
443(openBalena VPN uses TLS on port 443 by default). - Set Check interval to
1 minute. - Click Save.
Separately, add an HTTP monitor for the VPN management API if your openBalena version exposes one:
https://vpn.youropenbalena.example.com/ping
A VPN server outage causes mass device disconnection — all devices will show as "offline" in the openBalena dashboard even if the devices themselves are running fine.
Step 3: Monitor the Docker Registry
openBalena runs a private Docker registry that stores container images for all your applications. Devices pull images from this registry during OTA updates. Registry downtime doesn't immediately affect running containers, but it blocks all new deployments and OTA updates.
- Add a new monitor → HTTP / HTTPS.
- Enter:
https://registry.youropenbalena.example.com/v2/ - Set Expected HTTP status to
401(the registry returns 401 for unauthenticated requests — this is the correct health signal, confirming the registry is alive and requiring authentication). - Set Check interval to
2 minutes. - Click Save.
Alternatively, if your registry is configured to allow anonymous health checks:
# Test locally
curl -s https://registry.youropenbalena.example.com/v2/ -o /dev/null -w "%{http_code}"
# Returns 200 or 401 when healthy, 000 or 5xx when down
Step 4: Fleet Device Online Percentage via Cron Heartbeat
The most important fleet-level metric is what percentage of your devices are currently online. A sudden drop below your baseline (say, from 95% to 70%) indicates a network event, power outage, or ISP issue affecting a device cluster.
Create a script that queries the openBalena API for fleet status and sends a heartbeat to Vigilmon only when the online percentage is above your threshold:
- In Vigilmon, click Add Monitor → Cron Heartbeat.
- Set the expected ping interval to
5 minutes. - Copy the heartbeat URL (e.g.
https://vigilmon.online/heartbeat/abc123).
Deploy this script on the openBalena server or a management host:
#!/bin/bash
# fleet-health-check.sh
BALENA_API="https://api.youropenbalena.example.com"
BALENA_TOKEN="your-api-token"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
THRESHOLD=90 # alert if online % drops below 90%
# Fetch device list
RESPONSE=$(curl -s -H "Authorization: Bearer $BALENA_TOKEN" \
"$BALENA_API/v6/device?\$select=is_online,uuid&\$top=2000")
TOTAL=$(echo "$RESPONSE" | jq '.d | length')
ONLINE=$(echo "$RESPONSE" | jq '[.d[] | select(.is_online == true)] | length')
if [ "$TOTAL" -gt 0 ]; then
PCT=$(( ONLINE * 100 / TOTAL ))
echo "Fleet online: $ONLINE/$TOTAL ($PCT%)"
if [ "$PCT" -ge "$THRESHOLD" ]; then
curl -s "$HEARTBEAT_URL"
fi
fi
Add to crontab:
*/5 * * * * /opt/balena/fleet-health-check.sh >> /var/log/balena-health.log 2>&1
If the online percentage drops below 90%, the heartbeat stops and Vigilmon alerts after the 5-minute window passes. Tune the threshold to match your fleet's normal variance.
Step 5: OTA Update Success Rate Monitoring
Stuck OTA updates are silent failures — devices stop at a partial state, new releases don't propagate, and nothing alerts you unless you're actively checking the dashboard. Monitor update success rate with a cron heartbeat that only pings when updates are proceeding normally:
#!/bin/bash
# ota-health-check.sh
BALENA_API="https://api.youropenbalena.example.com"
BALENA_TOKEN="your-api-token"
OTA_HEARTBEAT="https://vigilmon.online/heartbeat/def456"
MAX_STUCK=10 # alert if more than 10% of devices are stuck
# Count devices in "updating" state for more than 30 minutes
STUCK=$(curl -s -H "Authorization: Bearer $BALENA_TOKEN" \
"$BALENA_API/v6/device?\$filter=status eq 'Updating'" | jq '.d | length')
TOTAL=$(curl -s -H "Authorization: Bearer $BALENA_TOKEN" \
"$BALENA_API/v6/device?\$select=uuid" | jq '.d | length')
if [ "$TOTAL" -gt 0 ]; then
STUCK_PCT=$(( STUCK * 100 / TOTAL ))
if [ "$STUCK_PCT" -le "$MAX_STUCK" ]; then
curl -s "$OTA_HEARTBEAT"
fi
fi
Set the Vigilmon heartbeat interval to 10 minutes. If the stuck-device percentage spikes above your threshold, the heartbeat stops and Vigilmon alerts.
Step 6: PostgreSQL Database Connectivity
openBalena stores all device state, fleet configuration, and release metadata in PostgreSQL. Database connectivity loss causes device state to become stale and OTA update tracking to stop working. Monitor the database port from the openBalena server:
- Add a new monitor → TCP Port.
- Set Host to your PostgreSQL host (or
localhostif running on the same server). - Set Port to
5432. - Set Check interval to
1 minute. - Click Save.
If your PostgreSQL port isn't directly accessible, add a lightweight health endpoint to your openBalena deployment that checks DB connectivity:
// health.js — add to openBalena's internal health check
app.get('/healthz/db', async (req, res) => {
try {
await db.query('SELECT 1');
res.json({ db: 'ok' });
} catch (err) {
res.status(503).json({ db: 'error', message: err.message });
}
});
Then monitor https://api.youropenbalena.example.com/healthz/db with an expected status of 200.
Step 7: Device Last-Seen Timestamp Alerts
For latency-sensitive IoT applications (industrial sensors, medical devices, security cameras), any device that hasn't been seen in the last 6 hours needs immediate attention. This script generates an alert for offline devices:
#!/bin/bash
# last-seen-check.sh
BALENA_API="https://api.youropenbalena.example.com"
BALENA_TOKEN="your-api-token"
LAST_SEEN_HEARTBEAT="https://vigilmon.online/heartbeat/ghi789"
MAX_OFFLINE_HOURS=6
# Find devices not seen in the last N hours
CUTOFF=$(date -u -d "$MAX_OFFLINE_HOURS hours ago" +%Y-%m-%dT%H:%M:%SZ)
OVERDUE=$(curl -s -H "Authorization: Bearer $BALENA_TOKEN" \
"$BALENA_API/v6/device?\$filter=last_connectivity_event lt '$CUTOFF' and is_online eq false" \
| jq '.d | length')
if [ "$OVERDUE" -eq 0 ]; then
curl -s "$LAST_SEEN_HEARTBEAT"
fi
Run every 30 minutes. If any device goes quiet for 6 hours, the heartbeat stops and Vigilmon alerts.
Step 8: Configure Alert Channels
- Go to Alert Channels in Vigilmon and add Slack, email, or webhook.
- Set Consecutive failures before alert to
2for the API and VPN monitors — brief restarts are normal during openBalena upgrades. - Set Consecutive failures before alert to
1for the PostgreSQL monitor — database downtime should alert immediately. - Use Maintenance windows in Vigilmon when deploying openBalena server updates:
# Before updating openBalena server
curl -X POST https://vigilmon.online/api/maintenance \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"monitor_id": "api-monitor-id", "duration_minutes": 15}'
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| API server | https://api.openbalena/ping | Device connectivity loss, OTA update halt |
| VPN server | TCP :443 on VPN host | Mass device disconnection |
| Docker registry | https://registry.openbalena/v2/ | Deployment blockage |
| Fleet online % | Cron heartbeat every 5 min | Network outage, mass device failure |
| OTA update rate | Cron heartbeat every 10 min | Stuck updates, image incompatibility |
| PostgreSQL | TCP :5432 | Device state staleness |
| Device last-seen | Cron heartbeat every 30 min | Individual device offline >6 hours |
openBalena gives you full control over your IoT fleet — but that control means you own the monitoring too. With Vigilmon watching the server stack and fleet health metrics, you'll know about connectivity issues and stuck OTA updates before they become fleet-wide outages.