A monitor that lives on your server cannot tell you that your server is down.
Everything else in this guide is useful. That sentence is the reason you still need one check you do not host, and it is better to say it in the first paragraph than to bury it under a feature list.
So run your own checks for the ninety-five per cent — the app that returns a 500 at 03:14, the certificate nobody renewed, the page that renders but shows an empty product list — and let one free external checker watch the log server itself.
The payoff for hosting the rest: when a check fails, the logs from that minute are already on the same disk, in the same tool, one query away.
Central Logging wakes every minute and runs whichever monitors are due. Each monitor has its own interval: 1, 2, 5 or 10 minutes.
Each check is a plain GET. It records:
Checks time out after 5 seconds. That is fixed. A page that takes 6 seconds to render is recorded as a failure, which is usually the answer you want anyway.
History is kept for 30 days.
Go to Website Monitors and add a monitor. The new-monitor form asks for two things: a name and a URL.
Everything else lives on the monitor’s edit page — check frequency, keyword, and whether the keyword matters by its presence or its absence. Open it straight after creating the monitor, because the defaults are “every minute” and “no keyword”, and the keyword is the part that earns its keep.
Point a monitor at a URL that returns 500 Internal Server Error and nothing happens. No alert. The check succeeds, records the 500, and moves on.
That is worth reading twice, because it is the opposite of what most people assume. Central Logging alerts on three things:
A 500 is an answer. So is a 404, and so is a login page served to a logged-in user.
Pick a string that appears on a healthy page and appears nowhere on a broken one, then alert on its absence:
URL: https://app.example.com/
Keyword: Sign in
Alert When: Alert when keyword does not exist
The match runs against the raw response body and is case-insensitive unless you turn on the case-sensitive toggle. HTML markup works, which is what makes it precise:
Keyword: <span id="db-status">ok</span>
Alert When: Alert when keyword does not exist
Choose the string carefully. A word in your nav bar tells you the web server is up. A string that only renders when the database answered tells you the application is up. The second one is the monitor worth having.
Two things to avoid:
Your log server going down takes its own monitoring with it. There are two honest answers.
A free external checker. One monitor, pointed at your Central Logging instance. Every hosted checker has a free tier that covers a single check comfortably. That one external check plus your own monitors covers more than most small teams have today.
A second box you already own. If you run a VPS somewhere else, give it a cron job that curls your log server and pings a cron monitor — hosted anywhere but on the box being watched.
Do not skip this step and tell yourself the monitors have it covered. They do not.
The TLS check reads the certificate on every HTTPS request it makes anyway, so it costs nothing. An alert goes out when a certificate expires within seven days, throttled to once a day.
Seven days is plenty for anything renewing automatically, and it is a useful backstop when a Let’s Encrypt renewal has been quietly failing for a month. It is tight for a certificate you buy and install by hand. If that is your situation, add a monitor for the same host and treat the first warning as a deadline, not a heads-up.
The certificate expiry is shown on the monitors list, so you can see the whole estate without waiting to be told.
This is the part a hosted checker cannot do for you.
The alert tells you the time. The logs from that minute are on the same server:
SELECT timestamp, msg FROM logs
WHERE timestamp BETWEEN CAST(strftime('%s', '2026-08-10 03:04:00') AS INTEGER)
AND CAST(strftime('%s', '2026-08-10 03:24:00') AS INTEGER)
ORDER BY timestamp
Ten minutes either side of the alert. Read what the application was saying while the check was failing.
If the source ships JSON, narrow it to the errors and guard the extract, because one plain-text line in the source makes json_extract fail the whole query:
SELECT timestamp, json_extract(msg, '$.message') AS message
FROM logs
WHERE timestamp > CAST(strftime('%s', 'now', '-1 hour') AS INTEGER)
AND json_valid(msg)
AND json_extract(msg, '$.level') = 'error'
ORDER BY timestamp DESC
More on that in querying logs with SQL.
Monitor alerts use the same notification channel as everything else. Tick Send alerts to this channel on the one you want, and check the Alerts page — the channel that receives alerts is labelled there.
GET only. No POST, no custom headers, no authentication. Public endpoints and health checks, not APIs behind a token.If external verification is the whole point of the exercise, use a hosted checker — see the Uptime Robot alternative and Better Stack alternative pages for that comparison in full.
Add the monitor with a URL, then go straight to the edit page and add a keyword. Without one you are only watching for a server that stopped answering, and the failures that cost you money answer with a 500.
Give one check to someone else: the one that watches your log server.
Then, when a monitor fires, stay in the same tool. The logs from the minute it broke are already there.
💌 Get notified on new features and updates