tutorial

Monitoring Cockpit CMS with Vigilmon

Cockpit is a lightweight self-hosted headless CMS with REST and GraphQL APIs — but API endpoint failures, Admin UI outages, and content sync job breakdowns silently break JAMstack builds and decoupled frontend apps. Here's how to monitor Cockpit availability, REST/GraphQL APIs, content jobs, and SSL certificates with Vigilmon.

Cockpit is a lightweight open-source headless CMS built in PHP. It is self-hosted, API-first, and designed for flexible content modeling without a fixed frontend — making it popular for JAMstack builds, decoupled architecture projects, and developer-driven content workflows. Cockpit exposes both REST and GraphQL APIs, allowing frontend frameworks (Next.js, Nuxt, SvelteKit, Astro) to pull content at build time or runtime. When Cockpit's API goes down, static site generators fail their content fetch step and stop building, and SSR frontends begin serving stale or error pages. When the Admin UI fails, content editors lose access without any automated alert. When content sync jobs or scheduled publication triggers break, content goes unpublished silently. Vigilmon gives you external monitoring for Cockpit's REST API, GraphQL endpoint, Admin UI, content jobs, and SSL certificates so you catch failures before they surface as build errors or blank frontend pages.

What You'll Set Up

  • Cockpit REST API availability (/api/collections/listCollections)
  • Admin UI login page availability
  • GraphQL API endpoint availability (/api/gql)
  • Content sync job and scheduled publication health via cron heartbeats
  • SSL certificate expiry alerts for HTTPS Cockpit deployments

Prerequisites

  • Cockpit CMS 2.x running on a server you control (self-hosted PHP)
  • API key for your Cockpit instance
  • Shell access to the Cockpit host
  • A free Vigilmon account

Step 1: Monitor the Cockpit REST API

The Cockpit REST API is the primary data source for frontend apps and build pipelines. The /api/collections/listCollections endpoint lists all available content collections — a healthy response confirms the API layer, PHP runtime, and database (SQLite or MongoDB) are all functioning. When this endpoint returns a 500, a blank response, or a timeout, every downstream build or live data fetch fails:

  1. In Vigilmon, click Add MonitorHTTP Keyword.
  2. Set the URL to https://your-cockpit-domain.com/api/collections/listCollections?token=YOUR_API_KEY.
  3. Set Keyword to [ or a known collection name (the response is a JSON array).
  4. Set Check interval to 2 minutes.

For a keyword-agnostic check, use HTTP status monitoring:

  1. In Vigilmon, click Add MonitorHTTP.
  2. Set URL to https://your-cockpit-domain.com/api/collections/listCollections?token=YOUR_API_KEY.
  3. Set Expected status to 200.
  4. Set Check interval to 2 minutes.

For private Cockpit instances (not accessible from the internet), monitor from the host:

#!/bin/bash
# /usr/local/bin/cockpit-api-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
COCKPIT_URL="https://your-cockpit-domain.com"
API_KEY="your-api-key"
TIMEOUT=15

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "${COCKPIT_URL}/api/collections/listCollections?token=${API_KEY}")

if [ "$HTTP_CODE" = "200" ]; then
  echo "Cockpit REST API OK: HTTP 200"
  curl -s "$HEARTBEAT_URL"
else
  echo "Cockpit REST API FAILED: HTTP $HTTP_CODE"
  exit 1
fi

Install as a cron heartbeat:

chmod +x /usr/local/bin/cockpit-api-check.sh
(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/cockpit-api-check.sh >> /var/log/cockpit-api-health.log 2>&1") | crontab -

Step 2: Monitor the Admin UI

The Cockpit Admin UI at the root URL (e.g., https://your-cockpit-domain.com) or at a custom base path provides the web interface for content editors. Admin UI failures often occur independently of the API — a broken PHP session handler, a missing asset, or a misconfigured .htaccess rewrite rule can render the Admin UI inaccessible while the API continues responding to authenticated requests. Monitor the Admin login page directly:

  1. In Vigilmon, click Add MonitorHTTP Keyword.
  2. Set the URL to https://your-cockpit-domain.com (the Admin UI login page).
  3. Set Keyword to Cockpit (present in the login page HTML).
  4. Set Check interval to 5 minutes.
  5. Set Alert after 2 consecutive failures.

For a shell-based check (if the Admin UI is on an internal network):

#!/bin/bash
# /usr/local/bin/cockpit-admin-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
COCKPIT_ADMIN_URL="https://your-cockpit-domain.com"
EXPECTED_KEYWORD="Cockpit"
TIMEOUT=15

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" "$COCKPIT_ADMIN_URL")
HTTP_RESPONSE=$(curl -s --max-time "$TIMEOUT" "$COCKPIT_ADMIN_URL")

if [ "$HTTP_CODE" != "200" ]; then
  echo "Admin UI returned HTTP $HTTP_CODE"
  exit 1
fi

if echo "$HTTP_RESPONSE" | grep -qi "$EXPECTED_KEYWORD"; then
  echo "Admin UI OK"
  curl -s "$HEARTBEAT_URL"
else
  echo "Admin UI keyword '$EXPECTED_KEYWORD' not found"
  exit 1
fi
chmod +x /usr/local/bin/cockpit-admin-check.sh
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/cockpit-admin-check.sh >> /var/log/cockpit-admin-health.log 2>&1") | crontab -

Step 3: Monitor the GraphQL API

Cockpit exposes a GraphQL endpoint at /api/gql in addition to its REST API. GraphQL is used by many modern frontend frameworks and toolchains — if the GraphQL endpoint fails while the REST API stays up, GraphQL-based frontends break silently while REST-based builds continue working. Monitor the GraphQL endpoint independently:

#!/bin/bash
# /usr/local/bin/cockpit-graphql-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
COCKPIT_URL="https://your-cockpit-domain.com"
API_KEY="your-api-key"
TIMEOUT=15

# Send a minimal GraphQL introspection query to verify the endpoint
GRAPHQL_QUERY='{"query": "{ __typename }"}'

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cockpit-Token: ${API_KEY}" \
  -d "$GRAPHQL_QUERY" \
  "${COCKPIT_URL}/api/gql")

GQL_RESPONSE=$(curl -s \
  --max-time "$TIMEOUT" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cockpit-Token: ${API_KEY}" \
  -d "$GRAPHQL_QUERY" \
  "${COCKPIT_URL}/api/gql")

if [ "$HTTP_CODE" = "200" ] && echo "$GQL_RESPONSE" | grep -q "data"; then
  echo "GraphQL API OK: HTTP 200, data field present"
  curl -s "$HEARTBEAT_URL"
elif [ "$HTTP_CODE" = "200" ]; then
  echo "GraphQL API returned 200 but response looks unexpected: $GQL_RESPONSE"
  exit 1
else
  echo "GraphQL API FAILED: HTTP $HTTP_CODE"
  exit 1
fi

Install the check:

chmod +x /usr/local/bin/cockpit-graphql-check.sh
(crontab -l 2>/dev/null; echo "*/3 * * * * /usr/local/bin/cockpit-graphql-check.sh >> /var/log/cockpit-graphql-health.log 2>&1") | crontab -

Set the Vigilmon heartbeat to 5 minutes. If the GraphQL check fails while the REST API check succeeds, the issue is specific to the GraphQL module — check Cockpit's PHP error log and verify the gql module is enabled in Cockpit's config.


Step 4: Monitor Content Sync Jobs and Scheduled Publication

Many Cockpit deployments integrate content publication triggers — webhooks that fire when content is published, build pipeline triggers for static site generators, or scheduled tasks that publish content at specific times. When these jobs break, scheduled content (a product launch announcement, a timed blog post, a campaign activation) never goes live. Monitor content sync and publication jobs via heartbeats:

Static site build trigger heartbeat:

#!/bin/bash
# /usr/local/bin/cockpit-build-trigger.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
COCKPIT_URL="https://your-cockpit-domain.com"
API_KEY="your-api-key"
BUILD_WEBHOOK_URL="https://your-ci-system.com/hooks/build-trigger"
TIMEOUT=20

# Verify Cockpit API is healthy before triggering the build
API_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time 15 \
  "${COCKPIT_URL}/api/collections/listCollections?token=${API_KEY}")

if [ "$API_CODE" != "200" ]; then
  echo "Cockpit API unhealthy ($API_CODE) — skipping build trigger"
  exit 1
fi

# Trigger the build
BUILD_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  -X POST "$BUILD_WEBHOOK_URL")

if [ "$BUILD_CODE" = "200" ] || [ "$BUILD_CODE" = "201" ] || [ "$BUILD_CODE" = "204" ]; then
  echo "Build trigger OK: HTTP $BUILD_CODE"
  curl -s "$HEARTBEAT_URL"
else
  echo "Build trigger FAILED: HTTP $BUILD_CODE"
  exit 1
fi

Scheduled content publication check:

#!/bin/bash
# /usr/local/bin/cockpit-scheduled-publish.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"
COCKPIT_URL="https://your-cockpit-domain.com"
API_KEY="your-api-key"
COLLECTION_NAME="posts"  # Collection with scheduled content
TIMEOUT=15

# Check for any content items with _scheduled field in the past that are not yet published
NOW=$(date +%s)

OVERDUE=$(curl -s \
  --max-time "$TIMEOUT" \
  "${COCKPIT_URL}/api/collections/get/${COLLECTION_NAME}?token=${API_KEY}&filter[published]=false" | \
  python3 -c "
import sys, json
from datetime import datetime

try:
    data = json.load(sys.stdin)
    entries = data.get('entries', [])
    now = $NOW
    overdue = [
        e for e in entries
        if e.get('_scheduled') and int(e['_scheduled']) < now - 300  # 5 min grace
    ]
    print(len(overdue))
except:
    print(0)
" 2>/dev/null || echo 0)

if [ "$OVERDUE" -eq 0 ]; then
  echo "No overdue scheduled content"
  curl -s "$HEARTBEAT_URL"
else
  echo "WARNING: $OVERDUE content item(s) past their scheduled publish time but still unpublished"
  exit 1
fi

Add the cron entries:

chmod +x /usr/local/bin/cockpit-build-trigger.sh /usr/local/bin/cockpit-scheduled-publish.sh

# Build trigger: every 30 minutes
(crontab -l 2>/dev/null; echo "*/30 * * * * /usr/local/bin/cockpit-build-trigger.sh >> /var/log/cockpit-build-trigger.log 2>&1") | crontab -

# Scheduled publish check: every 5 minutes
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/cockpit-scheduled-publish.sh >> /var/log/cockpit-scheduled-publish.log 2>&1") | crontab -

Set Vigilmon heartbeat expected intervals: 35 minutes for the build trigger and 7 minutes for the scheduled publish check.


Step 5: Monitor SSL Certificates

Cockpit deployments are typically on developer-managed VPS hosts where SSL certificates are renewed manually or via cron-triggered Certbot. An expired certificate causes the HTTPS API endpoint to fail hard — all build pipelines using HTTPS requests fail, and frontend apps that enforce TLS validation begin returning fetch errors:

  1. In Vigilmon, click Add MonitorSSL Certificate.
  2. Set Domain to your-cockpit-domain.com.
  3. Set Alert before expiry to 14 days.

For shell-based SSL monitoring:

#!/bin/bash
# /usr/local/bin/cockpit-ssl-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/pqr678"
DOMAIN="your-cockpit-domain.com"
MIN_DAYS_REMAINING=14

EXPIRY_DATE=$(echo | openssl s_client -servername "$DOMAIN" \
  -connect "${DOMAIN}:443" 2>/dev/null | \
  openssl x509 -noout -enddate 2>/dev/null | \
  cut -d= -f2)

if [ -z "$EXPIRY_DATE" ]; then
  echo "Could not retrieve SSL certificate for $DOMAIN"
  exit 1
fi

EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null || \
  date -j -f "%b %d %T %Y %Z" "$EXPIRY_DATE" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_REMAINING=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ "$DAYS_REMAINING" -ge "$MIN_DAYS_REMAINING" ]; then
  echo "SSL OK: $DAYS_REMAINING days until expiry"
  curl -s "$HEARTBEAT_URL"
else
  echo "SSL EXPIRING SOON: $DAYS_REMAINING days remaining"
  exit 1
fi

Run daily with a 25 hour Vigilmon heartbeat.


Step 6: Set Up Alert Channels

Configure Vigilmon to route Cockpit alerts appropriately:

  1. Go to Alert Channels in Vigilmon.
  2. Add a Slack webhook to #cms-ops for REST API and GraphQL monitors — API failures break active build pipelines immediately.
  3. Add email notification for Admin UI and SSL monitors — these are critical but not always on-call emergencies.
  4. Add a webhook to your build system's alert channel for the scheduled publish monitor — content delivery teams need to know about stale content.
  5. Set Consecutive failures before alert to 1 for the REST API monitor — a single API failure can break a JAMstack build mid-deploy.

Add a maintenance window during Cockpit upgrades:

curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "COCKPIT_API_MONITOR_ID",
    "duration_minutes": 20,
    "reason": "Cockpit CMS upgrade"
  }'

Summary

| Monitor | Target | What It Catches | |---|---|---| | HTTP keyword (REST API) | /api/collections/listCollections | PHP failure, database loss, API routing break | | HTTP keyword (Admin UI) | / (Admin login page) | Admin UI render failure, PHP session issue | | Cron heartbeat (GraphQL) | /api/gql introspection | GraphQL module failure | | Cron heartbeat (build trigger) | CI build webhook | Build pipeline decoupling | | Cron heartbeat (scheduled publish) | Collection query | Overdue scheduled content items | | SSL certificate | your-cockpit-domain.com | Certificate expiry, Let's Encrypt failure |

Cockpit's headless, API-first design means its failures are felt primarily in build pipelines and frontend apps rather than in visible UI errors. A broken API endpoint surfaces as a failed Netlify deploy, a blank Gatsby site, or a Next.js data fetch error in production — not as an obvious Cockpit error page. External monitoring with Vigilmon catches Cockpit API failures at the source, before they cascade into downstream build failures or content delivery outages.

Start monitoring for free at vigilmon.online.

Monitor your app with Vigilmon

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

Start free →