Ntfy notifications

Ntfy.sh is a website that offers a notification service. The fun part of this is that they also give you the possibility to self host your own ntfy server. So I’ve spun one up in Docker:

version: "2.3"

services:
  ntfy:
    image: binwiederhier/ntfy
    container_name: ntfy
    command:
      - serve
    environment:
      TZ: Europe/Amsterdam
      NTFY_BASE_URL: https://ntfy.example.com
      NTFY_CACHE_FILE: /etc/ntfy/cache.db
      NTFY_AUTH_FILE: /etc/ntfy/auth.db
      NTFY_AUTH_DEFAULT_ACCESS: deny-all
      NTFY_BEHIND_PROXY: true
      NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
      NTFY_ENABLE_LOGIN: true
    volumes:
      - /storage/ntfy/cache:/var/cache/ntfy
      - /storage/ntfy/config:/etc/ntfy
    networks:
      LocalNet:
        ipv4_address: '172.17.17.47'
    restart: unless-stopped
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
      - "traefik.enable=true"
      - "traefik.http.routers.ntfy.rule=Host(`ntfy.example.com`)"
      - "traefik.http.routers.ntfy.entrypoints=https"
      - "traefik.http.routers.ntfy.tls.certresolver=vm"
      - "traefik.http.services.ntfy.loadbalancer.server.port=80" 
      - "traefikpub.http.routers.ntfy.rule=Host(`ntfy.example.com`)"
      - "traefikpub.http.routers.ntfy.entrypoints=https"
      - "traefikpub.http.routers.ntfy.tls.certresolver=vm"
      - "traefikpub.http.services.ntfy.loadbalancer.server.port=80" 

networks:
  LocalNet:
    external: true

Similar to my other docker containers:

  • I use IPvlan layer2, which make the container directly reachable in the same subnet as my docker host
  • I don’t use volumes but have it /storage/XXX hardcoded in my docker-compose file. If you prefer to do it differently. Be my guest 😉
  • I use traefik as a reverse proxy to manage my SSL certificates and access to the application. That’s why I have 2. One is for internal use and one is for external/public use.

After the stack is running in portainer, you will have a ntfy server that enables everybody to send their notifications to and to subscribe to notifications. Personally I prefer to close it down, so I can also use notifications that are only ment for a limited number of people.

Limiting access

In order to limit the access to your ntfy server you will have to log into your container:

 $docker exec -it ntfy /bin/sh

Then you are able to use the CLI interface of ntfy to create an admin account for you:

ntfy access --help
NAME:
   ntfy access - Grant/revoke access to a topic, or show access

USAGE:
   ntfy access [USERNAME [TOPIC [PERMISSION]]]

CATEGORY:
   Server commands

DESCRIPTION:
   Manage the access control list for the ntfy server.

   This is a server-only command. It directly manages the user.db as defined in the server config
   file server.yml. The command only works if 'auth-file' is properly defined. Please also refer
   to the related command 'ntfy user'.

   The command allows you to show the access control list, as well as change it, depending on how
   it is called.

   Usage:
     ntfy access                            # Shows access control list (alias: 'ntfy user list')
     ntfy access USERNAME                   # Shows access control entries for USERNAME
     ntfy access USERNAME TOPIC PERMISSION  # Allow/deny access for USERNAME to TOPIC

   Arguments:
     USERNAME     an existing user, as created with 'ntfy user add', or "everyone"/"*"
                  to define access rules for anonymous/unauthenticated clients
     TOPIC        name of a topic with optional wildcards, e.g. "mytopic*"
     PERMISSION   one of the following:
                  - read-write (alias: rw)
                  - read-only (aliases: read, ro)
                  - write-only (aliases: write, wo)
                  - deny (alias: none)

   Examples:
     ntfy access                        # Shows access control list (alias: 'ntfy user list')
     ntfy access phil                   # Shows access for user phil
     ntfy access phil mytopic rw        # Allow read-write access to mytopic for user phil
     ntfy access everyone mytopic rw    # Allow anonymous read-write access to mytopic
     ntfy access everyone "up*" write   # Allow anonymous write-only access to topics "up..."
     ntfy access --reset                # Reset entire access control list
     ntfy access --reset phil           # Reset all access for user phil
     ntfy access --reset phil mytopic   # Reset access for user phil and topic mytopic


OPTIONS:
   --debug, -d                                                                                                            enable debug logging (default: false) [$NTFY_DEBUG]
   --trace                                                                                                                enable tracing (very verbose, be careful) (default: false) [$NTFY_TRACE]
   --no-log-dates, --no_log_dates                                                                                         disable the date/time prefix (default: false) [$NTFY_NO_LOG_DATES]
   --log-level value, --log_level value                                                                                   set log level (default: "INFO") [$NTFY_LOG_LEVEL]
   --log-level-overrides value, --log_level_overrides value [ --log-level-overrides value, --log_level_overrides value ]  set log level overrides [$NTFY_LOG_LEVEL_OVERRIDES]
   --log-format value, --log_format value                                                                                 set log format (default: "text") [$NTFY_LOG_FORMAT]
   --log-file value, --log_file value                                                                                     set log file, default is STDOUT [$NTFY_LOG_FILE]
   --config value, -c value                                                                                               config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE]
   --auth-file value, --auth_file value, -H value                                                                         auth database file used for access control [$NTFY_AUTH_FILE]
   --auth-default-access value, --auth_default_access value, -p value                                                     default permissions if no matching entries in the auth database are found (default: "read-write") [$NTFY_AUTH_DEFAULT_ACCESS]
   --reset, -r                                                                                                            reset access for user (and topic) (default: false)
   --help, -h                                                                                                             show help

Push messages to IOS

IOS has a limitation regarding to push messages. Rougly said only the website linked to the IOS app is allowed to send push messages. Push messages from other sites are ignored and you can only see them if you do a refresh. Since I’m self hosting ntfy the messages will not come directly from ntfy.sh.

Luckily they build a workaround for this issue, without compromising on the privacy of the messages. You will have to use ntfy.sh, but only to send a push message to your IOS device with the messageID of your notification. Your phone will then connect to your server to retrieve the message, with the credentials stored in your IOS device. In order to realize this, you will need an account on ntfy.sh and you will have to create an API key.

As you can see in my stack configuration I’ve mapped /etc/ntfy to persistant storage. In my case /storage/ntfy/config. Once you started your stack a server.yml will be placed in this directory. You will need to edit this file and add the following lines. It is also mentioned in the yml file.

upstream-base-url: "https://ntfy.sh"
upstream-access-token: <API-KEY>

Once that is done you should automaticly get push messages on your IOS devices.