Self-hosted notifications


Self-hosted notifications

Running any kind of personal infrastructure sometimes requires your attention based on certain events or failure states, no matter how much you automate tasks.

Over the years I have used E-Mail, Telegram bots and a variety of other tools for this purpose. However all of them have the drawback that they mix with other kinds of information and are not easilly usable in scripts.

My requirements

I took some time to list actual requirements that would be good to have for such a notification tool:

  • Produce notifications from any common shell and programming language
  • Easilly be notified on all my client devices; MacBook, iPhone, possibly Android
  • Web-UI to show notifications while not at my personal devices
  • Self-hosted with simple but durable persistence
  • Multiple notification channels
  • Protected by authentication

And some nice to haves:

  • Consume notifications from scripts and other programs, as a kind of poor mans event bus
  • Attach complex data like json-blobs or images to the notifications

ntfy.sh

I found this tool while browsing r/selfhosted and liked it almost instantly.

The setup was well documented, it is extremely easy to run besides my existing infrastructure and it fullfills all my requirements and even the nice to haves.

Setup

Besides their setup documentation being excellent here is what I did.

  • Added ntfy to my docker-compose

    services:
      # This is the reverse proxy used to publish ntfy later on
      traefik:
        image: traefik:v2.9
        # ...
        networks:
          - traefik
    
      # This is the actual ntfy service
      ntfy:
        image: binwiederhier/ntfy
        command:
          - serve
        environment:
          - TZ=UTC
        volumes:
          - ./ntfy/cache:/var/cache/ntfy
          - ./ntfy/config:/etc/ntfy
        networks:
          - traefik
        restart: "always"
    
  • Added traefik config

    http:
      routers:
        https-redirect:
          entryPoints:
            - http
          middlewares:
            - https-redirect
          rule: "(Host(`existing-host.example.org`) || Host(`<NOTIFY-HOSTNAME>`)"
          service: no-op
        ntfy:
          entryPoints:
            - https
          service: ntfy
          middlewares:
            - notify-auth
          rule: Host(`<NOTIFY-HOSTNAME>`)
          tls:
            certResolver: alpn
    
      services:
        ntfy:
          loadBalancer:
            servers:
              - url: http://ntfy/
            passHostHeader: false
    
      middlewares:
        https-redirect:
          redirectScheme:
            scheme: https
            permanent: true
        notify-auth:
          basicAuth:
            users:
              - "some user"
              - "another user"
    
  • Added ntfy config

    # General configuration
    base-url: "https://<NOTIFY-HOSTNAME>"
    behind-proxy: true
    
    # This is required for iOS instant notifications
    # See https://ntfy.sh/docs/config/#ios-instant-notifications
    upstream-base-url: "https://ntfy.sh"
    

Integration

ntfy comes with a CLI that works great and that I use on my client machines now, however in some situations I wanted to keep my current requirements, which already include curl.

So I wrote a small wrapper script to publish notifications that works with the pipe and dynamic channels.

#!/bin/bash
# Send a notification through ntfy using channel and message as specified
# Example usage:
# long-running && notify.sh
# long-running && notify.sh ping "specific message"
# long-running-with-output | notify.sh output-channel

# Channel
CHANNEL=$1
if [ -z "$CHANNEL" ]
then
    CHANNEL="ping"
fi

# Message, first from stdin, otherwise check parameter, otherwise default hardcoded
MESSAGE=$2

if [ ! -t 0 ]
then
    MESSAGE=$(</dev/stdin)
fi

if [ -z "$MESSAGE" ]
then
    MESSAGE="notify.sh got called on $HOST"
fi

curl -d "$MESSAGE" "https://user:pass@<NOTIFY-HOSTNAME>/$CHANNEL" &> /dev/null

Experience so far

So far my experience with ntfy is completly positive, it does exactly what it has to and with the wrapper scripts I’ve created I could easilly integrate it as a replacement for mails and other notification systems.

Possible business usecases

Having now used ntfy in my personal infrastructure I think it may even have value in a business environment for small teams.

For example:

  • Monitoring notifications, think affordable Pagerduty
  • Notifications for long running tasks, usually done by email or a custom solution
  • Notifications about events in a SaaS like new subscriptions for the business people

It does not have the same polish as specialised tools for those usecases, but it could server as a great MVP to explore notification-style features before committing time and money on them.

See also