Baikal is a slim, PHP-based CalDAV and CardDAV server that lets you self-host your calendars, task lists, and contacts without relying on Google Calendar or iCloud. It runs under any web server (nginx, Apache) and stores data in SQLite or MySQL. The downside of self-hosting is that sync failures — a misconfigured PHP-FPM pool, a corrupted SQLite file, or an expired TLS certificate — are completely silent to calendar clients until your phone stops syncing at the worst possible time. Vigilmon closes that gap with continuous endpoint monitoring, TLS expiry alerts, and PHP-FPM heartbeats.
What You'll Set Up
- HTTPS availability monitor for the Baikal web UI and DAV endpoints
- TLS/SSL certificate expiry alert
- PHP-FPM process health monitoring via a heartbeat
- CalDAV and CardDAV endpoint response time checks
- SQLite/MySQL database connectivity probe
- Admin panel accessibility check
- Cron heartbeat for the database backup job
Prerequisites
- Baikal installed and accessible over HTTPS (nginx or Apache, port 443)
- PHP-FPM running and serving Baikal
- A free Vigilmon account
Step 1: Monitor the Baikal Web Server Availability
Baikal's entire feature set lives behind the web server. If nginx crashes or PHP-FPM stops responding, every calendar client silently fails to sync.
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your Baikal URL:
https://baikal.yourdomain.com/html/. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Click Save.
If you installed Baikal in the document root, the URL may simply be https://baikal.yourdomain.com/.
Step 2: Monitor TLS Certificate Expiry
CalDAV and CardDAV clients reject expired certificates immediately, breaking all sync without any user-visible error on the server side. Let's Encrypt renewals can fail silently.
- Open the HTTP / HTTPS monitor created in Step 1.
- Enable Monitor SSL certificate.
- Set Alert when certificate expires in less than
21 days. - Click Save.
A 21-day window gives you three Let's Encrypt renewal cycles to recover before clients break. Verify your renewal cron job:
# Check the certbot/acme renewal timer
systemctl status certbot.timer
# Or for acme.sh
~/.acme.sh/acme.sh --list
Step 3: Monitor the CalDAV Endpoint
Baikal's CalDAV endpoint handles all calendar sync requests from iOS, Android, and Thunderbird. Monitor it directly to catch PHP or routing failures that wouldn't show up on the homepage:
- Click Add Monitor → HTTP / HTTPS.
- URL:
https://baikal.yourdomain.com/dav.php/calendars/ - Set Expected HTTP status to
401(Baikal returns 401 Unauthorized for unauthenticated requests — this confirms the endpoint is alive). - Set Check interval to
2 minutes. - Click Save.
Alternatively, if using the HTML directory layout:
https://baikal.yourdomain.com/html/index.php/dav/calendars/
A 401 response is healthy — it means Baikal processed the request. A 502 Bad Gateway or 504 Gateway Timeout means PHP-FPM is down.
Step 4: Monitor the CardDAV Endpoint
The CardDAV endpoint handles contact sync separately from CalDAV. Add a parallel monitor:
- Click Add Monitor → HTTP / HTTPS.
- URL:
https://baikal.yourdomain.com/dav.php/addressbooks/ - Set Expected HTTP status to
401. - Set Check interval to
2 minutes. - Click Save.
If you use the HTML path layout:
https://baikal.yourdomain.com/html/index.php/dav/addressbooks/
Step 5: Monitor PHP-FPM Health
PHP-FPM has a built-in status endpoint that reports pool status, active processes, and request queue depth. Expose it in your nginx config:
# /etc/nginx/sites-available/baikal
server {
...
location /php-fpm-status {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
allow 127.0.0.1;
deny all;
}
}
Enable the status page in your PHP-FPM pool config (/etc/php/8.2/fpm/pool.d/www.conf):
pm.status_path = /php-fpm-status
Reload PHP-FPM:
systemctl reload php8.2-fpm
Then add a Vigilmon monitor:
- Click Add Monitor → HTTP / HTTPS.
- URL:
http://127.0.0.1/php-fpm-status(or use an internal monitoring URL if you expose it on a non-public interface). - Set Expected HTTP status to
200. - Set Check interval to
1 minute. - Click Save.
If PHP-FPM is unreachable, you'll see a 502 from nginx on all Baikal endpoints — this monitor identifies the root cause.
Step 6: Monitor the Admin Panel
Baikal's admin panel (/admin/) is the management interface for users and collections. Monitor it separately — admin routing can break independently of the DAV endpoints:
- Click Add Monitor → HTTP / HTTPS.
- URL:
https://baikal.yourdomain.com/html/admin/ - Set Expected HTTP status to
200. - Set Check interval to
5 minutes. - Click Save.
Step 7: Monitor Database Connectivity
Baikal stores all calendar and contact data in SQLite (default) or MySQL. A corrupt SQLite file or a MySQL connection failure means all DAV operations return errors.
SQLite Health Check Script
Create a script that probes the SQLite file and pings Vigilmon on success:
#!/bin/bash
# /usr/local/bin/baikal-db-check.sh
BAIKAL_DB="/var/www/baikal/Specific/db/db.sqlite"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_ID"
if sqlite3 "$BAIKAL_DB" "SELECT COUNT(*) FROM calendarobjects;" > /dev/null 2>&1; then
curl -s "$HEARTBEAT_URL"
else
echo "Baikal SQLite check failed" | mail -s "Baikal DB Alert" admin@yourdomain.com
fi
chmod +x /usr/local/bin/baikal-db-check.sh
MySQL Health Check Script
If using MySQL instead:
#!/bin/bash
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_ID"
if mysql -u baikal -p"$BAIKAL_DB_PASS" baikal -e "SELECT 1;" > /dev/null 2>&1; then
curl -s "$HEARTBEAT_URL"
fi
Create the Vigilmon heartbeat monitor:
- Click Add Monitor → Cron Heartbeat.
- Set the expected interval to
5 minutes. - Copy the heartbeat URL into the script above.
Schedule the check:
# /etc/cron.d/baikal-db-check
*/5 * * * * root /usr/local/bin/baikal-db-check.sh
Step 8: Heartbeat for the Database Backup Job
Your Baikal backup cron (or a script using sqlite3 .dump / mysqldump) should ping Vigilmon after each successful run:
#!/bin/bash
# /usr/local/bin/baikal-backup.sh
BACKUP_DIR="/backups/baikal"
BAIKAL_DB="/var/www/baikal/Specific/db/db.sqlite"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_BACKUP_HEARTBEAT_ID"
mkdir -p "$BACKUP_DIR"
sqlite3 "$BAIKAL_DB" ".dump" | gzip > "$BACKUP_DIR/baikal-$(date +%Y%m%d).sql.gz"
if [ $? -eq 0 ]; then
curl -s "$HEARTBEAT_URL"
fi
- In Vigilmon, click Add Monitor → Cron Heartbeat.
- Set the expected interval to match your backup schedule (e.g.
24 hours). - Set the heartbeat URL in your backup script.
Add to crontab:
# Daily backup at 2 AM
0 2 * * * root /usr/local/bin/baikal-backup.sh
If the backup script fails or is never run (e.g. the cron daemon crashes), Vigilmon alerts after the 24-hour window passes.
Step 9: Configure Alert Channels
- Go to Alert Channels in Vigilmon and add your preferred channel (email, Slack, webhook, PagerDuty).
- For the CalDAV and CardDAV endpoint monitors, set Consecutive failures before alert to
2— transient PHP-FPM restarts can cause a single probe to fail. - For the TLS certificate monitor, use immediate alerting — a certificate warning has a fixed deadline.
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| Web server | https://baikal.yourdomain.com/ | nginx/Apache down |
| TLS certificate | HTTPS endpoint | Let's Encrypt renewal failure |
| CalDAV endpoint | /dav.php/calendars/ → 401 | PHP routing or auth failure |
| CardDAV endpoint | /dav.php/addressbooks/ → 401 | PHP routing or auth failure |
| PHP-FPM status | /php-fpm-status | FPM pool exhausted or crashed |
| Admin panel | /html/admin/ | Admin routing broken |
| Database heartbeat | Heartbeat URL | SQLite corruption, MySQL down |
| Backup heartbeat | Heartbeat URL | Backup job missed or crashed |
Baikal's simplicity is its strength — and its monitoring blind spot. Calendar clients retry in the background and surface no errors until sync is hours behind. Vigilmon's continuous checks catch web server failures, PHP-FPM exhaustion, and expired certificates before your contacts and calendar entries stop syncing.