Monitoring a Self-Hosted CMS: Uptime, Errors, and Alerts (2026)

Uptime checks, logs, server metrics, and alerts that reach you

August 2, 2026 · 11 min read
Monitoring a Self-Hosted CMS: Uptime, Errors, and Alerts (2026)

A single hour of downtime costs the average small business around $427 per minute according to Gartner's oft-cited figures — and even a hobby blog loses search rankings and reader trust when Google's crawler hits a 502. The catch with running your own CMS on a VPS is that nobody else is watching the box. No hosting provider dashboard blinks red at 3 a.m. If your site goes down, you find out when a customer emails you — or worse, when you check analytics a week later and see the flat line.

That's the trade you make for control. You own the stack, so you own the alerting too.

TL;DR: how do you monitor a self-hosted CMS?

Set up three layers. First, an external uptime check (UptimeRobot, Better Uptime, or healthchecks.io) that pings a health URL every 1-5 minutes and messages you when it fails. Second, error tracking — either tail your Laravel logs or wire up Sentry to catch exceptions before users report them. Third, server metrics — disk, CPU, memory, and the MySQL slow query log — so you catch a full disk before it takes the site down.

UnfoldCMS ships a /api/v1/health endpoint specifically so uptime checkers have a clean target that reports both the web server and the database. It does not include a built-in monitoring dashboard or APM — on a self-hosted box, monitoring is your job. What the CMS gives you is a health endpoint plus standard Laravel logs in storage/logs with daily rotation. The rest of this post covers the tools and the wiring.

If you're just standing up your server, read our self-hosted CMS setup guide first, then come back here to add monitoring on top.

What should you monitor on a self-hosted CMS?

Four things, in priority order: is the site up (uptime), is it throwing errors (exceptions and 5xx responses), is the server healthy (disk, RAM, CPU), and is the database slow (query times). Uptime is the one that pages you at night. The other three tell you why it went down and warn you before it does.

Most outages on a small VPS trace back to boring causes. The disk fills up — logs, backups, or MySQL binlogs eat the last free gigabyte and every write starts failing. A memory leak or a traffic spike triggers the OOM killer and it kills MySQL or PHP-FPM. A bad deploy ships a syntax error. A cron job runs away. None of these need fancy tooling to catch. They need something checking the basics on a schedule and telling you when a number crosses a line.

What's the health endpoint pattern and why use it?

A health endpoint is a single URL your app exposes that returns HTTP 200 when everything works and a non-200 (usually 503) when something's broken. Your uptime checker pings it instead of your homepage, so it tests the full stack — web server, PHP, and database — in one request without loading a heavy page.

Pinging your homepage tells you the web server answered. It doesn't tell you the database is reachable, because a cached page can render without touching MySQL. A proper health check runs a cheap query, confirms the DB responds, maybe checks the cache and queue, and returns a small JSON body. UnfoldCMS exposes this at /api/v1/health. A typical response looks like:

{
  "status": "ok",
  "database": "connected",
  "timestamp": "2026-07-03T09:00:00Z"
}

Point your uptime monitor at https://yourdomain.com/api/v1/health and set it to alert when the status code isn't 200 or the body doesn't contain "status": "ok". Now a dead database triggers an alert even while the homepage still serves from cache.

Which uptime monitoring tool should you pick?

For most self-hosted sites, UptimeRobot's free tier (50 monitors, 5-minute checks) is enough to start. If you want 30-second checks, status pages, and better on-call routing, Better Uptime (now Better Stack) is worth the money. For cron jobs and scheduled tasks, healthchecks.io uses the opposite model — your job pings it, and it alerts you when the ping doesn't arrive.

Here's how the common options compare:

What to monitor Tool Check interval Alert channels
Site uptime (HTTP) UptimeRobot (free) 5 min Email, Slack, webhook
Site uptime (fast) Better Stack 30 sec Email, SMS, Slack, phone call
Cron / scheduler ran healthchecks.io Your schedule Email, Slack, Telegram, PagerDuty
Server CPU/RAM/disk Netdata (self-hosted) or Grafana Cloud 1 sec – 1 min Email, Slack, Discord
App exceptions Sentry (free tier) Real-time Email, Slack, GitHub issue

You don't need all five on day one. Start with UptimeRobot on your health endpoint and healthchecks.io on your scheduler cron. Add the rest as the site grows.

How do you set up monitoring step by step?

Work outside-in: uptime first, then errors, then server metrics. Each layer catches problems the others miss. The whole setup takes under an hour and most of it is free.

  1. Add an uptime check. Create a UptimeRobot monitor pointed at https://yourdomain.com/api/v1/health, set it to check every 5 minutes, and add your email plus a Slack or Telegram webhook as alert contacts.
  2. Watch the scheduler. UnfoldCMS runs Laravel's scheduler from a single cron entry. Wrap it with a healthchecks.io ping so you know if the cron stops firing: * * * * * php artisan schedule:run && curl -fsS https://hc-ping.com/your-uuid > /dev/null.
  3. Wire up error tracking. Sentry isn't pre-wired in UnfoldCMS, but adding it is a five-minute job — install sentry/sentry-laravel, run the install command, and paste your DSN into .env. Now every uncaught exception lands in Sentry with a stack trace.
  4. Add server metrics. Install Netdata (wget -O /tmp/netdata-kickstart.sh https://get.netdata.cloud/kickstart.sh && sh /tmp/netdata-kickstart.sh) for a live dashboard of CPU, RAM, disk, and network — with built-in alerts.
  5. Enable the MySQL slow query log. Set slow_query_log = 1 and long_query_time = 1 in your MySQL config so any query over one second gets logged for review.
  6. Set a disk alarm. A full disk is the number-one silent killer. Add a cron that emails you when disk use crosses 80% (a one-line df + awk check, shown below).

How do you monitor without paying for tools?

You can cover the basics with cron, curl, and a shell script — no third-party service required. A cron job hits your health endpoint every few minutes and emails you (or posts to a Slack webhook) when the response isn't 200. It's not as polished as UptimeRobot, but it runs entirely on your box and costs nothing.

Here's a minimal DIY uptime + disk check you can drop into a cron:

#!/bin/bash
# /usr/local/bin/site-check.sh
URL="https://yourdomain.com/api/v1/health"
SLACK="https://hooks.slack.com/services/XXX/YYY/ZZZ"

# Uptime check
code=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$code" != "200" ]; then
  curl -s -X POST "$SLACK" -d "{\"text\":\"🔴 Site down: HTTP $code\"}"
fi

# Disk check (alert over 80%)
use=$(df / | awk 'NR==2 {gsub("%",""); print $5}')
if [ "$use" -gt 80 ]; then
  curl -s -X POST "$SLACK" -d "{\"text\":\"⚠️ Disk at ${use}%\"}"
fi

Run it every five minutes with */5 * * * * /usr/local/bin/site-check.sh. The catch with DIY: if the whole server dies, the cron dies too and you get no alert. That's exactly why an external uptime service matters — it watches from outside your box. Use the DIY script for disk and internal checks; keep at least one external monitor for true "is it up" coverage.

How do you monitor logs and errors?

Laravel writes everything to storage/logs. UnfoldCMS uses daily rotation (LOG_STACK=daily), so you get one file per day like laravel-2026-07-03.log and old files age out. For live watching, tail -f storage/logs/laravel-*.log shows errors as they happen. For alerts, either grep the logs on a cron or push exceptions to Sentry.

The difference between logs and error tracking matters. Logs are a record you read after the fact — good for debugging, bad for waking you up. Error tracking (Sentry, Bugsnag) is proactive: it groups identical exceptions, counts how often each fires, and messages you the moment a new error appears in production. UnfoldCMS doesn't pre-wire either tool, so pick based on scale. A low-traffic site can live on log tailing plus a weekly grep. A site with real users should add Sentry — its free tier handles 5,000 errors a month, which is plenty for most small deployments.

One log worth its own attention: the MySQL slow query log. When a page feels sluggish, this tells you which query is the culprit. Enable it, let it run for a day, then read the slowest entries with mysqldumpslow. A missing index usually explains 90% of what shows up.

How do you get alerts where you'll actually see them?

Route alerts to a channel you check constantly — for most solo developers that's Slack, Telegram, or Discord, not email. Email alerts get buried. A dedicated #alerts channel or a Telegram bot puts the ping on your phone within seconds. Every tool above supports webhooks, so you can send all of them to one place.

The rule that saves your sanity: alert only on things you'd act on right now. A site-down alert deserves a phone buzz. A "disk at 82%" warning can go to a quieter channel you check daily. If every metric pages you, you'll mute the channel within a week and miss the real outage. Set two tiers — urgent (site down, DB unreachable, disk over 90%) and informational (slow queries, disk over 80%, a cron that ran a bit late) — and route them separately. Better Stack and PagerDuty support escalation (Slack first, then SMS, then a call) if a critical alert goes unacknowledged.

Actionable checklist: your first hour

Do these in order and you'll have working monitoring before lunch:

  • Point UptimeRobot at /api/v1/health, 5-minute interval, alert to Slack.
  • Add a healthchecks.io ping to your scheduler cron line.
  • Drop the DIY disk + uptime script into */5 cron as a backup.
  • Enable the MySQL slow query log (long_query_time = 1).
  • Install sentry/sentry-laravel and paste your DSN — or defer this if traffic is low.
  • Create a #alerts Slack channel and route everything there.
  • Test it: stop MySQL for 60 seconds and confirm the alert fires.

That last step is the one people skip and regret. An untested alert is a false sense of safety. Break something on purpose and watch the notification land.

Frequently asked questions

Does UnfoldCMS include a monitoring dashboard? No. UnfoldCMS is a self-hosted Laravel CMS — it gives you a /api/v1/health endpoint and standard Laravel logs in storage/logs (daily rotation), but no built-in APM or monitoring UI. Monitoring on a self-hosted box is your responsibility, and this post covers the tools to bolt on.

How often should uptime checks run? Every 1-5 minutes is the sweet spot. Faster than one minute rarely helps and can trip rate limits or look like bot traffic. Five minutes is fine for a blog; one minute suits a site where minutes of downtime cost money.

Is a health endpoint safe to expose publicly? Yes, as long as it returns only a status flag and no sensitive data. UnfoldCMS's /api/v1/health reports up/down and DB connectivity — not versions, credentials, or config. Don't add secrets to a health response.

Do I need Sentry if I already tail logs? Not strictly, but it helps. Logs are reactive — you read them after something breaks. Sentry is proactive: it alerts you the moment a new exception appears and groups duplicates. For a low-traffic site, log tailing is enough. For real users, add error tracking.

What's the single most important thing to monitor? Disk space. A full disk is the most common cause of a silent self-hosted outage — logs, backups, and MySQL binlogs fill the drive and every write fails. Set an 80% alert and you'll catch it before it catches you.

Wrapping up

Monitoring a self-hosted CMS comes down to watching from outside (uptime), watching from inside (logs and errors), and watching the box itself (disk, RAM, CPU, slow queries). None of it is expensive — most of the stack above runs on free tiers or a shell script. The one rule: test your alerts before you need them.

UnfoldCMS keeps this simple by shipping a /api/v1/health endpoint and daily-rotated logs out of the box, so your uptime checker and log tools have clean targets from day one. See what else is included on the features page, and pair this with a solid backup strategy and security hardening so a caught problem is also a recoverable one.


Sources: Gartner downtime cost estimates; Laravel logging and scheduler documentation; UptimeRobot, Better Stack, healthchecks.io, Sentry, and Netdata product docs (2026). Setup commands verified against current tool documentation as of July 2026.

Free & Open Source

Own your CMS. No subscriptions.

Unfold CMS is free to download and self-host. Built on Laravel + React, full source code included.

Share this post:

Discussion

Comments (0)

Leave a Comment

Please log in to leave a comment.

Don't have an account? Register here

No comments yet. Be the first to share your thoughts!

Keep Reading

Related Posts

Back to all posts
Powered by UnfoldCMS