Skip to content

Notifications for the system administrator

The server should tell you itself when something goes wrong. You don’t need to log into the machine every five minutes and check df -h, journalctl or the backup status — let the server just call when a threshold is reached.

All recipes on these pages work on a plain Linux without additional monitoring agents. bash, curl and cron/systemd are enough. For Windows servers similar scenarios are implemented via PowerShell + Task Scheduler — see the Windows: PowerShell + Task Scheduler sections in each recipe.

  1. Active monitors — Notifly itself checks a site, port or SSL certificate and tells you when something stops responding. No code and no server access: the monitor is created in the admin panel, the target must be reachable from the internet.
  2. Heartbeat for cron and backups — an alert when a scheduled job did not report in time. Add && curl … to the crontab line.
  3. Low disk space — your first “own” script: copy the ready-made bash script and the notifly-send wrapper, add a line to cron. Requires root on the server.
  4. Escalation chain — so that an unread alert reaches you by SMS, a phone call or in your team chat. Set up in the admin panel, no code.

Already running Prometheus, Grafana or Zabbix? Connect them directly: Prometheus and Grafana alerts, Zabbix → Notifly. No programming, just configuration.

ScenarioWhen you get a notification
Disk space running outFree space less than N %
systemd service downAny important service has gone to failed
Suspicious SSH loginsSuccessful or failed SSH login
Fail2ban triggersIP ban or unban
Backup completionBackup completed successfully or failed
SSL certificate expiryExpires in < N days
High load / OOMCPU/RAM load above threshold
Failed cron jobsCron-job exited with an error
Server rebootThe server rebooted, especially unexpectedly
RAID array degradationA disk dropped out, rebuild in progress
Growing swap usageMemory is running out, the system swaps
Unhealthy Docker containersA container is unhealthy or in a restart loop
5xx spike in nginxRise of 5xx errors in nginx logs
PostgreSQL replication lagA replica lags beyond the threshold
Power outage / UPSPower lost, the UPS is on battery
Security updatesSecurity package updates are available
Domain registration expiryDomain registration expires in < N days
Sudo / root auditA new sudo session or root login

Recipes where Notifly itself does the work instead of your script:

ScenarioWhat you get
Heartbeat / dead-man-switchAn alert when a cron job or backup stops reporting
Active monitors (HTTP/TCP/SSL)Notifly itself checks a site, a port or a certificate
Prometheus and Grafana alertsAlertmanager receiver → push with priority by severity
Zabbix → Notifly”Webhook” media type → push by trigger severity
Escalation chainNot read — SMS, call, Discord, Teams, PagerDuty
Planned work without false alertsMaintenance windows: checks keep running but wake no one

Basic principle: silence is not “everything is fine”, silence is “I don’t know”. Individual “success” notifications (green) are also needed to make sure the system is alive and the check itself works. For example, a daily backup should send “OK” — if it’s missing, something in the check itself is broken.

Everywhere in this section the same send wrapper is used. Save it once to /usr/local/bin/notifly-send:

#!/usr/bin/env bash
# Usage:
# notifly-send "Title" "Message text" [priority]
set -eu
: "${NOTIFLY_URL:?NOTIFLY_URL not set}"
: "${NOTIFLY_TOKEN:?NOTIFLY_TOKEN not set}"
TITLE="${1:?title required}"
MESSAGE="${2:?message required}"
PRIORITY="${3:-5}"
curl -s --max-time 10 \
"$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$TITLE" --arg m "$MESSAGE" --argjson p "$PRIORITY" \
'{title:$t, message:$m, priority:$p}')" >/dev/null

Make the file executable and put the tokens in /etc/notifly.env:

Окно терминала
sudo chmod +x /usr/local/bin/notifly-send
sudo tee /etc/notifly.env >/dev/null <<'EOF'
NOTIFLY_URL=https://api.notifly.ru
NOTIFLY_TOKEN=AGdjfk_L.dKe8q
EOF
sudo chmod 600 /etc/notifly.env

Then in all scripts it’s enough to source the variables:

Окно терминала
set -a; source /etc/notifly.env; set +a
notifly-send "Test" "Hello from $(hostname)"

For Windows servers use the PowerShell function Send-Notifly. Save it to the profile C:\Program Files\WindowsPowerShell\Modules\Notifly\Notifly.psm1 (or just dot-source via . C:\scripts\Notifly.ps1 at the start of each script):

C:\scripts\Notifly.ps1
$NotiflyConfigPath = "C:\ProgramData\Notifly\notifly.json"
function Send-Notifly {
param(
[Parameter(Mandatory)] [string] $Title,
[string] $Message = "",
[int] $Priority = 5
)
$cfg = Get-Content $NotiflyConfigPath -Raw | ConvertFrom-Json
$body = @{ title = $Title; message = $Message; priority = $Priority } | ConvertTo-Json -Compress
try {
Invoke-RestMethod -Method Post `
-Uri "$($cfg.url)/message?token=$($cfg.token)" `
-ContentType "application/json; charset=utf-8" `
-Body ([System.Text.Encoding]::UTF8.GetBytes($body)) `
-TimeoutSec 10 | Out-Null
} catch {
Write-EventLog -LogName Application -Source "Notifly" -EntryType Warning `
-EventId 1000 -Message "Send-Notifly failed: $_" -ErrorAction SilentlyContinue
}
}

Create the config (once, as administrator):

Окно терминала
New-Item -ItemType Directory -Path "C:\ProgramData\Notifly" -Force | Out-Null
@{
url = "https://api.notifly.ru"
token = "AGdjfk_L.dKe8q"
} | ConvertTo-Json | Set-Content "C:\ProgramData\Notifly\notifly.json"
# Restrict reading to administrators and SYSTEM
icacls "C:\ProgramData\Notifly\notifly.json" /inheritance:r /grant:r "SYSTEM:R" "Administrators:R"

Test:

Окно терминала
. C:\scripts\Notifly.ps1
Send-Notifly -Title "Test" -Message "Hello from $env:COMPUTERNAME" -Priority 5

All Windows examples in this section dot-source Notifly.ps1 and call Send-Notifly.