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.