My website went down recently for some random reason, and it took me some time before I realized it. So I decided to put an outage detection system in place.

There are many cloud-based and self-hosted outage detection services such as UptimeRobot and Uptime Kuma, but I thought I could mostly get away with a simple cron job that would run a one-liner to curl my website periodically and send notifications based on the HTTP response code.

Dealing with notifications was a bit trickier. Services like Pushover, ntfy, and gotify offer varying degrees of privacy, but I really didn’t want to rely on internet services for push notifications, and I’d prefer to avoid self-hosting a service just for push notifications if possible. Obviously, there’s no sensitive data involved in this outage detection, but it’s a matter of principle, and I was looking for a solution I could use later with other projects.

After some searching, I realized I could use my private self-hosted Home Assistant instance to send push notifications to its phone apps.

For this, we’d need the Home Assistant REST API, which is not enabled by default. You first have to enable the API integration by adding the empty block below to your configuration.yaml file and generate a token from your account profile.

api:

You can then use the /api/services/notify endpoint to send notifications to your Home Assistant phone apps.

Putting everything together, I ended up with the script below as a cron job:

#!/usr/bin/env bash

HA_TOKEN="YOUR ACCESS TOKEN"

http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 10 https://mil.ad)

if [ "$http_code" -ne 200 ]; then
  curl \
    -H "Authorization: Bearer $HA_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"title": "🚨", "message": "mil.ad is down!"}' \
    https://home.mil.ad/api/services/notify/notify
fi

The https://home.mil.ad URL above might suggest that my Home Assistant instance is open to the internet, but it is not. That subdomain is a public CNAME record that resolves to the Tailscale domain of the server where I host Home Assistant. Unless I’m connected to my Tailnet, that domain is useless. (Tailscale has a nice YouTube video on how to set this up).

Sending critical notifications

If you’re using Home Assistant for truly sensitive notifications, e.g., a gas leak, you probably do not want to miss them. Both Android and iOS provide ways to mark notifications as “critical” to bypass the usual limitations. On iOS, for example, critical notifications always appear above all other notifications and play a sound even if “Do Not Disturb” is enabled. Home Assistant has good documentation on how to set them up, but in the above case for iOS, all I have to do is change the request data to:

{
  "title": "🚨",
  "message": "mil.ad is down!",
  "data": {
    "push": {
        "interruption-level": "critical"
    }
  }
}