tutorial

Monitoring Damselfly with Vigilmon

Damselfly is a high-performance self-hosted photo DAM system built on .NET 8 — here's how to monitor its Blazor web UI, REST API, indexing pipeline, SSL certificate, and background scan health with Vigilmon.

Damselfly is a self-hosted digital asset management (DAM) system designed for photographers and enthusiasts with large local photo archives. Built on C#/.NET 8 with a Blazor WebAssembly frontend, it indexes photos directly from a local filesystem path — no import step required — and provides AI-powered face recognition, IPTC metadata editing, keyword tagging, and basket/export functionality. Because Damselfly continuously indexes a watched directory in the background, the most dangerous failure mode is a silent one: the Blazor UI loads fine, but the background indexer has stopped and new photos added to the watched directory are no longer being discovered. Vigilmon monitors Damselfly from every angle: the Blazor web UI, the REST API, the indexing pipeline health endpoint, SSL certificate validity for reverse-proxied deployments, and a heartbeat tied to the last indexer scan timestamp.

What You'll Set Up

  • HTTP monitor for the Damselfly Blazor web UI (port 6363)
  • HTTP monitor for the Damselfly REST API status endpoint
  • HTTP monitor for the indexing pipeline with a content count check
  • SSL certificate expiry alerts for reverse-proxied HTTPS deployments
  • Heartbeat monitor that confirms the indexing pipeline is actively scanning

Prerequisites

  • Damselfly deployed and accessible (port 6363 is the default Kestrel port)
  • A free Vigilmon account

Step 1: Monitor the Damselfly Blazor Web UI

Damselfly serves its Blazor WebAssembly UI via ASP.NET Core Kestrel on port 6363. A GET / returns the Blazor application HTML shell — a 200 response confirms the .NET 8 runtime and Kestrel web server are running correctly.

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter your Damselfly URL: http://your-server:6363 (or https://photos.yourdomain.com if reverse-proxied).
  4. Set Check interval to 1 minute.
  5. Set Expected HTTP status to 200.
  6. Under Response body check, enter Damselfly to confirm the application shell loaded rather than a generic Kestrel error page.
  7. Click Save.

Damselfly's Blazor app loads the UI shell on first request and bootstraps the frontend via WebAssembly — a 200 response at the root is sufficient to confirm Kestrel is healthy and .NET is running.


Step 2: Monitor the REST API Status Endpoint

Damselfly exposes a REST API for programmatic access to photo data. The /api/status endpoint (or /api/images/status in some builds) returns JSON containing indexing statistics — total photos indexed, pending tasks, and service status. This confirms not just that Kestrel is running, but that the REST API layer and the underlying SQLite or Postgres database are accessible.

  1. Click Add Monitor in Vigilmon.
  2. Set Type to HTTP / HTTPS.
  3. Enter the status URL: http://your-server:6363/api/status
  4. Set Expected HTTP status to 200.
  5. Under Response body check, enter "totalImages" or "status" to confirm a JSON response with indexing data.
  6. Set Check interval to 5 minutes.
  7. Click Save.

A healthy response includes:

{
  "status": "idle",
  "totalImages": 42831,
  "pendingTasks": 0,
  "lastScan": "2026-07-13T08:42:00Z"
}

If the database connection is broken, the API endpoint will return a 500 error or a non-JSON error response — both caught by the status code check.


Step 3: Monitor the Indexing Pipeline with a Content Count Check

The status endpoint tells you the API is up, but the /api/images?first=0&count=1 endpoint confirms the indexing pipeline has completed at least one scan and the database has indexed content. An empty image set while a watched directory exists indicates the indexer has never run successfully or was interrupted before completing its initial scan.

  1. Click Add Monitor in Vigilmon.
  2. Set Type to HTTP / HTTPS.
  3. Enter the images URL: http://your-server:6363/api/images?first=0&count=1
  4. Set Expected HTTP status to 200.
  5. Under Response body check, enter "total" to confirm the response includes a total image count field.
  6. Set Check interval to 10 minutes.
  7. Click Save.

A healthy response looks like:

{
  "total": 42831,
  "entries": [{ "imageId": 1, "fileName": "IMG_0001.jpg", ... }]
}

If the database is empty or inaccessible, total will be 0 or missing — the body check will fail and you'll know the indexer has not successfully populated the database.


Step 4: SSL Certificate Alerts for Reverse-Proxied Deployments

Damselfly is commonly placed behind a reverse proxy (nginx, Caddy, or Traefik) for HTTPS access. An expired certificate locks every user out of the photo management interface.

  1. Open the HTTPS monitor for your Damselfly domain (created in Step 1 or using the proxied URL).
  2. Enable Monitor SSL certificate under the SSL settings.
  3. Set Alert when certificate expires in less than 21 days.
  4. Click Save.

Verify your reverse proxy's TLS is configured correctly:

# Check certificate expiry via openssl
openssl s_client -connect photos.yourdomain.com:443 -servername photos.yourdomain.com \
  </dev/null 2>/dev/null | openssl x509 -noout -dates

# For Traefik (check Traefik dashboard or logs)
journalctl -u traefik --since "24 hours ago" | grep -i "certificate\|acme"

# For nginx + certbot
certbot certificates

Step 5: Heartbeat Monitoring for Indexing Pipeline Health

The API responding correctly does not guarantee that Damselfly is actively scanning the watched directory. The lastScan timestamp in the /api/status response shows when the indexer last completed a scan cycle. A stale timestamp — older than your expected scan interval — means new photos added to the watched directory are not being discovered.

Create the heartbeat monitor first:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to 60 minutes.
  3. Copy the heartbeat URL (e.g. https://vigilmon.online/heartbeat/abc123).

Then set up a cron job on the Damselfly host to check the last scan timestamp:

#!/bin/bash
# /etc/cron.hourly/damselfly-heartbeat

DAMSELFLY_URL="http://localhost:6363"
VIGILMON_HEARTBEAT="https://vigilmon.online/heartbeat/abc123"
MAX_AGE_HOURS=3  # Alert if last scan is older than 3 hours

# Get status with last scan timestamp
STATUS=$(curl -s "${DAMSELFLY_URL}/api/status")

if [ -z "$STATUS" ]; then
  echo "Damselfly API unreachable" >&2
  exit 1
fi

# Extract lastScan timestamp
LAST_SCAN=$(echo "$STATUS" | grep -o '"lastScan":"[^"]*"' | cut -d'"' -f4)

if [ -z "$LAST_SCAN" ]; then
  # If no lastScan field, fall back to checking the API is alive
  if echo "$STATUS" | grep -q '"totalImages"'; then
    curl -s "${VIGILMON_HEARTBEAT}" > /dev/null
  fi
  exit 0
fi

# Parse the timestamp and check how long ago the last scan ran
LAST_SCAN_EPOCH=$(date -d "$LAST_SCAN" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$LAST_SCAN" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
AGE_HOURS=$(( (NOW_EPOCH - LAST_SCAN_EPOCH) / 3600 ))

# Only ping heartbeat if last scan was recent enough
if [ "$AGE_HOURS" -lt "$MAX_AGE_HOURS" ]; then
  curl -s "${VIGILMON_HEARTBEAT}" > /dev/null
else
  echo "Damselfly last scan was ${AGE_HOURS}h ago — indexer may be stalled" >&2
fi

Make the script executable:

chmod +x /etc/cron.hourly/damselfly-heartbeat

For Docker-based Damselfly deployments:

docker exec damselfly curl -s http://localhost:6363/api/status \
  | grep -q '"totalImages"' && curl -s "https://vigilmon.online/heartbeat/abc123"

If the background indexer stops scanning — due to a filesystem permission change, a database lock, or an unhandled .NET exception — the heartbeat will not fire and Vigilmon will alert you before your photo library falls out of sync.


Step 6: Configure Alert Channels

  1. Go to Alert Channels in Vigilmon and add Slack, email, or a webhook.
  2. For the Blazor UI and API monitors, set Consecutive failures before alert to 2 — .NET Kestrel can experience brief startup delays.
  3. For the heartbeat, set Grace period to 0 — a stalled indexer should alert immediately after the interval expires.

Summary

| Monitor | Target | What It Catches | |---|---|---| | Blazor web UI | http://your-server:6363/ | Kestrel down, .NET runtime failure | | REST API status | /api/status | API layer broken, database unreachable | | Indexing content | /api/images?first=0&count=1 | Empty database, initial scan never completed | | SSL certificate | Damselfly domain | Reverse proxy certificate expiry | | Cron heartbeat | Heartbeat URL | Background indexer stalled, new photos not discovered |

Damselfly's biggest risk is silent indexer failure — the Blazor UI remains perfectly responsive while thousands of new photos accumulate in the watched directory without being catalogued. With Vigilmon monitoring the Kestrel server, the REST API, the indexed content count, and a heartbeat tied to the last scan timestamp, you'll know the moment Damselfly stops discovering photos rather than noticing it when you search for an image that should have appeared weeks ago.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →