The Versatile ntfy
Ever executed a long terminal command *multi-stage docker build* and forgot about it? ever wished you could easily get notified after a job or task fails *pg_dumpall*?
Notification systems can be rather tedious to set up, annoying to have on different platforms or simply lack flexibility.
Let’s take an example, we have a script that looks like this:
# /usr/local/sbin/pg_backup.sh
PG_HOST=localhost
PG_USER=postgres
PG_PORT=5432
PG_DB=postgres
BACKUP_DIR="/tmp/postgres/backup"
mkdir -p "${BACKUP_DIR}"
pg_dump -U "${PG_USER}" -d "${PG_DB}" -p "${PG_PORT}" -h "${PG_HOST}" > "${BACKUP_DIR}"/backup_"${PG_DB}".dump
Create a folder for logs and give postgres the correct permissions
sudo mkdir /var/log/postgres/ -p
sudo chown postgres:postgres /var/log/postgres/
This is only for demonstration, do NOT use this for actual PostgreSQL backups!
Now let’s create a simple cronjob to schedule this script
sudo -u postgres crontab -e
I personally prefer tying such jobs to their actual users, hence why I did thesudo -u postgres
Put this into it:
0 0 * * * /usr/local/sbin/pg_backup.sh > /var/log/postgres/pg_backup.log 2>&1
It’s a good idea to timestamp your logs in the filename
For a critical task like a database backup, I prefer using a systemd timer
Now, how would we get notified if this particular job failed? And preferably attach some logs when it does.
Answer: you guessed it, ntfy
ntfy is not the only tool, but it’s one that I think deserves more attention for how simple it is
From the official website :
ntfy (pronounced notify) is a simple HTTP-based pub-sub notification service. It allows you to send notifications to your phone or desktop via scripts from any computer, and/or using a REST API. It’s infinitely flexible, and 100% free software.
This sounds rather confusing and doesn’t convey, in my opinion, just how much this little guy is hiding.
At its core ntfy is a pub-sub service; You have queues or topics or whatever you want to call them, you push notifications into them and whoever is subscribed can get notified when something happens.
However it is ABLE to connect to a topic via a websocket for
realtime notifications, customize the authentication and restrict
access to topics following a pattern (for example: topic names
starting with private_ can only be seen by the admin user),
schedule messages into the future and more.
And my favourite part is that the publishers don’t even need to
install anything, you can simply post notifications using curl or
wget or a python script and it would still work. Although you can
use the official ntfy binary which is very pleasant.
I will assume you have docker installed and configured, because we will be deploying it within docker for simplicity
- Create an
ntfydirectory / folder in your working environment, I’ll put mine into~/Projects/blog/ntfy/ - Create a
compose.ymlfile - Put this into it (which I got from the official website ):
services:
ntfy:
image: binwiederhier/ntfy
container_name: ntfy
command:
- serve
environment:
- TZ=YOUR_TIMEZONE # optional: set desired timezone
volumes: # I modified these to suit my needs, but feel free to use whatever you like
- ./cache:/var/cache/ntfy
- ./ntfy:/var/lib/ntfy
- ./server.yml:/etc/ntfy/server.yml
ports:
- 8080:80
healthcheck: # optional: remember to adapt the host:port to your environment
test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1"]
interval: 60s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
init: true # needed, if healthcheck is used. Prevents zombie processes
- Create two directories,
ntfyandcacheinto the same folder - Next, create a
server.ymlfile and put this into it:
# Server
base-url: "http://localhost:8080"
# Change this to true if you want a reverse proxy, you will have to configure it
behind-proxy: false
# Access control
auth-file: "/var/lib/ntfy/auth.db"
auth-default-access: "deny-all"
# This creates an admin user with `admin` password
auth-users:
- "admin:$2b$10$1AnX6EAXnojzz6KFJjsjaejk4/o4.SPY0o0G6aVXQDb3ZSY6FmJoW:admin"
enable-login: true
require-login: true
# We don't want new users creating accounts on our private server
enable-signup: false
# Attachments
attachment-cache-dir: "/var/cache/ntfy/attachments"
# Message cache
cache-file: "/var/cache/ntfy/cache.db"
# Email notifications (outgoing)
smtp-sender-addr: "smtp_domain_if_you_want_to_have_emails:587"
# This part can be something different if your mail server supports it
smtp-sender-from: "smtp_user_from"
smtp-sender-user: "smtp_user_from"
smtp-sender-pass: "token_or_password"
# Require verified recipient addresses for email notifications
smtp-sender-verify: true
# Message Delay
## the limit to how long you can 'schedule' your notifications into the future
message-delay-limit: 3d
- Then
docker compose up -dand you’re good!
- Open your web browser and navigate to
http://localhost:8080/ - Login with admin as username and password
- Click on
Subscribe to topicbutton on the left panel - Input
remindersinto the field and hitSubscribe - Send a curl command like this from your terminal:
curl -H "Title: Notification title" -u admin:admin http://localhost:8080/reminders -d "Notification Body here"
- You should now see a notification in your browser
We could create a topic named backups or logs or events or
whatever you like, I’ll just reuse our existing reminders topic.
Let’s change it with this
I have intentionally changed thePG_DBvariable tonon_existentso the backup fails.
# /usr/local/sbin/pg_backup.sh
PG_HOST=localhost
PG_USER=postgres
PG_PORT=5432
PG_DB=non_existent
BACKUP_DIR="/tmp/postgres/backup"
mkdir -p "${BACKUP_DIR}"
if ! pg_dump \
-U "${PG_USER}" \
-d "${PG_DB}" \
-p "${PG_PORT}" \
-h "${PG_HOST}" > "${BACKUP_DIR}"/backup_"${PG_DB}".dump 2>"${BACKUP_DIR}"/"${PG_DB}".log; then
curl -X PUT \
-u admin:admin \
-H "Title: PostgreSQL Backup Failed" \
-H "Message: Backup for ${PG_DB} failed. See log file for more info" \
-H "Filename: ${PG_DB}.log" \
-T "${BACKUP_DIR}/${PG_DB}.log" localhost:8080/reminders
fi
Here I intentionally used a different way of publishing a notification so you can see that you do have flexibility in doing things
Having your credentials exposed like this can be dangerous, you can read in theofficial documentation about how to use tokens and configure your client.
This will try to backup a non existant database non_existent which
will result in a failure and a notification. Check your browser and
you’ll see the log file attached and you can simply download it and
view it.
As I kept saying, ntfy is very flexible and very permissive in the way you use it.
Here I will lay down some personal ways where I use ntfy, this is simply to give ideas and is not meant as a guide
- Sharing files between my laptop and phone quickly, the phone app is pretty good.
- I used it for a personal multiplayer game where I create a topic when a lobby is created, you share topic name with your friends and the info is there to join, not efficient or safe but fun.
- Receiving alerts like I just showed you when something in my VPS goes down.
- Reminding myself to do tasks in the future
- Creating reminders from my personal caldav calendar using a custom python package called caldav2ntfy .
ntfy is basically very versatile and that’s what I love about it, it doesn’t restrict you, it gives you topics and an ACL and you just do whatever you like with it.
I highly recommend you check out the official documentation which explains more about the features and how to configure ACLs which I did not get into in this post.