Cron Job Failure Alert to Telegram (cron and systemd)

Cron Job Failure Alert to Telegram (cron and systemd)

push.tg

The worst cron failure is the silent one: the backup that's been failing for three weeks. Here's how to get a Telegram message the moment a cron job or systemd unit fails, with the last lines of output attached. Checked against crontab(5) and the systemd.unit manual (October 2026).

Step 1: get your endpoint (30 seconds)

Open @trafficRobot in Telegram and press Start. You get an address like k3x9q@push.tg. Your endpoint is the part before the @: https://push.tg/k3x9q. Every example below uses k3x9q, so swap in your own key.

There's no bot to create, no chat_id to look up and no token to keep safe. Add @trafficRobot to a group and the group gets its own address, so the whole team sees the alerts.

Fastest: one line in crontab

0 3 * * * /usr/local/bin/backup.sh || echo "❌ backup failed on $(hostname)" | curl -s -m 10 --data-binary @- https://push.tg/k3x9q >/dev/null

|| runs the alert only when the job exits non-zero. One crontab gotcha: % means "newline" in a crontab command, so escape it as \% or move the logic into a script.

Better: a wrapper that sends the error output

Save as /usr/local/bin/alert-on-fail and chmod +x it:

#!/bin/sh
# run a command; if it fails, send the last 20 lines of output to Telegram
out=$("$@" 2>&1); rc=$?
if [ $rc -ne 0 ]; then
  { echo "❌ $* failed on $(hostname) (exit $rc)"; echo; echo "$out" | tail -n 20; } \
    | curl -s -m 10 --data-binary @- https://push.tg/k3x9q >/dev/null
fi
exit $rc

Then in crontab:

0 3 * * * /usr/local/bin/alert-on-fail /usr/local/bin/backup.sh

systemd: OnFailure for any unit

Create /etc/systemd/system/notify-telegram@.service:

[Unit]
Description=Telegram alert for %i

[Service]
Type=oneshot
ExecStart=/bin/sh -c '{ echo "❌ %i failed on %H"; systemctl status --no-pager -n 20 %i; } | curl -s -m 10 --data-binary @- https://push.tg/k3x9q'

Then add one line to the [Unit] section of any service or timer-driven service you want to watch (systemctl edit backup.service works well):

[Unit]
OnFailure=notify-telegram@%N.service

%N is the unit name without its suffix, %i is the instance name and %H is the hostname. systemd starts the alert unit whenever the watched unit enters the failed state.

Also catch "didn't run at all"

A failure alert can't fire if the job never starts. Pair this with a dead-man's switch such as Healthchecks.io (see the Healthchecks page in the list below).

Check that the message really arrived. push.tg answers HTTP 200 even when the key is wrong. The body says {"error":"no such user"} instead of {"ok":...}. So a green "test sent" in your tool doesn't prove delivery. Look at Telegram.

More copy-paste guides

Get your endpoint: t.me/trafficRobot?start=tg-cron. It takes 30 seconds, it has no ads, and it has been running since 2016.

Report Page