From c1ff20f5be4fc0928ab027ec60e97e5b12aa5cd9 Mon Sep 17 00:00:00 2001
From: nimbleghost <132819643+nimbleghost@users.noreply.github.com>
Date: Mon, 29 May 2023 22:25:01 +0200
Subject: [PATCH] Run prettier on all the things
---
.github/ISSUE_TEMPLATE/1_bug_report.md | 15 +-
.../ISSUE_TEMPLATE/2_enhancement_request.md | 10 +-
.github/ISSUE_TEMPLATE/3_tech_support.md | 12 +-
.github/ISSUE_TEMPLATE/4_question.md | 8 +-
.github/workflows/build.yaml | 26 +-
.github/workflows/docs.yaml | 15 +-
.github/workflows/release.yaml | 31 +-
.github/workflows/test.yaml | 35 +-
.gitpod.yml | 2 +-
.goreleaser.yml | 47 +-
CODE_OF_CONDUCT.md | 23 +-
README.md | 77 +-
docker-compose.yml | 3 +-
docs/_overrides/main.html | 103 +-
docs/config.md | 628 +++++----
docs/deprecations.md | 23 +-
docs/develop.md | 222 ++--
docs/examples.md | 435 +++----
docs/faq.md | 38 +-
docs/index.md | 34 +-
docs/install.md | 155 ++-
docs/integrations.md | 55 +-
docs/known-issues.md | 13 +-
docs/privacy.md | 2 +-
docs/publish.md | 1150 ++++++++++-------
docs/releases.md | 927 ++++++-------
docs/static/css/extra.css | 211 +--
docs/static/js/extra.js | 136 +-
docs/subscribe/api.md | 192 +--
docs/subscribe/cli.md | 133 +-
docs/subscribe/phone.md | 104 +-
docs/subscribe/web.md | 3 +-
docs/troubleshooting.md | 23 +-
examples/grafana-dashboard/ntfy-grafana.json | 34 +-
.../web-example-eventsource/example-sse.html | 86 +-
mkdocs.yml | 50 +-
tools/fbsend/README.md | 1 +
37 files changed, 2831 insertions(+), 2231 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.md b/.github/ISSUE_TEMPLATE/1_bug_report.md
index 90ff2b27..cbfe1ff5 100644
--- a/.github/ISSUE_TEMPLATE/1_bug_report.md
+++ b/.github/ISSUE_TEMPLATE/1_bug_report.md
@@ -1,26 +1,29 @@
---
name: 🐛 Bug Report
about: Report any errors and problems
-title: ''
-labels: '🪲 bug'
-assignees: ''
-
+title: ""
+labels: "🪲 bug"
+assignees: ""
---
:lady_beetle: **Describe the bug**
+
:computer: **Components impacted**
+
:bulb: **Screenshots and/or logs**
-
:crystal_ball: **Additional context**
+
diff --git a/.github/ISSUE_TEMPLATE/2_enhancement_request.md b/.github/ISSUE_TEMPLATE/2_enhancement_request.md
index 790ded12..c119f22f 100644
--- a/.github/ISSUE_TEMPLATE/2_enhancement_request.md
+++ b/.github/ISSUE_TEMPLATE/2_enhancement_request.md
@@ -1,10 +1,9 @@
---
name: 💡 Feature/Enhancement Request
about: Got a great idea? Let us know!
-title: ''
-labels: 'enhancement'
-assignees: ''
-
+title: ""
+labels: "enhancement"
+assignees: ""
---
:bulb: **Idea**
+
:computer: **Target components**
+
-
diff --git a/.github/ISSUE_TEMPLATE/3_tech_support.md b/.github/ISSUE_TEMPLATE/3_tech_support.md
index 82afe7a2..fbbbd292 100644
--- a/.github/ISSUE_TEMPLATE/3_tech_support.md
+++ b/.github/ISSUE_TEMPLATE/3_tech_support.md
@@ -1,18 +1,16 @@
---
name: 🆘 I need help with ...
about: Installing ntfy, configuring the app, etc.
-title: ''
-labels: 'tech-support'
-assignees: ''
-
+title: ""
+labels: "tech-support"
+assignees: ""
---
-
:question: **Question**
+
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 0076c0fa..40be1e53 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -4,27 +4,21 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- -
- name: Checkout code
+ - name: Checkout code
uses: actions/checkout@v3
- -
- name: Install Go
+ - name: Install Go
uses: actions/setup-go@v4
with:
- go-version: '1.19.x'
- -
- name: Install node
+ go-version: "1.19.x"
+ - name: Install node
uses: actions/setup-node@v3
with:
- node-version: '18'
- cache: 'npm'
- cache-dependency-path: './web/package-lock.json'
- -
- name: Install dependencies
+ node-version: "18"
+ cache: "npm"
+ cache-dependency-path: "./web/package-lock.json"
+ - name: Install dependencies
run: make build-deps-ubuntu
- -
- name: Build all the things
+ - name: Build all the things
run: make build
- -
- name: Print build results and checksums
+ - name: Print build results and checksums
run: make cli-build-results
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 6991dea6..64951fdf 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -7,11 +7,9 @@ jobs:
publish-docs:
runs-on: ubuntu-latest
steps:
- -
- name: Checkout ntfy code
+ - name: Checkout ntfy code
uses: actions/checkout@v3
- -
- name: Checkout docs pages code
+ - name: Checkout docs pages code
uses: actions/checkout@v3
with:
repository: binwiederhier/ntfy-docs.github.io
@@ -19,14 +17,11 @@ jobs:
token: ${{secrets.NTFY_DOCS_PUSH_TOKEN}}
# Expires after 1 year, re-generate via
# User -> Settings -> Developer options -> Personal Access Tokens -> Fine Grained Token
- -
- name: Build docs
+ - name: Build docs
run: make docs
- -
- name: Copy generated docs
+ - name: Copy generated docs
run: rsync -av --exclude CNAME --delete server/docs/ build/ntfy-docs.github.io/docs/
- -
- name: Publish docs
+ - name: Publish docs
run: |
cd build/ntfy-docs.github.io
git config user.name "GitHub Actions Bot"
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index f709332a..aa923199 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -2,40 +2,33 @@ name: release
on:
push:
tags:
- - 'v[0-9]+.[0-9]+.[0-9]+'
+ - "v[0-9]+.[0-9]+.[0-9]+"
jobs:
release:
runs-on: ubuntu-latest
steps:
- -
- name: Checkout code
+ - name: Checkout code
uses: actions/checkout@v3
- -
- name: Install Go
+ - name: Install Go
uses: actions/setup-go@v4
with:
- go-version: '1.19.x'
- -
- name: Install node
+ go-version: "1.19.x"
+ - name: Install node
uses: actions/setup-node@v3
with:
- node-version: '18'
- cache: 'npm'
- cache-dependency-path: './web/package-lock.json'
- -
- name: Docker login
+ node-version: "18"
+ cache: "npm"
+ cache-dependency-path: "./web/package-lock.json"
+ - name: Docker login
uses: docker/login-action@v2
with:
username: ${{ github.repository_owner }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- -
- name: Install dependencies
+ - name: Install dependencies
run: make build-deps-ubuntu
- -
- name: Build and publish
+ - name: Build and publish
run: make release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- -
- name: Print build results and checksums
+ - name: Print build results and checksums
run: make cli-build-results
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 7473567b..81056257 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -4,36 +4,27 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- -
- name: Checkout code
+ - name: Checkout code
uses: actions/checkout@v3
- -
- name: Install Go
+ - name: Install Go
uses: actions/setup-go@v4
with:
- go-version: '1.19.x'
- -
- name: Install node
+ go-version: "1.19.x"
+ - name: Install node
uses: actions/setup-node@v3
with:
- node-version: '18'
- cache: 'npm'
- cache-dependency-path: './web/package-lock.json'
- -
- name: Install dependencies
+ node-version: "18"
+ cache: "npm"
+ cache-dependency-path: "./web/package-lock.json"
+ - name: Install dependencies
run: make build-deps-ubuntu
- -
- name: Build docs (required for tests)
+ - name: Build docs (required for tests)
run: make docs
- -
- name: Build web app (required for tests)
+ - name: Build web app (required for tests)
run: make web
- -
- name: Run tests, formatting, vetting and linting
+ - name: Run tests, formatting, vetting and linting
run: make check
- -
- name: Run coverage
+ - name: Run coverage
run: make coverage
- -
- name: Upload coverage to codecov.io
+ - name: Upload coverage to codecov.io
run: make coverage-upload
diff --git a/.gitpod.yml b/.gitpod.yml
index 6cccd8f2..2c818b36 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -25,4 +25,4 @@ ports:
- name: binary
port: 2586
- name: web
- port: 3000
\ No newline at end of file
+ port: 3000
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 131a302a..18d957ca 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -3,53 +3,48 @@ before:
- go mod download
- go mod tidy
builds:
- -
- id: ntfy_linux_amd64
+ - id: ntfy_linux_amd64
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- tags: [sqlite_omit_load_extension,osusergo,netgo]
+ tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [amd64]
- -
- id: ntfy_linux_armv6
+ - id: ntfy_linux_armv6
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
- tags: [sqlite_omit_load_extension,osusergo,netgo]
+ tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm]
goarm: [6]
- -
- id: ntfy_linux_armv7
+ - id: ntfy_linux_armv7
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=arm-linux-gnueabi-gcc # apt install gcc-arm-linux-gnueabi
- tags: [sqlite_omit_load_extension,osusergo,netgo]
+ tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm]
goarm: [7]
- -
- id: ntfy_linux_arm64
+ - id: ntfy_linux_arm64
binary: ntfy
env:
- CGO_ENABLED=1 # required for go-sqlite3
- CC=aarch64-linux-gnu-gcc # apt install gcc-aarch64-linux-gnu
- tags: [sqlite_omit_load_extension,osusergo,netgo]
+ tags: [sqlite_omit_load_extension, osusergo, netgo]
ldflags:
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [linux]
goarch: [arm64]
- -
- id: ntfy_windows_amd64
+ - id: ntfy_windows_amd64
binary: ntfy
env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
@@ -58,8 +53,7 @@ builds:
- "-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
goos: [windows]
goarch: [amd64]
- -
- id: ntfy_darwin_all
+ - id: ntfy_darwin_all
binary: ntfy
env:
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
@@ -69,8 +63,7 @@ builds:
goos: [darwin]
goarch: [amd64, arm64] # will be combined to "universal binary" (see below)
nfpms:
- -
- package_name: ntfy
+ - package_name: ntfy
homepage: https://heckel.io/ntfy
maintainer: Philipp C. Heckel
description: Simple pub-sub notification service
@@ -104,8 +97,7 @@ nfpms:
preremove: "scripts/prerm.sh"
postremove: "scripts/postrm.sh"
archives:
- -
- id: ntfy_linux
+ - id: ntfy_linux
builds:
- ntfy_linux_amd64
- ntfy_linux_armv6
@@ -121,8 +113,7 @@ archives:
- client/ntfy-client.service
replacements:
amd64: x86_64
- -
- id: ntfy_windows
+ - id: ntfy_windows
builds:
- ntfy_windows_amd64
format: zip
@@ -133,8 +124,7 @@ archives:
- client/client.yml
replacements:
amd64: x86_64
- -
- id: ntfy_darwin
+ - id: ntfy_darwin
builds:
- ntfy_darwin_all
wrap_in_directory: true
@@ -145,20 +135,19 @@ archives:
replacements:
darwin: macOS
universal_binaries:
- -
- id: ntfy_darwin_all
+ - id: ntfy_darwin_all
replace: true
name_template: ntfy
checksum:
- name_template: 'checksums.txt'
+ name_template: "checksums.txt"
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- - '^docs:'
- - '^test:'
+ - "^docs:"
+ - "^test:"
dockers:
- image_templates:
- &amd64_image "binwiederhier/ntfy:{{ .Tag }}-amd64"
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 863c0996..6e92d468 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
-* Demonstrating empathy and kindness toward other people
-* Being respectful of differing opinions, viewpoints, and experiences
-* Giving and gracefully accepting constructive feedback
-* Accepting responsibility and apologizing to those affected by our mistakes,
+- Demonstrating empathy and kindness toward other people
+- Being respectful of differing opinions, viewpoints, and experiences
+- Giving and gracefully accepting constructive feedback
+- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
-* Focusing on what is best not just for us as individuals, but for the overall
+- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
-* The use of sexualized language or imagery, and sexual attention or advances of
+- The use of sexualized language or imagery, and sexual attention or advances of
any kind
-* Trolling, insulting or derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or email address,
+- Trolling, insulting or derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or email address,
without their explicit permission
-* Other conduct which could reasonably be considered inappropriate in a
+- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
@@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement via Discord/Matrix (binwiederhier),
-or email (ntfy@heckel.io). All complaints will be reviewed and investigated promptly
+or email (ntfy@heckel.io). All complaints will be reviewed and investigated promptly
and fairly.
All community leaders are obligated to respect the privacy and security of the
@@ -130,4 +130,3 @@ For answers to common questions about this code of conduct, see the FAQ at
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
-
diff --git a/README.md b/README.md
index cebf55be..1acd7009 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@

# ntfy.sh | Send push notifications to your phone or desktop via PUT/POST
+
[](https://github.com/binwiederhier/ntfy/releases/latest)
[](https://pkg.go.dev/heckel.io/ntfy)
[](https://github.com/binwiederhier/ntfy/actions)
@@ -13,9 +14,9 @@
[](https://ntfy.statuspage.io/)
[](https://gitpod.io/#https://github.com/binwiederhier/ntfy)
-**ntfy** (pronounced "*notify*") is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
-notification service. With ntfy, you can **send notifications to your phone or desktop via scripts** from any computer,
-**without having to sign up or pay any fees**. If you'd like to run your own instance of the service, you can easily do
+**ntfy** (pronounced "_notify_") is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
+notification service. With ntfy, you can **send notifications to your phone or desktop via scripts** from any computer,
+**without having to sign up or pay any fees**. If you'd like to run your own instance of the service, you can easily do
so since ntfy is open source.
You can access the free version of ntfy at **[ntfy.sh](https://ntfy.sh)**. There is also an [open source Android app](https://github.com/binwiederhier/ntfy-android)
@@ -31,7 +32,8 @@ as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) a
## [ntfy Pro](https://ntfy.sh/app) 💸 🎉
-I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self-host, or you want to support the development of ntfy (→ [Purchase via web app](https://ntfy.sh/app)). You can **buy a plan for as low as $3.33/month** (if you use promo code `MYTOPIC`, limited time only). You can also donate via [GitHub Sponsors](https://github.com/sponsors/binwiederhier), and [Liberapay](https://liberapay.com/ntfy). I would be very humbled by your sponsorship. ❤️
+
+I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self-host, or you want to support the development of ntfy (→ [Purchase via web app](https://ntfy.sh/app)). You can **buy a plan for as low as $3.33/month** (if you use promo code `MYTOPIC`, limited time only). You can also donate via [GitHub Sponsors](https://github.com/sponsors/binwiederhier), and [Liberapay](https://liberapay.com/ntfy). I would be very humbled by your sponsorship. ❤️
## **[Documentation](https://ntfy.sh/docs/)**
@@ -42,23 +44,26 @@ I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self
[Building](https://ntfy.sh/docs/develop/)
## Chat / forum
+
There are a few ways to get in touch with me and/or the rest of the community. Feel free to use any of these methods. Whatever
works best for you:
-* [Discord server](https://discord.gg/cT7ECsZj9w) - direct chat with the community
-* [Matrix room #ntfy](https://matrix.to/#/#ntfy:matrix.org) (+ [Matrix space](https://matrix.to/#/#ntfy-space:matrix.org)) - same chat, bridged from Discord
-* [Reddit r/ntfy](https://www.reddit.com/r/ntfy/) - asynchronous forum (_new as of October 2022_)
-* [GitHub issues](https://github.com/binwiederhier/ntfy/issues) - questions, features, bugs
-* [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_)
+- [Discord server](https://discord.gg/cT7ECsZj9w) - direct chat with the community
+- [Matrix room #ntfy](https://matrix.to/#/#ntfy:matrix.org) (+ [Matrix space](https://matrix.to/#/#ntfy-space:matrix.org)) - same chat, bridged from Discord
+- [Reddit r/ntfy](https://www.reddit.com/r/ntfy/) - asynchronous forum (_new as of October 2022_)
+- [GitHub issues](https://github.com/binwiederhier/ntfy/issues) - questions, features, bugs
+- [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_)
## Announcements / beta testers
-For announcements of new releases and cutting-edge beta versions, please subscribe to the [ntfy.sh/announcements](https://ntfy.sh/announcements)
+
+For announcements of new releases and cutting-edge beta versions, please subscribe to the [ntfy.sh/announcements](https://ntfy.sh/announcements)
topic. If you'd like to test the iOS app, join [TestFlight](https://testflight.apple.com/join/P1fFnAm9). For Android betas,
join Discord/Matrix (I'll eventually make a testing channel in Google Play).
## Contributing
+
I welcome any and all contributions. Just create a PR or an issue. For larger features/ideas, please reach out
-on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
+on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
@@ -67,8 +72,9 @@ for the server and the Android app. Or, if you'd like to help translate 🇩🇪
## Sponsors
+
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier),
-and [Liberapay](https://liberapay.com/ntfy). I would be humbled if you helped me carry the server and developer
+and [Liberapay](https://liberapay.com/ntfy). I would be humbled if you helped me carry the server and developer
account costs. Even small donations are very much appreciated. A big fat **Thank You** to the folks already sponsoring ntfy:
@@ -143,38 +149,41 @@ account costs. Even small donations are very much appreciated. A big fat **Thank
I'd also like to thank JetBrains for providing their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/) to me for free,
-and [DigitalOcean](https://m.do.co/c/442b929528db) (*referral link*) for supporting the project:
+and [DigitalOcean](https://m.do.co/c/442b929528db) (_referral link_) for supporting the project:
## Code of Conduct
+
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
**We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.**
-_Please be sure to read the complete [Code of Conduct](CODE_OF_CONDUCT.md)._
+_Please be sure to read the complete [Code of Conduct](CODE_OF_CONDUCT.md)._
## License
-Made with ❤️ by [Philipp C. Heckel](https://heckel.io).
+
+Made with ❤️ by [Philipp C. Heckel](https://heckel.io).
The project is dual licensed under the [Apache License 2.0](LICENSE) and the [GPLv2 License](LICENSE.GPLv2).
Third party libraries and resources:
-* [github.com/urfave/cli](https://github.com/urfave/cli) (MIT) is used to drive the CLI
-* [Mixkit sounds](https://mixkit.co/free-sound-effects/notification/) (Mixkit Free License) are used as notification sounds
-* [Sounds from notificationsounds.com](https://notificationsounds.com) (Creative Commons Attribution) are used as notification sounds
-* [Roboto Font](https://fonts.google.com/specimen/Roboto) (Apache 2.0) is used as a font in everything web
-* [React](https://reactjs.org/) (MIT) is used for the web app
-* [Material UI components](https://mui.com/) (MIT) are used in the web app
-* [MUI dashboard template](https://github.com/mui/material-ui/tree/master/docs/data/material/getting-started/templates/dashboard) (MIT) was used as a basis for the web app
-* [Dexie.js](https://github.com/dexie/Dexie.js) (Apache 2.0) is used for web app persistence in IndexedDB
-* [GoReleaser](https://goreleaser.com/) (MIT) is used to create releases
-* [go-smtp](https://github.com/emersion/go-smtp) (MIT) is used to receive e-mails
-* [stretchr/testify](https://github.com/stretchr/testify) (MIT) is used for unit and integration tests
-* [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
-* [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
-* [github/gemoji](https://github.com/github/gemoji) (MIT) is used for emoji support (specifically the [emoji.json](https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json) file)
-* [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page
-* [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files
-* [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
-* [Statically linking go-sqlite3](https://www.arp242.net/static-go.html)
-* [Linked tabs in mkdocs](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs)
+
+- [github.com/urfave/cli](https://github.com/urfave/cli) (MIT) is used to drive the CLI
+- [Mixkit sounds](https://mixkit.co/free-sound-effects/notification/) (Mixkit Free License) are used as notification sounds
+- [Sounds from notificationsounds.com](https://notificationsounds.com) (Creative Commons Attribution) are used as notification sounds
+- [Roboto Font](https://fonts.google.com/specimen/Roboto) (Apache 2.0) is used as a font in everything web
+- [React](https://reactjs.org/) (MIT) is used for the web app
+- [Material UI components](https://mui.com/) (MIT) are used in the web app
+- [MUI dashboard template](https://github.com/mui/material-ui/tree/master/docs/data/material/getting-started/templates/dashboard) (MIT) was used as a basis for the web app
+- [Dexie.js](https://github.com/dexie/Dexie.js) (Apache 2.0) is used for web app persistence in IndexedDB
+- [GoReleaser](https://goreleaser.com/) (MIT) is used to create releases
+- [go-smtp](https://github.com/emersion/go-smtp) (MIT) is used to receive e-mails
+- [stretchr/testify](https://github.com/stretchr/testify) (MIT) is used for unit and integration tests
+- [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
+- [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
+- [github/gemoji](https://github.com/github/gemoji) (MIT) is used for emoji support (specifically the [emoji.json](https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json) file)
+- [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page
+- [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files
+- [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
+- [Statically linking go-sqlite3](https://www.arp242.net/static-go.html)
+- [Linked tabs in mkdocs](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs)
diff --git a/docker-compose.yml b/docker-compose.yml
index d39492e8..8e4e8267 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,7 +6,7 @@ services:
command:
- serve
environment:
- - TZ=UTC # optional: Change to your desired timezone
+ - TZ=UTC # optional: Change to your desired timezone
user: UID:GID # optional: Set custom user/group or uid/gid
volumes:
- /var/cache/ntfy:/var/cache/ntfy
@@ -14,4 +14,3 @@ services:
ports:
- 80:80
restart: unless-stopped
-
diff --git a/docs/_overrides/main.html b/docs/_overrides/main.html
index 52483ebd..1ec8cda4 100644
--- a/docs/_overrides/main.html
+++ b/docs/_overrides/main.html
@@ -1,50 +1,77 @@
-{% extends "base.html" %}
-
-{% block announce %}
+{% extends "base.html" %} {% block announce %}
-
-
-
-
+
+
+
+
-If you like ntfy, please consider sponsoring me via GitHub Sponsors
-or Liberapay
-, or subscribing to ntfy Pro .
+If you like ntfy, please consider sponsoring me via
+GitHub Sponsors
+or
+Liberapay
+, or subscribing to
+ntfy Pro .
{% endblock %}
diff --git a/docs/config.md b/docs/config.md
index df1f2cd6..66ab57cb 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -1,25 +1,29 @@
# Configuring the ntfy server
-The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`,
-see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)), via command line arguments
+
+The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`,
+see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)), via command line arguments
or using environment variables.
## Quick start
-By default, simply running `ntfy serve` will start the server at port 80. No configuration needed. Batteries included 😀.
+
+By default, simply running `ntfy serve` will start the server at port 80. No configuration needed. Batteries included 😀.
If everything works as it should, you'll see something like this:
+
```
$ ntfy serve
2021/11/30 19:59:08 Listening on :80
```
You can immediately start [publishing messages](publish.md), or subscribe via the [Android app](subscribe/phone.md),
-[the web UI](subscribe/web.md), or simply via [curl or your favorite HTTP client](subscribe/api.md). To configure
+[the web UI](subscribe/web.md), or simply via [curl or your favorite HTTP client](subscribe/api.md). To configure
the server further, check out the [config options table](#config-options) or simply type `ntfy serve --help` to
get a list of [command line options](#command-line-options).
## Example config
+
!!! info
- Definitely check out the **[server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)** file.
- It contains examples and detailed descriptions of all the settings.
+Definitely check out the **[server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)** file.
+It contains examples and detailed descriptions of all the settings.
The most basic settings are `base-url` (the external URL of the ntfy server), the HTTP/HTTPS listen address (`listen-http`
and `listen-https`), and socket path (`listen-unix`). All the other things are additional features.
@@ -27,14 +31,16 @@ and `listen-https`), and socket path (`listen-unix`). All the other things are a
Here are a few working sample configs:
=== "server.yml (HTTP-only, with cache + attachments)"
- ``` yaml
+
+ ```yaml
base-url: "http://ntfy.example.com"
cache-file: "/var/cache/ntfy/cache.db"
attachment-cache-dir: "/var/cache/ntfy/attachments"
```
=== "server.yml (HTTP+HTTPS, with cache + attachments)"
- ``` yaml
+
+ ```yaml
base-url: "http://ntfy.example.com"
listen-http: ":80"
listen-https: ":443"
@@ -45,8 +51,9 @@ Here are a few working sample configs:
```
=== "server.yml (ntfy.sh config)"
- ``` yaml
- # All the things: Behind a proxy, Firebase, cache, attachments,
+
+ ```yaml
+ # All the things: Behind a proxy, Firebase, cache, attachments,
# SMTP publishing & receiving
base-url: "https://ntfy.sh"
@@ -66,16 +73,17 @@ Here are a few working sample configs:
```
## Message cache
+
If desired, ntfy can temporarily keep notifications in an in-memory or an on-disk cache. Caching messages for a short period
of time is important to allow [phones](subscribe/phone.md) and other devices with brittle Internet connections to be able to retrieve
-notifications that they may have missed.
+notifications that they may have missed.
By default, ntfy keeps messages **in-memory for 12 hours**, which means that **cached messages do not survive an application
restart**. You can override this behavior using the following config settings:
-* `cache-file`: if set, ntfy will store messages in a SQLite based cache (default is empty, which means in-memory cache).
+- `cache-file`: if set, ntfy will store messages in a SQLite based cache (default is empty, which means in-memory cache).
**This is required if you'd like messages to be retained across restarts**.
-* `cache-duration`: defines the duration for which messages are stored in the cache (default is `12h`).
+- `cache-duration`: defines the duration for which messages are stored in the cache (default is `12h`).
You can also entirely disable the cache by setting `cache-duration` to `0`. When the cache is disabled, messages are only
passed on to the connected subscribers, but never stored on disk or even kept in memory longer than is needed to forward
@@ -85,30 +93,33 @@ Subscribers can retrieve cached messaging using the [`poll=1` parameter](subscri
[`since=` parameter](subscribe/api.md#fetch-cached-messages).
## Attachments
+
If desired, you may allow users to upload and [attach files to notifications](publish.md#attachments). To enable
-this feature, you have to simply configure an attachment cache directory and a base URL (`attachment-cache-dir`, `base-url`).
+this feature, you have to simply configure an attachment cache directory and a base URL (`attachment-cache-dir`, `base-url`).
Once these options are set and the directory is writable by the server user, you can upload attachments via PUT.
By default, attachments are stored in the disk-cache **for only 3 hours**. The main reason for this is to avoid legal issues
-and such when hosting user controlled content. Typically, this is more than enough time for the user (or the auto download
+and such when hosting user controlled content. Typically, this is more than enough time for the user (or the auto download
feature) to download the file. The following config options are relevant to attachments:
-* `base-url` is the root URL for the ntfy server; this is needed for the generated attachment URLs
-* `attachment-cache-dir` is the cache directory for attached files
-* `attachment-total-size-limit` is the size limit of the on-disk attachment cache (default: 5G)
-* `attachment-file-size-limit` is the per-file attachment size limit (e.g. 300k, 2M, 100M, default: 15M)
-* `attachment-expiry-duration` is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h, default: 3h)
+- `base-url` is the root URL for the ntfy server; this is needed for the generated attachment URLs
+- `attachment-cache-dir` is the cache directory for attached files
+- `attachment-total-size-limit` is the size limit of the on-disk attachment cache (default: 5G)
+- `attachment-file-size-limit` is the per-file attachment size limit (e.g. 300k, 2M, 100M, default: 15M)
+- `attachment-expiry-duration` is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h, default: 3h)
-Here's an example config using mostly the defaults (except for the cache directory, which is empty by default):
+Here's an example config using mostly the defaults (except for the cache directory, which is empty by default):
=== "/etc/ntfy/server.yml (minimal)"
- ``` yaml
+
+ ```yaml
base-url: "https://ntfy.sh"
attachment-cache-dir: "/var/cache/ntfy/attachments"
```
=== "/etc/ntfy/server.yml (all options)"
- ``` yaml
+
+ ```yaml
base-url: "https://ntfy.sh"
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "5G"
@@ -122,41 +133,43 @@ Please also refer to the [rate limiting](#rate-limiting) settings below, specifi
and `visitor-attachment-daily-bandwidth-limit`. Setting these conservatively is necessary to avoid abuse.
## Access control
-By default, the ntfy server is open for everyone, meaning **everyone can read and write to any topic** (this is how
-ntfy.sh is configured). To restrict access to your own server, you can optionally configure authentication and authorization.
-ntfy's auth is implemented with a simple [SQLite](https://www.sqlite.org/)-based backend. It implements two roles
-(`user` and `admin`) and per-topic `read` and `write` permissions using an [access control list (ACL)](https://en.wikipedia.org/wiki/Access-control_list).
-Access control entries can be applied to users as well as the special everyone user (`*`), which represents anonymous API access.
+By default, the ntfy server is open for everyone, meaning **everyone can read and write to any topic** (this is how
+ntfy.sh is configured). To restrict access to your own server, you can optionally configure authentication and authorization.
+
+ntfy's auth is implemented with a simple [SQLite](https://www.sqlite.org/)-based backend. It implements two roles
+(`user` and `admin`) and per-topic `read` and `write` permissions using an [access control list (ACL)](https://en.wikipedia.org/wiki/Access-control_list).
+Access control entries can be applied to users as well as the special everyone user (`*`), which represents anonymous API access.
To set up auth, simply **configure the following two options**:
-* `auth-file` is the user/access database; it is created automatically if it doesn't already exist; suggested
+- `auth-file` is the user/access database; it is created automatically if it doesn't already exist; suggested
location `/var/lib/ntfy/user.db` (easiest if deb/rpm package is used)
-* `auth-default-access` defines the default/fallback access if no access control entry is found; it can be
+- `auth-default-access` defines the default/fallback access if no access control entry is found; it can be
set to `read-write` (default), `read-only`, `write-only` or `deny-all`.
Once configured, you can use the `ntfy user` command to [add or modify users](#users-and-roles), and the `ntfy access` command
-lets you [modify the access control list](#access-control-list-acl) for specific users and topic patterns. Both of these
-commands **directly edit the auth database** (as defined in `auth-file`), so they only work on the server, and only if the user
+lets you [modify the access control list](#access-control-list-acl) for specific users and topic patterns. Both of these
+commands **directly edit the auth database** (as defined in `auth-file`), so they only work on the server, and only if the user
accessing them has the right permissions.
### Users and roles
+
The `ntfy user` command allows you to add/remove/change users in the ntfy user database, as well as change
-passwords or roles (`user` or `admin`). In practice, you'll often just create one admin
+passwords or roles (`user` or `admin`). In practice, you'll often just create one admin
user with `ntfy user add --role=admin ...` and be done with all this (see [example below](#example-private-instance)).
**Roles:**
-* Role `user` (default): Users with this role have no special permissions. Manage access using `ntfy access`
+- Role `user` (default): Users with this role have no special permissions. Manage access using `ntfy access`
(see [below](#access-control-list-acl)).
-* Role `admin`: Users with this role can read/write to all topics. Granular access control is not necessary.
+- Role `admin`: Users with this role can read/write to all topics. Granular access control is not necessary.
**Example commands** (type `ntfy user --help` or `ntfy user COMMAND --help` for more details):
```
ntfy user list # Shows list of users (alias: 'ntfy access')
-ntfy user add phil # Add regular user phil
+ntfy user add phil # Add regular user phil
ntfy user add --role=admin phil # Add admin user phil
ntfy user del phil # Delete user phil
ntfy user change-pass phil # Change password for user phil
@@ -165,8 +178,9 @@ ntfy user change-tier phil pro # Change phil's tier to "pro"
```
### Access control list (ACL)
+
The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access (`everyone`/`*`)**.
-Each entry represents the access permissions for a user to a specific topic or topic pattern.
+Each entry represents the access permissions for a user to a specific topic or topic pattern.
The ACL can be displayed or modified with the `ntfy access` command:
@@ -176,22 +190,23 @@ ntfy access USERNAME # Shows access control entries for USERNA
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
```
-A `USERNAME` is an existing user, as created with `ntfy user add` (see [users and roles](#users-and-roles)), or the
+A `USERNAME` is an existing user, as created with `ntfy user add` (see [users and roles](#users-and-roles)), or the
anonymous user `everyone` or `*`, which represents clients that access the API without username/password.
A `TOPIC` is either a specific topic name (e.g. `mytopic`, or `phil_alerts`), or a wildcard pattern that matches any
-number of topics (e.g. `alerts_*` or `ben-*`). Only the wildcard character `*` is supported. It stands for zero to any
+number of topics (e.g. `alerts_*` or `ben-*`). Only the wildcard character `*` is supported. It stands for zero to any
number of characters.
A `PERMISSION` is any of the following supported permissions:
-* `read-write` (alias: `rw`): Allows [publishing messages](publish.md) to the given topic, as well as
+- `read-write` (alias: `rw`): Allows [publishing messages](publish.md) to the given topic, as well as
[subscribing](subscribe/api.md) and reading messages
-* `read-only` (aliases: `read`, `ro`): Allows only subscribing and reading messages, but not publishing to the topic
-* `write-only` (aliases: `write`, `wo`): Allows only publishing to the topic, but not subscribing to it
-* `deny` (alias: `none`): Allows neither publishing nor subscribing to a topic
+- `read-only` (aliases: `read`, `ro`): Allows only subscribing and reading messages, but not publishing to the topic
+- `write-only` (aliases: `write`, `wo`): Allows only publishing to the topic, but not subscribing to it
+- `deny` (alias: `none`): Allows neither publishing nor subscribing to a topic
**Example commands** (type `ntfy access --help` for more details):
+
```
ntfy access # Shows entire access control list
ntfy access phil # Shows access for user phil
@@ -204,6 +219,7 @@ ntfy access --reset phil mytopic # Reset access for user phil and topic mytopi
```
**Example ACL:**
+
```
$ ntfy access
user phil (admin)
@@ -224,20 +240,22 @@ to topic `garagedoor` and all topics starting with the word `alerts` (wildcards)
(called `*`/`everyone`) only have read access to the `announcements` and `server-stats` topics.
### Access tokens
+
In addition to username/password auth, ntfy also provides authentication via access tokens. Access tokens are useful
to avoid having to configure your password across multiple publishing/subscribing applications. For instance, you may
want to use a dedicated token to publish from your backup host, and one from your home automation system.
!!! info
- As of today, access tokens grant users **full access to the user account**. Aside from changing the password,
- and deleting the account, every action can be performed with a token. Granular access tokens are on the roadmap,
- but not yet implemented.
+As of today, access tokens grant users **full access to the user account**. Aside from changing the password,
+and deleting the account, every action can be performed with a token. Granular access tokens are on the roadmap,
+but not yet implemented.
The `ntfy token` command can be used to manage access tokens for users. Tokens can have labels, and they can expire
-automatically (or never expire). Each user can have up to 20 tokens (hardcoded).
+automatically (or never expire). Each user can have up to 20 tokens (hardcoded).
**Example commands** (type `ntfy token --help` or `ntfy token COMMAND --help` for more details):
-```
+
+```sh
ntfy token list # Shows list of tokens for all users
ntfy token list phil # Shows list of tokens for user phil
ntfy token add phil # Create token for user phil which never expires
@@ -246,7 +264,8 @@ ntfy token remove phil tk_th2sxr... # Delete token
```
**Creating an access token:**
-```
+
+```sh
$ ntfy token add --expires=30d --label="backups" phil
$ ntfy token list
user phil
@@ -257,28 +276,31 @@ Once an access token is created, you can **use it to authenticate against the nt
subscribe to topics**. To learn how, check out [authenticate via access tokens](publish.md#access-tokens).
### Example: Private instance
+
The easiest way to configure a private instance is to set `auth-default-access` to `deny-all` in the `server.yml`:
=== "/etc/ntfy/server.yml"
- ``` yaml
+
+ ```yaml
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"
```
After that, simply create an `admin` user:
-```
+```sh
$ ntfy user add --role=admin phil
password: mypass
confirm: mypass
-user phil added with role admin
+user phil added with role admin
```
-Once you've done that, you can publish and subscribe using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
+Once you've done that, you can publish and subscribe using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
with the given username/password. Be sure to use HTTPS to avoid eavesdropping and exposing your password. Here's a simple example:
=== "Command line (curl)"
- ```
+
+ ```sh
curl \
-u phil:mypass \
-d "Look ma, with auth" \
@@ -286,7 +308,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "ntfy CLI"
- ```
+
+ ```sh
ntfy publish \
-u phil:mypass \
ntfy.example.com/mysecrets \
@@ -294,7 +317,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "HTTP"
- ``` http
+
+ ```sh
POST /mysecrets HTTP/1.1
Host: ntfy.example.com
Authorization: Basic cGhpbDpteXBhc3M=
@@ -303,7 +327,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "JavaScript"
- ``` javascript
+
+ ```js
fetch('https://ntfy.example.com/mysecrets', {
method: 'POST', // PUT works too
body: 'Look ma, with auth',
@@ -314,7 +339,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
strings.NewReader("Look ma, with auth"))
req.Header.Set("Authorization", "Basic cGhpbDpteXBhc3M=")
@@ -322,7 +348,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.example.com/mysecrets",
data="Look ma, with auth",
headers={
@@ -331,11 +358,12 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
- 'header' =>
+ 'header' =>
'Content-Type: text/plain\r\n' .
'Authorization: Basic cGhpbDpteXBhc3M=',
'content' => 'Look ma, with auth'
@@ -344,42 +372,47 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
```
### Example: UnifiedPush
-[UnifiedPush](https://unifiedpush.org) requires that the [application server](https://unifiedpush.org/spec/definitions/#application-server) (e.g. Synapse, Fediverse Server, …)
-has anonymous write access to the [topic](https://unifiedpush.org/spec/definitions/#endpoint) used for push messages.
-The topic names used by UnifiedPush all start with the `up*` prefix. Please refer to the
+
+[UnifiedPush](https://unifiedpush.org) requires that the [application server](https://unifiedpush.org/spec/definitions/#application-server) (e.g. Synapse, Fediverse Server, …)
+has anonymous write access to the [topic](https://unifiedpush.org/spec/definitions/#endpoint) used for push messages.
+The topic names used by UnifiedPush all start with the `up*` prefix. Please refer to the
**[UnifiedPush documentation](https://unifiedpush.org/users/distributors/ntfy/#limit-access-to-some-users)** for more details.
-To enable support for UnifiedPush for private servers (i.e. `auth-default-access: "deny-all"`), you should either
+To enable support for UnifiedPush for private servers (i.e. `auth-default-access: "deny-all"`), you should either
allow anonymous write access for the entire prefix or explicitly per topic:
=== "Prefix"
- ```
+
+ ```sh
$ ntfy access '*' 'up*' write-only
```
=== "Explicitly"
- ```
+
+ ```sh
$ ntfy access '*' upYzMtZGZiYTY5 write-only
```
## E-mail notifications
-To allow forwarding messages via e-mail, you can configure an **SMTP server for outgoing messages**. Once configured,
-you can set the `X-Email` header to [send messages via e-mail](publish.md#e-mail-notifications) (e.g.
+
+To allow forwarding messages via e-mail, you can configure an **SMTP server for outgoing messages**. Once configured,
+you can set the `X-Email` header to [send messages via e-mail](publish.md#e-mail-notifications) (e.g.
`curl -d "hi there" -H "X-Email: phil@example.com" ntfy.sh/mytopic`).
-As of today, only SMTP servers with PLAIN auth and STARTLS are supported. To enable e-mail sending, you must set the
+As of today, only SMTP servers with PLAIN auth and STARTLS are supported. To enable e-mail sending, you must set the
following settings:
-* `base-url` is the root URL for the ntfy server; this is needed for e-mail footer
-* `smtp-sender-addr` is the hostname:port of the SMTP server
-* `smtp-sender-user` and `smtp-sender-pass` are the username and password of the SMTP user
-* `smtp-sender-from` is the e-mail address of the sender
+- `base-url` is the root URL for the ntfy server; this is needed for e-mail footer
+- `smtp-sender-addr` is the hostname:port of the SMTP server
+- `smtp-sender-user` and `smtp-sender-pass` are the username and password of the SMTP user
+- `smtp-sender-from` is the e-mail address of the sender
-Here's an example config using [Amazon SES](https://aws.amazon.com/ses/) for outgoing mail (this is how it is
+Here's an example config using [Amazon SES](https://aws.amazon.com/ses/) for outgoing mail (this is how it is
configured for `ntfy.sh`):
=== "/etc/ntfy/server.yml"
- ``` yaml
+
+ ```yaml
base-url: "https://ntfy.sh"
smtp-sender-addr: "email-smtp.us-east-2.amazonaws.com:587"
smtp-sender-user: "AKIDEADBEEFAFFE12345"
@@ -387,34 +420,36 @@ configured for `ntfy.sh`):
smtp-sender-from: "ntfy@ntfy.sh"
```
-Please also refer to the [rate limiting](#rate-limiting) settings below, specifically `visitor-email-limit-burst`
+Please also refer to the [rate limiting](#rate-limiting) settings below, specifically `visitor-email-limit-burst`
and `visitor-email-limit-burst`. Setting these conservatively is necessary to avoid abuse.
## E-mail publishing
-To allow publishing messages via e-mail, ntfy can run a lightweight **SMTP server for incoming messages**. Once configured,
-users can [send emails to a topic e-mail address](publish.md#e-mail-publishing) (e.g. `mytopic@ntfy.sh` or
-`myprefix-mytopic@ntfy.sh`) to publish messages to a topic. This is useful for e-mail based integrations such as for
+
+To allow publishing messages via e-mail, ntfy can run a lightweight **SMTP server for incoming messages**. Once configured,
+users can [send emails to a topic e-mail address](publish.md#e-mail-publishing) (e.g. `mytopic@ntfy.sh` or
+`myprefix-mytopic@ntfy.sh`) to publish messages to a topic. This is useful for e-mail based integrations such as for
statuspage.io (though these days most services also support webhooks and HTTP calls).
To configure the SMTP server, you must at least set `smtp-server-listen` and `smtp-server-domain`:
-* `smtp-server-listen` defines the IP address and port the SMTP server will listen on, e.g. `:25` or `1.2.3.4:25`
-* `smtp-server-domain` is the e-mail domain, e.g. `ntfy.sh` (must be identical to MX record, see below)
-* `smtp-server-addr-prefix` is an optional prefix for the e-mail addresses to prevent spam. If set to `ntfy-`, for instance,
+- `smtp-server-listen` defines the IP address and port the SMTP server will listen on, e.g. `:25` or `1.2.3.4:25`
+- `smtp-server-domain` is the e-mail domain, e.g. `ntfy.sh` (must be identical to MX record, see below)
+- `smtp-server-addr-prefix` is an optional prefix for the e-mail addresses to prevent spam. If set to `ntfy-`, for instance,
only e-mails to `ntfy-$topic@ntfy.sh` will be accepted. If this is not set, all emails to `$topic@ntfy.sh` will be
accepted (which may obviously be a spam problem).
Here's an example config (this is how it is configured for `ntfy.sh`):
=== "/etc/ntfy/server.yml"
- ``` yaml
+
+ ```yaml
smtp-server-listen: ":25"
smtp-server-domain: "ntfy.sh"
smtp-server-addr-prefix: "ntfy-"
```
-In addition to configuring the ntfy server, you have to create two DNS records (an [MX record](https://en.wikipedia.org/wiki/MX_record)
-and a corresponding A record), so incoming mail will find its way to your server. Here's an example of how `ntfy.sh` is
+In addition to configuring the ntfy server, you have to create two DNS records (an [MX record](https://en.wikipedia.org/wiki/MX_record)
+and a corresponding A record), so incoming mail will find its way to your server. Here's an example of how `ntfy.sh` is
configured (in [Amazon Route 53](https://aws.amazon.com/route53/)):
@@ -422,7 +457,7 @@ configured (in [Amazon Route 53](https://aws.amazon.com/route53/)):
DNS records for incoming mail
-You can check if everything is working correctly by sending an email as raw SMTP via `nc`. Create a text file, e.g.
+You can check if everything is working correctly by sending an email as raw SMTP via `nc`. Create a text file, e.g.
`email.txt`
```
@@ -437,10 +472,10 @@ Hello from 🇩🇪
.
```
-And then send the mail via `nc` like this. If you see any lines starting with `451`, those are errors from the
+And then send the mail via `nc` like this. If you see any lines starting with `451`, those are errors from the
ntfy server. Read them carefully.
-```
+```sh
$ cat email.txt | nc -N ntfy.sh 25
220 ntfy.sh ESMTP Service Ready
250-Hello example.com
@@ -451,50 +486,55 @@ $ cat email.txt | nc -N ntfy.sh 25
As for the DNS setup, be sure to verify that `dig MX` and `dig A` are returning results similar to this:
-```
-$ dig MX ntfy.sh +short
+```sh
+$ dig MX ntfy.sh +short
10 mx1.ntfy.sh.
-$ dig A mx1.ntfy.sh +short
+$ dig A mx1.ntfy.sh +short
3.139.215.220
```
## Behind a proxy (TLS, etc.)
+
!!! warning
- If you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Otherwise, all visitors are
- [rate limited](#rate-limiting) as if they are one.
+If you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Otherwise, all visitors are
+[rate limited](#rate-limiting) as if they are one.
-It may be desirable to run ntfy behind a proxy (e.g. nginx, HAproxy or Apache), so you can provide TLS certificates
-using Let's Encrypt using certbot, or simply because you'd like to share the ports (80/443) with other services.
-Whatever your reasons may be, there are a few things to consider.
+It may be desirable to run ntfy behind a proxy (e.g. nginx, HAproxy or Apache), so you can provide TLS certificates
+using Let's Encrypt using certbot, or simply because you'd like to share the ports (80/443) with other services.
+Whatever your reasons may be, there are a few things to consider.
-If you are running ntfy behind a proxy, you should set the `behind-proxy` flag. This will instruct the
-[rate limiting](#rate-limiting) logic to use the `X-Forwarded-For` header as the primary identifier for a visitor,
+If you are running ntfy behind a proxy, you should set the `behind-proxy` flag. This will instruct the
+[rate limiting](#rate-limiting) logic to use the `X-Forwarded-For` header as the primary identifier for a visitor,
as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will
be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address.
=== "/etc/ntfy/server.yml"
- ``` yaml
+
+ ```yaml
# Tell ntfy to use "X-Forwarded-For" to identify visitors
behind-proxy: true
```
### TLS/SSL
-ntfy supports HTTPS/TLS by setting the `listen-https` [config option](#config-options). However, if you
+
+ntfy supports HTTPS/TLS by setting the `listen-https` [config option](#config-options). However, if you
are behind a proxy, it is recommended that TLS/SSL termination is done by the proxy itself (see below).
-I highly recommend using [certbot](https://certbot.eff.org/). I use it with the [dns-route53 plugin](https://certbot-dns-route53.readthedocs.io/en/stable/),
+I highly recommend using [certbot](https://certbot.eff.org/). I use it with the [dns-route53 plugin](https://certbot-dns-route53.readthedocs.io/en/stable/),
which lets you use [AWS Route 53](https://aws.amazon.com/route53/) as the challenge. That's much easier than using the
HTTP challenge. I've found [this guide](https://nandovieira.com/using-lets-encrypt-in-development-with-nginx-and-aws-route53) to
be incredibly helpful.
### nginx/Apache2/caddy
+
For your convenience, here's a working config that'll help configure things behind a proxy. Be sure to **enable WebSockets**
-by forwarding the `Connection` and `Upgrade` headers accordingly.
+by forwarding the `Connection` and `Upgrade` headers accordingly.
In this example, ntfy runs on `:2586` and we proxy traffic to it. We also redirect HTTP to HTTPS for GET requests against a topic
or the root domain:
=== "nginx (convenient)"
+
```
# /etc/nginx/sites-*/ntfy
#
@@ -509,7 +549,7 @@ or the root domain:
server_name ntfy.sh;
location / {
- # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
+ # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
# it to work with curl without the annoying https:// prefix
set $redirect_https "";
if ($request_method = GET) {
@@ -524,16 +564,16 @@ or the root domain:
proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1;
-
+
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
-
+
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
+
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
@@ -541,11 +581,11 @@ or the root domain:
client_max_body_size 0; # Stream request body to backend
}
}
-
+
server {
listen 443 ssl http2;
server_name ntfy.sh;
-
+
# See https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6see https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
@@ -553,10 +593,10 @@ or the root domain:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
-
+
ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;
-
+
location / {
proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1;
@@ -564,28 +604,29 @@ or the root domain:
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
-
+
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
+
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
-
+
client_max_body_size 0; # Stream request body to backend
}
}
```
=== "nginx (more secure)"
+
```
# /etc/nginx/sites-*/ntfy
#
# This config requires the use of the -L flag in curl to redirect to HTTPS, and it keeps nginx output buffering
# enabled. While recommended, I have had issues with that in the past.
-
+
server {
listen 80;
server_name ntfy.sh;
@@ -608,11 +649,11 @@ or the root domain:
client_max_body_size 0; # Stream request body to backend
}
}
-
+
server {
listen 443 ssl http2;
server_name ntfy.sh;
-
+
# See https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6see https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
@@ -620,10 +661,10 @@ or the root domain:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
-
+
ssl_certificate /etc/letsencrypt/live/ntfy.sh/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ntfy.sh/privkey.pem;
-
+
location / {
proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1;
@@ -643,6 +684,7 @@ or the root domain:
```
=== "Apache2"
+
```
# /etc/apache2/sites-*/ntfy.conf
@@ -666,16 +708,16 @@ or the root domain:
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L]
-
- # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
- # it to work with curl without the annoying https:// prefix
+
+ # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
+ # it to work with curl without the annoying https:// prefix
RewriteCond %{REQUEST_METHOD} GET
RewriteRule ^/([-_A-Za-z0-9]{0,64})$ https://%{SERVER_NAME}/$1 [R,L]
-
+
ServerName ntfy.sh
-
+
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/ntfy.sh/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ntfy.sh/privkey.pem
@@ -688,7 +730,7 @@ or the root domain:
SetEnv proxy-nokeepalive 1
SetEnv proxy-sendchunked 1
- # Higher than the max message size of 4096 bytes
+ # Higher than the max message size of 4096 bytes
LimitRequestBody 102400
# Enable mod_rewrite (requires "a2enmod rewrite")
@@ -697,11 +739,12 @@ or the root domain:
# WebSockets support (requires "a2enmod rewrite proxy_wstunnel")
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
- RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L]
+ RewriteRule ^/?(.*) "ws://127.0.0.1:2586/$1" [P,L]
```
=== "caddy"
+
```
# Note that this config is most certainly incomplete. Please help out and let me know what's missing
# via Discord/Matrix or in a GitHub issue.
@@ -721,9 +764,10 @@ or the root domain:
```
## Firebase (FCM)
+
!!! info
- Using Firebase is **optional** and only works if you modify and [build your own Android .apk](develop.md#android-app).
- For a self-hosted instance, it's easier to just not bother with FCM.
+Using Firebase is **optional** and only works if you modify and [build your own Android .apk](develop.md#android-app).
+For a self-hosted instance, it's easier to just not bother with FCM.
[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) is the Google approved way to send
push messages to Android devices. FCM is the only method that an Android app can receive messages without having to run a
@@ -740,7 +784,8 @@ To configure FCM for your self-hosted instance of the ntfy server, follow these
4. Build your own Android .apk following [these instructions](develop.md#android-app)
Example:
-```
+
+```yaml
# If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app.
# This is optional and only required to support Android apps (which don't allow background services anymore).
#
@@ -748,16 +793,17 @@ firebase-key-file: "/etc/ntfy/ntfy-sh-firebase-adminsdk-ahnce-9f4d6f14b5.json"
```
## iOS instant notifications
-Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant
-push notifications without a central server.
-To still support instant notifications on iOS through your self-hosted ntfy server, you have to forward so called `poll_request`
+Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant
+push notifications without a central server.
+
+To still support instant notifications on iOS through your self-hosted ntfy server, you have to forward so called `poll_request`
messages to the main ntfy.sh server (or any upstream server that's APNS/Firebase connected, if you build your own iOS app),
which will then forward it to Firebase/APNS.
To configure it, simply set `upstream-base-url` like so:
-``` yaml
+```yaml
upstream-base-url: "https://ntfy.sh"
upstream-access-token: "..." # optional, only if rate limits exceeded, or upstream server protected
```
@@ -768,29 +814,30 @@ the message ID of the original message, instructing the iOS app to poll this ser
If `upstream-base-url` is not set, notifications will still eventually get to your device, but delivery can take hours,
depending on the state of the phone. If you are using your phone, it shouldn't take more than 20-30 minutes though.
-In case you're curious, here's an example of the entire flow:
+In case you're curious, here's an example of the entire flow:
- In the iOS app, you subscribe to `https://ntfy.example.com/mytopic`
- The app subscribes to the Firebase topic `6de73be8dfb7d69e...` (the SHA256 of the topic URL)
-- When you publish a message to `https://ntfy.example.com/mytopic`, your ntfy server will publish a
- poll request to `https://ntfy.sh/6de73be8dfb7d69e...`. The request from your server to the upstream server
+- When you publish a message to `https://ntfy.example.com/mytopic`, your ntfy server will publish a
+ poll request to `https://ntfy.sh/6de73be8dfb7d69e...`. The request from your server to the upstream server
contains only the message ID (in the `X-Poll-ID` header), and the SHA256 checksum of the topic URL (as upstream topic).
- The ntfy.sh server publishes the poll request message to Firebase, which forwards it to APNS, which forwards it to your iOS device
- Your iOS device receives the poll request, and fetches the actual message from your server, and then displays it
Here's an example of what the self-hosted server forwards to the upstream server. The request is equivalent to this curl:
-```
+```sh
curl -X POST -H "X-Poll-ID: s4PdJozxM8na" https://ntfy.sh/6de73be8dfb7d69e32fb2c00c23fe7adbd8b5504406e3068c273aa24cef4055b
{"id":"4HsClFEuCIcs","time":1654087955,"event":"poll_request","topic":"6de73be8dfb7d69e32fb2c00c23fe7adbd8b5504406e3068c273aa24cef4055b","message":"New message","poll_id":"s4PdJozxM8na"}
```
-Note that the self-hosted server literally sends the message `New message` for every message, even if your message
-may be `Some other message`. This is so that if iOS cannot talk to the self-hosted server (in time, or at all),
+Note that the self-hosted server literally sends the message `New message` for every message, even if your message
+may be `Some other message`. This is so that if iOS cannot talk to the self-hosted server (in time, or at all),
it'll show `New message` as a popup.
## Tiers
-ntfy supports associating users to pre-defined tiers. Tiers can be used to grant users higher limits, such as
+
+ntfy supports associating users to pre-defined tiers. Tiers can be used to grant users higher limits, such as
daily message limits, attachment size, or make it possible for users to reserve topics. If [payments are enabled](#payments),
tiers can be paid or unpaid, and users can upgrade/downgrade between them. If payments are disabled, then the only way
to switch between tiers is with the `ntfy user change-tier` command (see [users and roles](#users-and-roles)).
@@ -801,7 +848,8 @@ Once a user is associated with a tier, some limits are overridden based on the t
The `ntfy tier` command can be used to manage all available tiers. By default, there are no pre-defined tiers.
**Example commands** (type `ntfy token --help` or `ntfy token COMMAND --help` for more details):
-```
+
+```sh
ntfy tier add pro # Add tier with code "pro", using the defaults
ntfy tier change --name="Pro" pro # Update the name of an existing tier
ntfy tier del starter # Delete an existing tier
@@ -809,7 +857,8 @@ ntfy user change-tier phil pro # Switch user "phil" to tier "pro"
```
**Creating a tier (full example):**
-```
+
+```sh
ntfy tier add \
--name="Pro" \
--message-limit=10000 \
@@ -826,37 +875,39 @@ ntfy tier add \
```
## Payments
+
ntfy supports paid [tiers](#tiers) via [Stripe](https://stripe.com/) as a payment provider. If payments are enabled,
-users can register, login and switch plans in the web app. The web app will behave slightly differently if payments
+users can register, login and switch plans in the web app. The web app will behave slightly differently if payments
are enabled (e.g. showing an upgrade banner, or "ntfy Pro" tags).
!!! info
- The ntfy payments integration is very tailored to ntfy.sh and Stripe. I do not intend to support arbitrary use
- cases.
+The ntfy payments integration is very tailored to ntfy.sh and Stripe. I do not intend to support arbitrary use
+cases.
To enable payments, sign up with [Stripe](https://stripe.com/), set the `stripe-secret-key` and `stripe-webhook-key`
-config options:
+config options:
-* `stripe-secret-key` is the key used for the Stripe API communication. Setting this values
- enables payments in the ntfy web app (e.g. Upgrade dialog). See [API keys](https://dashboard.stripe.com/apikeys).
-* `stripe-webhook-key` is the key required to validate the authenticity of incoming webhooks from Stripe.
- Webhooks are essential to keep the local database in sync with the payment provider. See [Webhooks](https://dashboard.stripe.com/webhooks).
-* `billing-contact` is an email address or website displayed in the "Upgrade tier" dialog to let people reach
- out with billing questions. If unset, nothing will be displayed.
+- `stripe-secret-key` is the key used for the Stripe API communication. Setting this values
+ enables payments in the ntfy web app (e.g. Upgrade dialog). See [API keys](https://dashboard.stripe.com/apikeys).
+- `stripe-webhook-key` is the key required to validate the authenticity of incoming webhooks from Stripe.
+ Webhooks are essential to keep the local database in sync with the payment provider. See [Webhooks](https://dashboard.stripe.com/webhooks).
+- `billing-contact` is an email address or website displayed in the "Upgrade tier" dialog to let people reach
+ out with billing questions. If unset, nothing will be displayed.
In addition to setting these two options, you also need to define a [Stripe webhook](https://dashboard.stripe.com/webhooks)
-for the `customer.subscription.updated` and `customer.subscription.deleted` event, which points
+for the `customer.subscription.updated` and `customer.subscription.deleted` event, which points
to `https://ntfy.example.com/v1/account/billing/webhook`.
Here's an example:
-``` yaml
+```yaml
stripe-secret-key: "sk_test_ZmhzZGtmbGhkc2tqZmhzYcO2a2hmbGtnaHNkbGtnaGRsc2hnbG"
stripe-webhook-key: "whsec_ZnNkZnNIRExBSFNES0hBRFNmaHNka2ZsaGR"
billing-contact: "phil@example.com"
```
## Phone calls
+
ntfy supports phone calls via [Twilio](https://www.twilio.com/) as a call provider. If phone calls are enabled,
users can verify and add a phone number, and then receive phone calls when publishing a message using the `X-Call` header.
See [publishing page](publish.md#phone-calls) for more details.
@@ -864,81 +915,88 @@ See [publishing page](publish.md#phone-calls) for more details.
To enable Twilio integration, sign up with [Twilio](https://www.twilio.com/), purchase a phone number (Toll free numbers
are the easiest), and then configure the following options:
-* `twilio-account` is the Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586
-* `twilio-auth-token` is the Twilio auth token, e.g. affebeef258625862586258625862586
-* `twilio-phone-number` is the outgoing phone number you purchased, e.g. +18775132586
-* `twilio-verify-service` is the Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586
+- `twilio-account` is the Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586
+- `twilio-auth-token` is the Twilio auth token, e.g. affebeef258625862586258625862586
+- `twilio-phone-number` is the outgoing phone number you purchased, e.g. +18775132586
+- `twilio-verify-service` is the Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586
After you have configured phone calls, create a [tier](#tiers) with a call limit (e.g. `ntfy tier create --call-limit=10 ...`),
and then assign it to a user. Users may then use the `X-Call` header to receive a phone call when publishing a message.
## Rate limiting
+
!!! info
- Be aware that if you are running ntfy behind a proxy, you must set the `behind-proxy` flag.
- Otherwise, all visitors are rate limited as if they are one.
+Be aware that if you are running ntfy behind a proxy, you must set the `behind-proxy` flag.
+Otherwise, all visitors are rate limited as if they are one.
By default, ntfy runs without authentication, so it is vitally important that we protect the server from abuse or overload.
There are various limits and rate limits in place that you can use to configure the server:
-* **Global limit**: A global limit applies across all visitors (IPs, clients, users)
-* **Visitor limit**: A visitor limit only applies to a certain visitor. A **visitor** is identified by its IP address
- (or the `X-Forwarded-For` header if `behind-proxy` is set). All config options that start with the word `visitor` apply
+- **Global limit**: A global limit applies across all visitors (IPs, clients, users)
+- **Visitor limit**: A visitor limit only applies to a certain visitor. A **visitor** is identified by its IP address
+ (or the `X-Forwarded-For` header if `behind-proxy` is set). All config options that start with the word `visitor` apply
only on a per-visitor basis.
During normal usage, you shouldn't encounter these limits at all, and even if you burst a few requests or emails
(e.g. when you reconnect after a connection drop), it shouldn't have any effect.
### General limits
+
Let's do the easy limits first:
-* `global-topic-limit` defines the total number of topics before the server rejects new topics. It defaults to 15,000.
-* `visitor-subscription-limit` is the number of subscriptions (open connections) per visitor. This value defaults to 30.
+- `global-topic-limit` defines the total number of topics before the server rejects new topics. It defaults to 15,000.
+- `visitor-subscription-limit` is the number of subscriptions (open connections) per visitor. This value defaults to 30.
### Request limits
+
In addition to the limits above, there is a requests/second limit per visitor for all sensitive GET/PUT/POST requests.
This limit uses a [token bucket](https://en.wikipedia.org/wiki/Token_bucket) (using Go's [rate package](https://pkg.go.dev/golang.org/x/time/rate)):
-Each visitor has a bucket of 60 requests they can fire against the server (defined by `visitor-request-limit-burst`).
+Each visitor has a bucket of 60 requests they can fire against the server (defined by `visitor-request-limit-burst`).
After the 60, new requests will encounter a `429 Too Many Requests` response. The visitor request bucket is refilled at a rate of one
request every 5s (defined by `visitor-request-limit-replenish`)
-* `visitor-request-limit-burst` is the initial bucket of requests each visitor has. This defaults to 60.
-* `visitor-request-limit-replenish` is the rate at which the bucket is refilled (one request per x). Defaults to 5s.
-* `visitor-request-limit-exempt-hosts` is a comma-separated list of hostnames and IPs to be exempt from request rate
+- `visitor-request-limit-burst` is the initial bucket of requests each visitor has. This defaults to 60.
+- `visitor-request-limit-replenish` is the rate at which the bucket is refilled (one request per x). Defaults to 5s.
+- `visitor-request-limit-exempt-hosts` is a comma-separated list of hostnames and IPs to be exempt from request rate
limiting; hostnames are resolved at the time the server is started. Defaults to an empty list.
### Message limits
-By default, the number of messages a visitor can send is governed entirely by the [request limit](#request-limits).
+
+By default, the number of messages a visitor can send is governed entirely by the [request limit](#request-limits).
For instance, if the request limit allows for 15,000 requests per day, and all of those requests are POST/PUT requests
to publish messages, then that is the daily message limit.
-To limit the number of daily messages per visitor, you can set `visitor-message-daily-limit`. This defines the number
+To limit the number of daily messages per visitor, you can set `visitor-message-daily-limit`. This defines the number
of messages a visitor can send in a day. This counter is reset every day at midnight (UTC).
### Attachment limits
-Aside from the global file size and total attachment cache limits (see [above](#attachments)), there are two relevant
+
+Aside from the global file size and total attachment cache limits (see [above](#attachments)), there are two relevant
per-visitor limits:
-* `visitor-attachment-total-size-limit` is the total storage limit used for attachments per visitor. It defaults to 100M.
- The per-visitor storage is automatically decreased as attachments expire. External attachments (attached via `X-Attach`,
- see [publishing docs](publish.md#attachments)) do not count here.
-* `visitor-attachment-daily-bandwidth-limit` is the total daily attachment download/upload bandwidth limit per visitor,
+- `visitor-attachment-total-size-limit` is the total storage limit used for attachments per visitor. It defaults to 100M.
+ The per-visitor storage is automatically decreased as attachments expire. External attachments (attached via `X-Attach`,
+ see [publishing docs](publish.md#attachments)) do not count here.
+- `visitor-attachment-daily-bandwidth-limit` is the total daily attachment download/upload bandwidth limit per visitor,
including PUT and GET requests. This is to protect your precious bandwidth from abuse, since egress costs money in
most cloud providers. This defaults to 500M.
### E-mail limits
-Similarly to the request limit, there is also an e-mail limit (only relevant if [e-mail notifications](#e-mail-notifications)
+
+Similarly to the request limit, there is also an e-mail limit (only relevant if [e-mail notifications](#e-mail-notifications)
are enabled):
-* `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16.
-* `visitor-email-limit-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h.
+- `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16.
+- `visitor-email-limit-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h.
### Firebase limits
-If [Firebase is configured](#firebase-fcm), all messages are also published to a Firebase topic (unless `Firebase: no`
+
+If [Firebase is configured](#firebase-fcm), all messages are also published to a Firebase topic (unless `Firebase: no`
is set). Firebase enforces [its own limits](https://firebase.google.com/docs/cloud-messaging/concept-options#topics_throttling)
-on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time
-of day. In practice, I have only ever observed `429 Quota exceeded` responses from Firebase if **too many messages are published to
-the same topic**.
+on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time
+of day. In practice, I have only ever observed `429 Quota exceeded` responses from Firebase if **too many messages are published to
+the same topic**.
In ntfy, if Firebase responds with a 429 after publishing to a topic, the visitor (= IP address) who published the message
is **banned from publishing to Firebase for 10 minutes** (not configurable). Because publishing to Firebase happens asynchronously,
@@ -946,11 +1004,13 @@ there is no indication of the user that this has happened. Non-Firebase subscrib
After the 10 minutes are up, messages forwarding to Firebase is resumed for this visitor.
If this ever happens, there will be a log message that looks something like this:
+
```
WARN Firebase quota exceeded (likely for topic), temporarily denying Firebase access to visitor
```
### Subscriber-based rate limiting
+
By default, ntfy puts almost all rate limits on the message publisher, e.g. number of messages, requests, and attachment
size are all based on the visitor who publishes a message. **Subscriber-based rate limiting is a way to use the rate limits
of a topic's subscriber, instead of the limits of the publisher.**
@@ -964,23 +1024,25 @@ HTTP stream, or websockets, thereby registering itself as the "rate visitor", i.
to use when publishing on this topic. Note that setting the rate visitor requires **read-write permission** on the topic.
UnifiedPush only: If this setting is enabled, publishing to UnifiedPush topics will lead to an `HTTP 507 Insufficient Storage`
-response if no "rate visitor" has been previously registered. This is to avoid burning the publisher's
+response if no "rate visitor" has been previously registered. This is to avoid burning the publisher's
`visitor-message-daily-limit`.
To enable subscriber-based rate limiting, set `visitor-subscriber-rate-limiting: true`.
## Tuning for scale
+
If you're running ntfy for your home server, you probably don't need to worry about scale at all. In its default config,
if it's not behind a proxy, the ntfy server can keep about **as many connections as the open file limit allows**.
This limit is typically called `nofile`. Other than that, RAM and CPU are obviously relevant. You may also want to check
out [this discussion on Reddit](https://www.reddit.com/r/golang/comments/r9u4ee/how_many_actively_connected_http_clients_can_a_go/).
-Depending on *how you run it*, here are a few limits that are relevant:
+Depending on _how you run it_, here are a few limits that are relevant:
### Message cache
+
By default, the [message cache](#message-cache) (defined by `cache-file`) uses the SQLite default settings, which means it
syncs to disk on every write. For personal servers, this is perfectly adequate. For larger installations, such as ntfy.sh,
-the [write-ahead log (WAL)](https://sqlite.org/wal.html) should be enabled, and the sync mode should be adjusted.
+the [write-ahead log (WAL)](https://sqlite.org/wal.html) should be enabled, and the sync mode should be adjusted.
See [this article](https://phiresky.github.io/blog/2020/sqlite-performance-tuning/) for details.
In addition to that, for very high load servers (such as ntfy.sh), it may be beneficial to write messages to the cache
@@ -989,48 +1051,54 @@ seeing `database locked` messages in the logs, you should probably enable that.
Here's how ntfy.sh has been tuned in the `server.yml` file:
-``` yaml
+```yaml
cache-batch-size: 25
cache-batch-timeout: "1s"
cache-startup-queries: |
- pragma journal_mode = WAL;
- pragma synchronous = normal;
- pragma temp_store = memory;
- pragma busy_timeout = 15000;
- vacuum;
+ pragma journal_mode = WAL;
+ pragma synchronous = normal;
+ pragma temp_store = memory;
+ pragma busy_timeout = 15000;
+ vacuum;
```
### For systemd services
+
If you're running ntfy in a systemd service (e.g. for .deb/.rpm packages), the main limiting factor is the
`LimitNOFILE` setting in the systemd unit. The default open files limit for `ntfy.service` is 10,000. You can override it
by creating a `/etc/systemd/system/ntfy.service.d/override.conf` file. As far as I can tell, `/etc/security/limits.conf`
is not relevant.
=== "/etc/systemd/system/ntfy.service.d/override.conf"
- ```
+
+ ```ini
# Allow 20,000 ntfy connections (and give room for other file handles)
[Service]
LimitNOFILE=20500
```
### Outside of systemd
+
If you're running outside systemd, you may want to adjust your `/etc/security/limits.conf` file to
increase the `nofile` setting. Here's an example that increases the limit to 5,000. You can find out the current setting
by running `ulimit -n`, or manually override it temporarily by running `ulimit -n 50000`.
=== "/etc/security/limits.conf"
+
```
# Increase open files limit globally
* hard nofile 20500
```
### Proxy limits (nginx, Apache2)
+
If you are running [behind a proxy](#behind-a-proxy-tls-etc) (e.g. nginx, Apache), the open files limit of the proxy is also
relevant. So if your proxy runs inside of systemd, increase the limits in systemd for the proxy. Typically, the proxy
open files limit has to be **double the number of how many connections you'd like to support**, because the proxy has
to maintain the client connection and the connection to ntfy.
=== "/etc/nginx/nginx.conf"
+
```
events {
# Allow 40,000 proxy connections (2x of the desired ntfy connection count;
@@ -1040,6 +1108,7 @@ to maintain the client connection and the connection to ntfy.
```
=== "/etc/systemd/system/nginx.service.d/override.conf"
+
```
# Allow 40,000 proxy connections (2x of the desired ntfy connection count;
# and give room for other file handles)
@@ -1048,18 +1117,20 @@ to maintain the client connection and the connection to ntfy.
```
### Banning bad actors (fail2ban)
+
If you put stuff on the Internet, bad actors will try to break them or break in. [fail2ban](https://www.fail2ban.org/)
and nginx's [ngx_http_limit_req_module module](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html) can be used
to ban client IPs if they misbehave. This is on top of the [rate limiting](#rate-limiting) inside the ntfy server.
-Here's an example for how ntfy.sh is configured, following the instructions from two tutorials ([here](https://easyengine.io/tutorials/nginx/fail2ban/)
+Here's an example for how ntfy.sh is configured, following the instructions from two tutorials ([here](https://easyengine.io/tutorials/nginx/fail2ban/)
and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-attack/)):
=== "/etc/nginx/nginx.conf"
+
```
# Rate limit all IP addresses
http {
- limit_req_zone $binary_remote_addr zone=one:10m rate=45r/m;
+ limit_req_zone $binary_remote_addr zone=one:10m rate=45r/m;
}
# Alternatively, whitelist certain IP addresses
@@ -1079,16 +1150,18 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
```
=== "/etc/nginx/sites-enabled/ntfy.sh"
+
```
# For each server/location block
server {
location / {
limit_req zone=one burst=1000 nodelay;
}
- }
+ }
```
=== "/etc/fail2ban/filter.d/nginx-req-limit.conf"
+
```
[Definition]
failregex = limiting requests, excess:.* by zone.*client:
@@ -1096,7 +1169,8 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
```
=== "/etc/fail2ban/jail.local"
- ```
+
+ ```ini
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
@@ -1108,16 +1182,18 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
```
## Health checks
+
A preliminary health check API endpoint is exposed at `/v1/health`. The endpoint returns a `json` response in the format shown below.
If a non-200 HTTP status code is returned or if the returned `health` field is `false` the ntfy service should be considered as unhealthy.
```json
-{"health":true}
+{ "health": true }
```
See [Installation for Docker](install.md#docker) for an example of how this could be used in a `docker-compose` environment.
## Monitoring
+
If configured, ntfy can expose a `/metrics` endpoint for [Prometheus](https://prometheus.io/), which can then be used to
create dashboards and alerts (e.g. via [Grafana](https://grafana.com/)).
@@ -1130,11 +1206,13 @@ doing, and/or secure access to the endpoint in your reverse proxy.
enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
=== "server.yml (Using default port)"
+
```yaml
enable-metrics: true
```
=== "server.yml (Using dedicated IP/port)"
+
```yaml
metrics-listen-http: "10.0.1.1:9090"
```
@@ -1142,6 +1220,7 @@ doing, and/or secure access to the endpoint in your reverse proxy.
In Prometheus, an example scrape config would look like this:
=== "prometheus.yml"
+
```yaml
scrape_configs:
- job_name: "ntfy"
@@ -1157,11 +1236,13 @@ Here's an example Grafana dashboard built from the metrics (see [Grafana JSON on
## Profiling
-ntfy can expose Go's [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoints to support profiling of the ntfy server.
+
+ntfy can expose Go's [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoints to support profiling of the ntfy server.
If enabled, ntfy will listen on a dedicated listen IP/port, which can be accessed via the web browser on `http://:/debug/pprof/`.
This can be helpful to expose bottlenecks, and visualize call flows. To enable, simply set the `profile-listen-http` config option.
## Logging & debugging
+
By default, ntfy logs to the console (stderr), with an `info` log level, and in a human-readable text format.
ntfy supports five different log levels, can also write to a file, log as JSON, and even supports granular
@@ -1170,34 +1251,36 @@ by calling `kill -HUP $pid` or `systemctl reload ntfy`.
The following config options define the logging behavior:
-* `log-format` defines the output format, can be `text` (default) or `json`
-* `log-file` is a filename to write logs to. If this is not set, ntfy logs to stderr.
-* `log-level` defines the default log level, can be one of `trace`, `debug`, `info` (default), `warn` or `error`.
+- `log-format` defines the output format, can be `text` (default) or `json`
+- `log-file` is a filename to write logs to. If this is not set, ntfy logs to stderr.
+- `log-level` defines the default log level, can be one of `trace`, `debug`, `info` (default), `warn` or `error`.
Be aware that `debug` (and particularly `trace`) can be **very verbose**. Only turn them on briefly for debugging purposes.
-* `log-level-overrides` lets you override the log level if certain fields match. This is incredibly powerful
+- `log-level-overrides` lets you override the log level if certain fields match. This is incredibly powerful
for debugging certain parts of the system (e.g. only the account management, or only a certain visitor).
This is an array of strings in the format:
- - `field=value -> level` to match a value exactly, e.g. `tag=manager -> trace`
- - `field -> level` to match any value, e.g. `time_taken_ms -> debug`
+ - `field=value -> level` to match a value exactly, e.g. `tag=manager -> trace`
+ - `field -> level` to match any value, e.g. `time_taken_ms -> debug`
**Logging config (good for production use):**
-``` yaml
+
+```yaml
log-level: info
log-format: json
log-file: /var/log/ntfy.log
```
-**Temporary debugging:**
+**Temporary debugging:**
If something's not working right, you can debug/trace through what the ntfy server is doing by setting the `log-level`
to `debug` or `trace`. The `debug` setting will output information about each published message, but not the message
contents. The `trace` setting will also print the message contents.
-Alternatively, you can set `log-level-overrides` for only certain fields, such as a visitor's IP address (`visitor_ip`),
-a username (`user_name`), or a tag (`tag`). There are dozens of fields you can use to override log levels. To learn what
+Alternatively, you can set `log-level-overrides` for only certain fields, such as a visitor's IP address (`visitor_ip`),
+a username (`user_name`), or a tag (`tag`). There are dozens of fields you can use to override log levels. To learn what
they are, either turn the log-level to `trace` and observe, or reference the [source code](https://github.com/binwiederhier/ntfy).
Here's an example that will output only `info` log events, except when they match either of the defined overrides:
-``` yaml
+
+```yaml
log-level: info
log-level-overrides:
- "tag=manager -> trace"
@@ -1206,11 +1289,11 @@ log-level-overrides:
```
!!! warning
- The `debug` and `trace` log levels are very verbose, and using `log-level-overrides` has a
- performance penalty. Only use it for temporary debugging.
+The `debug` and `trace` log levels are very verbose, and using `log-level-overrides` has a
+performance penalty. Only use it for temporary debugging.
-You can also hot-reload the `log-level` and `log-level-overrides` by sending the `SIGHUP` signal to the process after
-editing the `server.yml` file. You can do so by calling `systemctl reload ntfy` (if ntfy is running inside systemd),
+You can also hot-reload the `log-level` and `log-level-overrides` by sending the `SIGHUP` signal to the process after
+editing the `server.yml` file. You can do so by calling `systemctl reload ntfy` (if ntfy is running inside systemd),
or by calling `kill -HUP $(pidof ntfy)`. If successful, you'll see something like this:
```
@@ -1221,76 +1304,78 @@ $ ntfy serve
```
## Config options
+
Each config option can be set in the config file `/etc/ntfy/server.yml` (e.g. `listen-http: :80`) or as a
CLI option (e.g. `--listen-http :80`. Here's a list of all available options. Alternatively, you can set an environment
variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
!!! info
- All config options can also be defined in the `server.yml` file using underscores instead of dashes, e.g.
- `cache_duration` and `cache-duration` are both supported. This is to support stricter YAML parsers that do
- not support dashes.
+All config options can also be defined in the `server.yml` file using underscores instead of dashes, e.g.
+`cache_duration` and `cache-duration` are both supported. This is to support stricter YAML parsers that do
+not support dashes.
| Config option | Env variable | Format | Default | Description |
-|--------------------------------------------|-------------------------------------------------|-----------------------------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `base-url` | `NTFY_BASE_URL` | *URL* | - | Public facing base URL of the service (e.g. `https://ntfy.sh`) |
+| ------------------------------------------ | ----------------------------------------------- | --------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `base-url` | `NTFY_BASE_URL` | _URL_ | - | Public facing base URL of the service (e.g. `https://ntfy.sh`) |
| `listen-http` | `NTFY_LISTEN_HTTP` | `[host]:port` | `:80` | Listen address for the HTTP web server |
| `listen-https` | `NTFY_LISTEN_HTTPS` | `[host]:port` | - | Listen address for the HTTPS web server. If set, you also need to set `key-file` and `cert-file`. |
-| `listen-unix` | `NTFY_LISTEN_UNIX` | *filename* | - | Path to a Unix socket to listen on |
-| `listen-unix-mode` | `NTFY_LISTEN_UNIX_MODE` | *file mode* | *system default* | File mode of the Unix socket, e.g. 0700 or 0777 |
-| `key-file` | `NTFY_KEY_FILE` | *filename* | - | HTTPS/TLS private key file, only used if `listen-https` is set. |
-| `cert-file` | `NTFY_CERT_FILE` | *filename* | - | HTTPS/TLS certificate file, only used if `listen-https` is set. |
-| `firebase-key-file` | `NTFY_FIREBASE_KEY_FILE` | *filename* | - | If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. This is optional and only required to save battery when using the Android app. See [Firebase (FCM](#firebase-fcm). |
-| `cache-file` | `NTFY_CACHE_FILE` | *filename* | - | If set, messages are cached in a local SQLite database instead of only in-memory. This allows for service restarts without losing messages in support of the since= parameter. See [message cache](#message-cache). |
-| `cache-duration` | `NTFY_CACHE_DURATION` | *duration* | 12h | Duration for which messages will be buffered before they are deleted. This is required to support the `since=...` and `poll=1` parameter. Set this to `0` to disable the cache entirely. |
-| `cache-startup-queries` | `NTFY_CACHE_STARTUP_QUERIES` | *string (SQL queries)* | - | SQL queries to run during database startup; this is useful for tuning and [enabling WAL mode](#wal-for-message-cache) |
-| `cache-batch-size` | `NTFY_CACHE_BATCH_SIZE` | *int* | 0 | Max size of messages to batch together when writing to message cache (if zero, writes are synchronous) |
-| `cache-batch-timeout` | `NTFY_CACHE_BATCH_TIMEOUT` | *duration* | 0s | Timeout for batched async writes to the message cache (if zero, writes are synchronous) |
-| `auth-file` | `NTFY_AUTH_FILE` | *filename* | - | Auth database file used for access control. If set, enables authentication and access control. See [access control](#access-control). |
+| `listen-unix` | `NTFY_LISTEN_UNIX` | _filename_ | - | Path to a Unix socket to listen on |
+| `listen-unix-mode` | `NTFY_LISTEN_UNIX_MODE` | _file mode_ | _system default_ | File mode of the Unix socket, e.g. 0700 or 0777 |
+| `key-file` | `NTFY_KEY_FILE` | _filename_ | - | HTTPS/TLS private key file, only used if `listen-https` is set. |
+| `cert-file` | `NTFY_CERT_FILE` | _filename_ | - | HTTPS/TLS certificate file, only used if `listen-https` is set. |
+| `firebase-key-file` | `NTFY_FIREBASE_KEY_FILE` | _filename_ | - | If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. This is optional and only required to save battery when using the Android app. See [Firebase (FCM](#firebase-fcm). |
+| `cache-file` | `NTFY_CACHE_FILE` | _filename_ | - | If set, messages are cached in a local SQLite database instead of only in-memory. This allows for service restarts without losing messages in support of the since= parameter. See [message cache](#message-cache). |
+| `cache-duration` | `NTFY_CACHE_DURATION` | _duration_ | 12h | Duration for which messages will be buffered before they are deleted. This is required to support the `since=...` and `poll=1` parameter. Set this to `0` to disable the cache entirely. |
+| `cache-startup-queries` | `NTFY_CACHE_STARTUP_QUERIES` | _string (SQL queries)_ | - | SQL queries to run during database startup; this is useful for tuning and [enabling WAL mode](#wal-for-message-cache) |
+| `cache-batch-size` | `NTFY_CACHE_BATCH_SIZE` | _int_ | 0 | Max size of messages to batch together when writing to message cache (if zero, writes are synchronous) |
+| `cache-batch-timeout` | `NTFY_CACHE_BATCH_TIMEOUT` | _duration_ | 0s | Timeout for batched async writes to the message cache (if zero, writes are synchronous) |
+| `auth-file` | `NTFY_AUTH_FILE` | _filename_ | - | Auth database file used for access control. If set, enables authentication and access control. See [access control](#access-control). |
| `auth-default-access` | `NTFY_AUTH_DEFAULT_ACCESS` | `read-write`, `read-only`, `write-only`, `deny-all` | `read-write` | Default permissions if no matching entries in the auth database are found. Default is `read-write`. |
-| `behind-proxy` | `NTFY_BEHIND_PROXY` | *bool* | false | If set, the X-Forwarded-For header is used to determine the visitor IP address instead of the remote address of the connection. |
-| `attachment-cache-dir` | `NTFY_ATTACHMENT_CACHE_DIR` | *directory* | - | Cache directory for attached files. To enable attachments, this has to be set. |
-| `attachment-total-size-limit` | `NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT` | *size* | 5G | Limit of the on-disk attachment cache directory. If the limits is exceeded, new attachments will be rejected. |
-| `attachment-file-size-limit` | `NTFY_ATTACHMENT_FILE_SIZE_LIMIT` | *size* | 15M | Per-file attachment size limit (e.g. 300k, 2M, 100M). Larger attachment will be rejected. |
-| `attachment-expiry-duration` | `NTFY_ATTACHMENT_EXPIRY_DURATION` | *duration* | 3h | Duration after which uploaded attachments will be deleted (e.g. 3h, 20h). Strongly affects `visitor-attachment-total-size-limit`. |
+| `behind-proxy` | `NTFY_BEHIND_PROXY` | _bool_ | false | If set, the X-Forwarded-For header is used to determine the visitor IP address instead of the remote address of the connection. |
+| `attachment-cache-dir` | `NTFY_ATTACHMENT_CACHE_DIR` | _directory_ | - | Cache directory for attached files. To enable attachments, this has to be set. |
+| `attachment-total-size-limit` | `NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT` | _size_ | 5G | Limit of the on-disk attachment cache directory. If the limits is exceeded, new attachments will be rejected. |
+| `attachment-file-size-limit` | `NTFY_ATTACHMENT_FILE_SIZE_LIMIT` | _size_ | 15M | Per-file attachment size limit (e.g. 300k, 2M, 100M). Larger attachment will be rejected. |
+| `attachment-expiry-duration` | `NTFY_ATTACHMENT_EXPIRY_DURATION` | _duration_ | 3h | Duration after which uploaded attachments will be deleted (e.g. 3h, 20h). Strongly affects `visitor-attachment-total-size-limit`. |
| `smtp-sender-addr` | `NTFY_SMTP_SENDER_ADDR` | `host:port` | - | SMTP server address to allow email sending |
-| `smtp-sender-user` | `NTFY_SMTP_SENDER_USER` | *string* | - | SMTP user; only used if e-mail sending is enabled |
-| `smtp-sender-pass` | `NTFY_SMTP_SENDER_PASS` | *string* | - | SMTP password; only used if e-mail sending is enabled |
-| `smtp-sender-from` | `NTFY_SMTP_SENDER_FROM` | *e-mail address* | - | SMTP sender e-mail address; only used if e-mail sending is enabled |
+| `smtp-sender-user` | `NTFY_SMTP_SENDER_USER` | _string_ | - | SMTP user; only used if e-mail sending is enabled |
+| `smtp-sender-pass` | `NTFY_SMTP_SENDER_PASS` | _string_ | - | SMTP password; only used if e-mail sending is enabled |
+| `smtp-sender-from` | `NTFY_SMTP_SENDER_FROM` | _e-mail address_ | - | SMTP sender e-mail address; only used if e-mail sending is enabled |
| `smtp-server-listen` | `NTFY_SMTP_SERVER_LISTEN` | `[ip]:port` | - | Defines the IP address and port the SMTP server will listen on, e.g. `:25` or `1.2.3.4:25` |
-| `smtp-server-domain` | `NTFY_SMTP_SERVER_DOMAIN` | *domain name* | - | SMTP server e-mail domain, e.g. `ntfy.sh` |
-| `smtp-server-addr-prefix` | `NTFY_SMTP_SERVER_ADDR_PREFIX` | *string* | - | Optional prefix for the e-mail addresses to prevent spam, e.g. `ntfy-` |
-| `twilio-account` | `NTFY_TWILIO_ACCOUNT` | *string* | - | Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586 |
-| `twilio-auth-token` | `NTFY_TWILIO_AUTH_TOKEN` | *string* | - | Twilio auth token, e.g. affebeef258625862586258625862586 |
-| `twilio-phone-number` | `NTFY_TWILIO_PHONE_NUMBER` | *string* | - | Twilio outgoing phone number, e.g. +18775132586 |
-| `twilio-verify-service` | `NTFY_TWILIO_VERIFY_SERVICE` | *string* | - | Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586 |
-| `keepalive-interval` | `NTFY_KEEPALIVE_INTERVAL` | *duration* | 45s | Interval in which keepalive messages are sent to the client. This is to prevent intermediaries closing the connection for inactivity. Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. |
-| `manager-interval` | `NTFY_MANAGER_INTERVAL` | *duration* | 1m | Interval in which the manager prunes old messages, deletes topics and prints the stats. |
-| `global-topic-limit` | `NTFY_GLOBAL_TOPIC_LIMIT` | *number* | 15,000 | Rate limiting: Total number of topics before the server rejects new topics. |
-| `upstream-base-url` | `NTFY_UPSTREAM_BASE_URL` | *URL* | `https://ntfy.sh` | Forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers |
-| `upstream-access-token` | `NTFY_UPSTREAM_ACCESS_TOKEN` | *string* | `tk_zyYLYj...` | Access token to use for the upstream server; needed only if upstream rate limits are exceeded or upstream server requires auth |
-| `visitor-attachment-total-size-limit` | `NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT` | *size* | 100M | Rate limiting: Total storage limit used for attachments per visitor, for all attachments combined. Storage is freed after attachments expire. See `attachment-expiry-duration`. |
-| `visitor-attachment-daily-bandwidth-limit` | `NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT` | *size* | 500M | Rate limiting: Total daily attachment download/upload traffic limit per visitor. This is to protect your bandwidth costs from exploding. |
-| `visitor-email-limit-burst` | `NTFY_VISITOR_EMAIL_LIMIT_BURST` | *number* | 16 | Rate limiting:Initial limit of e-mails per visitor |
-| `visitor-email-limit-replenish` | `NTFY_VISITOR_EMAIL_LIMIT_REPLENISH` | *duration* | 1h | Rate limiting: Strongly related to `visitor-email-limit-burst`: The rate at which the bucket is refilled |
-| `visitor-message-daily-limit` | `NTFY_VISITOR_MESSAGE_DAILY_LIMIT` | *number* | - | Rate limiting: Allowed number of messages per day per visitor, reset every day at midnight (UTC). By default, this value is unset. |
-| `visitor-request-limit-burst` | `NTFY_VISITOR_REQUEST_LIMIT_BURST` | *number* | 60 | Rate limiting: Allowed GET/PUT/POST requests per second, per visitor. This setting is the initial bucket of requests each visitor has |
-| `visitor-request-limit-replenish` | `NTFY_VISITOR_REQUEST_LIMIT_REPLENISH` | *duration* | 5s | Rate limiting: Strongly related to `visitor-request-limit-burst`: The rate at which the bucket is refilled |
-| `visitor-request-limit-exempt-hosts` | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS` | *comma-separated host/IP list* | - | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting |
-| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
-| `visitor-subscriber-rate-limiting` | `NTFY_VISITOR_SUBSCRIBER_RATE_LIMITING` | *bool* | `false` | Rate limiting: Enables subscriber-based rate limiting |
-| `web-root` | `NTFY_WEB_ROOT` | *path*, e.g. `/` or `/app`, or `disable` | `/` | Sets root of the web app (e.g. /, or /app), or disables it entirely (disable) |
-| `enable-signup` | `NTFY_ENABLE_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
-| `enable-login` | `NTFY_ENABLE_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
-| `enable-reservations` | `NTFY_ENABLE_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
-| `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | *string* | - | Payments: Key used for the Stripe API communication, this enables payments |
-| `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | *string* | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe |
-| `billing-contact` | `NTFY_BILLING_CONTACT` | *email address* or *website* | - | Payments: Email or website displayed in Upgrade dialog as a billing contact |
+| `smtp-server-domain` | `NTFY_SMTP_SERVER_DOMAIN` | _domain name_ | - | SMTP server e-mail domain, e.g. `ntfy.sh` |
+| `smtp-server-addr-prefix` | `NTFY_SMTP_SERVER_ADDR_PREFIX` | _string_ | - | Optional prefix for the e-mail addresses to prevent spam, e.g. `ntfy-` |
+| `twilio-account` | `NTFY_TWILIO_ACCOUNT` | _string_ | - | Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586 |
+| `twilio-auth-token` | `NTFY_TWILIO_AUTH_TOKEN` | _string_ | - | Twilio auth token, e.g. affebeef258625862586258625862586 |
+| `twilio-phone-number` | `NTFY_TWILIO_PHONE_NUMBER` | _string_ | - | Twilio outgoing phone number, e.g. +18775132586 |
+| `twilio-verify-service` | `NTFY_TWILIO_VERIFY_SERVICE` | _string_ | - | Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586 |
+| `keepalive-interval` | `NTFY_KEEPALIVE_INTERVAL` | _duration_ | 45s | Interval in which keepalive messages are sent to the client. This is to prevent intermediaries closing the connection for inactivity. Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. |
+| `manager-interval` | `NTFY_MANAGER_INTERVAL` | _duration_ | 1m | Interval in which the manager prunes old messages, deletes topics and prints the stats. |
+| `global-topic-limit` | `NTFY_GLOBAL_TOPIC_LIMIT` | _number_ | 15,000 | Rate limiting: Total number of topics before the server rejects new topics. |
+| `upstream-base-url` | `NTFY_UPSTREAM_BASE_URL` | _URL_ | `https://ntfy.sh` | Forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers |
+| `upstream-access-token` | `NTFY_UPSTREAM_ACCESS_TOKEN` | _string_ | `tk_zyYLYj...` | Access token to use for the upstream server; needed only if upstream rate limits are exceeded or upstream server requires auth |
+| `visitor-attachment-total-size-limit` | `NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT` | _size_ | 100M | Rate limiting: Total storage limit used for attachments per visitor, for all attachments combined. Storage is freed after attachments expire. See `attachment-expiry-duration`. |
+| `visitor-attachment-daily-bandwidth-limit` | `NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT` | _size_ | 500M | Rate limiting: Total daily attachment download/upload traffic limit per visitor. This is to protect your bandwidth costs from exploding. |
+| `visitor-email-limit-burst` | `NTFY_VISITOR_EMAIL_LIMIT_BURST` | _number_ | 16 | Rate limiting:Initial limit of e-mails per visitor |
+| `visitor-email-limit-replenish` | `NTFY_VISITOR_EMAIL_LIMIT_REPLENISH` | _duration_ | 1h | Rate limiting: Strongly related to `visitor-email-limit-burst`: The rate at which the bucket is refilled |
+| `visitor-message-daily-limit` | `NTFY_VISITOR_MESSAGE_DAILY_LIMIT` | _number_ | - | Rate limiting: Allowed number of messages per day per visitor, reset every day at midnight (UTC). By default, this value is unset. |
+| `visitor-request-limit-burst` | `NTFY_VISITOR_REQUEST_LIMIT_BURST` | _number_ | 60 | Rate limiting: Allowed GET/PUT/POST requests per second, per visitor. This setting is the initial bucket of requests each visitor has |
+| `visitor-request-limit-replenish` | `NTFY_VISITOR_REQUEST_LIMIT_REPLENISH` | _duration_ | 5s | Rate limiting: Strongly related to `visitor-request-limit-burst`: The rate at which the bucket is refilled |
+| `visitor-request-limit-exempt-hosts` | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS` | _comma-separated host/IP list_ | - | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting |
+| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | _number_ | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
+| `visitor-subscriber-rate-limiting` | `NTFY_VISITOR_SUBSCRIBER_RATE_LIMITING` | _bool_ | `false` | Rate limiting: Enables subscriber-based rate limiting |
+| `web-root` | `NTFY_WEB_ROOT` | _path_, e.g. `/` or `/app`, or `disable` | `/` | Sets root of the web app (e.g. /, or /app), or disables it entirely (disable) |
+| `enable-signup` | `NTFY_ENABLE_SIGNUP` | _boolean_ (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
+| `enable-login` | `NTFY_ENABLE_LOGIN` | _boolean_ (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
+| `enable-reservations` | `NTFY_ENABLE_RESERVATIONS` | _boolean_ (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
+| `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | _string_ | - | Payments: Key used for the Stripe API communication, this enables payments |
+| `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | _string_ | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe |
+| `billing-contact` | `NTFY_BILLING_CONTACT` | _email address_ or _website_ | - | Payments: Email or website displayed in Upgrade dialog as a billing contact |
-The format for a *duration* is: `(smh)`, e.g. 30s, 20m or 1h.
-The format for a *size* is: `(GMK)`, e.g. 1G, 200M or 4000k.
+The format for a _duration_ is: `(smh)`, e.g. 30s, 20m or 1h.
+The format for a _size_ is: `(GMK)`, e.g. 1G, 200M or 4000k.
## Command line options
-```
+
+```sh
$ ntfy serve --help
NAME:
ntfy serve - Run the ntfy server
@@ -1304,7 +1389,7 @@ CATEGORY:
DESCRIPTION:
Run the ntfy server and listen for incoming requests
- The command will load the configuration from /etc/ntfy/server.yml. Config options can
+ The command will load the configuration from /etc/ntfy/server.yml. Config options can
be overridden using the command line options.
Examples:
@@ -1368,7 +1453,6 @@ OPTIONS:
--behind-proxy, --behind_proxy, -P if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting) (default: false) [$NTFY_BEHIND_PROXY]
--stripe-secret-key value, --stripe_secret_key value key used for the Stripe API communication, this enables payments [$NTFY_STRIPE_SECRET_KEY]
--stripe-webhook-key value, --stripe_webhook_key value key required to validate the authenticity of incoming webhooks from Stripe [$NTFY_STRIPE_WEBHOOK_KEY]
- --billing-contact value, --billing_contact value e-mail or website to display in upgrade dialog (only if payments are enabled) [$NTFY_BILLING_CONTACT]
+ --billing-contact value, --billing_contact value e-mail or website to display in upgrade dialog (only if payments are enabled) [$NTFY_BILLING_CONTACT]
--help, -h show help (default: false)
```
-
diff --git a/docs/deprecations.md b/docs/deprecations.md
index 99cdeeb9..8951e786 100644
--- a/docs/deprecations.md
+++ b/docs/deprecations.md
@@ -1,30 +1,36 @@
# Deprecation notices
-This page is used to list deprecation notices for ntfy. Deprecated commands and options will be
+
+This page is used to list deprecation notices for ntfy. Deprecated commands and options will be
**removed after 1-3 months** from the time they were deprecated. How long the feature is deprecated
before the behavior is changed depends on the severity of the change, and how prominent the feature is.
## Active deprecations
+
_No active deprecations_
## Previous deprecations
### ntfy CLI: `ntfy publish --env-topic` will be removed
+
> Active since 2022-06-20, behavior changed with v1.30.1
The `ntfy publish --env-topic` option will be removed. It'll still be possible to specify a topic via the
`NTFY_TOPIC` environment variable, but it won't be necessary anymore to specify the `--env-topic` flag.
=== "Before"
- ```
+
+ ```sh
$ NTFY_TOPIC=mytopic ntfy publish --env-topic "this is the message"
```
=== "After"
- ```
+
+ ```sh
$ NTFY_TOPIC=mytopic ntfy publish "this is the message"
```
### Android app: WebSockets will become the default connection protocol
+
> Active since 2022-03-13, behavior will not change (deprecation removed 2022-06-20)
Instant delivery connections and connections to self-hosted servers in the Android app were going to switch
@@ -32,14 +38,16 @@ to use the WebSockets protocol by default. It was decided to keep JSON stream as
and add a notice banner in the Android app instead.
### Android app: Using `since=` instead of `since=`
+
> Active since 2022-02-27, behavior changed with v1.14.0
-The Android app started using `since=` instead of `since=`, which means as of Android app v1.14.0,
+The Android app started using `since=` instead of `since=`, which means as of Android app v1.14.0,
it will not work with servers older than v1.16.0 anymore. This is to simplify handling of deduplication in the Android app.
The `since=` endpoint will continue to work. This is merely a notice that the Android app behavior will change.
### Running server via `ntfy` (instead of `ntfy serve`)
+
> Deprecated 2021-12-17, behavior changed with v1.10.0
As more commands are added to the `ntfy` CLI tool, using just `ntfy` to run the server is not practical
@@ -47,14 +55,15 @@ anymore. Please use `ntfy serve` instead. This also applies to Docker images, as
just the server.
=== "Before"
- ```
+
+ ```sh
$ ntfy
2021/12/17 08:16:01 Listening on :80/http
```
=== "After"
- ```
+
+ ```sh
$ ntfy serve
2021/12/17 08:16:01 Listening on :80/http
```
-
diff --git a/docs/develop.md b/docs/develop.md
index baab3f3a..917eb254 100644
--- a/docs/develop.md
+++ b/docs/develop.md
@@ -1,50 +1,53 @@
# Development
+
Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎
-I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't
+I tried my very best to write up detailed instructions, but if at any point in time you run into issues, don't
hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)**.
## ntfy server
+
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the
server consists of three components:
-* **The main server/client** is written in [Go](https://go.dev/) (so you'll need Go). Its main entrypoint is at
- [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go), and the meat you're likely interested in is
- in [server.go](https://github.com/binwiederhier/ntfy/blob/main/server/server.go). Notably, the server uses a
- [SQLite](https://sqlite.org) library called [go-sqlite3](https://github.com/mattn/go-sqlite3), which requires
+- **The main server/client** is written in [Go](https://go.dev/) (so you'll need Go). Its main entrypoint is at
+ [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go), and the meat you're likely interested in is
+ in [server.go](https://github.com/binwiederhier/ntfy/blob/main/server/server.go). Notably, the server uses a
+ [SQLite](https://sqlite.org) library called [go-sqlite3](https://github.com/mattn/go-sqlite3), which requires
[Cgo](https://go.dev/blog/cgo) and `CGO_ENABLED=1` to be set. Otherwise things will not work (see below).
-* **The documentation** is generated by [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/),
+- **The documentation** is generated by [MkDocs](https://www.mkdocs.org/) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/),
which is written in [Python](https://www.python.org/). You'll need Python and MkDocs (via `pip`) only if you want to
build the docs.
-* **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Create React App](https://create-react-app.dev/)
- to build the production build. If you want to modify the web app, you need [nodejs](https://nodejs.org/en/) (for `npm`)
- and install all the 100,000 dependencies (*sigh*).
+- **The web app** is written in [React](https://reactjs.org/), using [MUI](https://mui.com/). It uses [Create React App](https://create-react-app.dev/)
+ to build the production build. If you want to modify the web app, you need [nodejs](https://nodejs.org/en/) (for `npm`)
+ and install all the 100,000 dependencies (_sigh_).
-All of these components are built and then **baked into one binary**.
+All of these components are built and then **baked into one binary**.
### Navigating the code
+
Code:
-* [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go) - Main entrypoint into the CLI, for both server and client
-* [cmd/](https://github.com/binwiederhier/ntfy/tree/main/cmd) - CLI commands, such as `serve` or `publish`
-* [server/](https://github.com/binwiederhier/ntfy/tree/main/server) - The meat of the server logic
-* [docs/](https://github.com/binwiederhier/ntfy/tree/main/docs) - The [MkDocs](https://www.mkdocs.org/) documentation, also see `mkdocs.yml`
-* [web/](https://github.com/binwiederhier/ntfy/tree/main/web) - The [React](https://reactjs.org/) application, also see `web/package.json`
+- [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go) - Main entrypoint into the CLI, for both server and client
+- [cmd/](https://github.com/binwiederhier/ntfy/tree/main/cmd) - CLI commands, such as `serve` or `publish`
+- [server/](https://github.com/binwiederhier/ntfy/tree/main/server) - The meat of the server logic
+- [docs/](https://github.com/binwiederhier/ntfy/tree/main/docs) - The [MkDocs](https://www.mkdocs.org/) documentation, also see `mkdocs.yml`
+- [web/](https://github.com/binwiederhier/ntfy/tree/main/web) - The [React](https://reactjs.org/) application, also see `web/package.json`
Build related:
-* [Makefile](https://github.com/binwiederhier/ntfy/blob/main/Makefile) - Main entrypoint for all things related to building
-* [.goreleaser.yml](https://github.com/binwiederhier/ntfy/blob/main/.goreleaser.yml) - Describes all build outputs (for [GoReleaser](https://goreleaser.com/))
-* [go.mod](https://github.com/binwiederhier/ntfy/blob/main/go.mod) - Go modules dependency file
-* [mkdocs.yml](https://github.com/binwiederhier/ntfy/blob/main/mkdocs.yml) - Config file for the docs (for [MkDocs](https://www.mkdocs.org/))
-* [web/package.json](https://github.com/binwiederhier/ntfy/blob/main/web/package.json) - Build and dependency file for web app (for npm)
-
+- [Makefile](https://github.com/binwiederhier/ntfy/blob/main/Makefile) - Main entrypoint for all things related to building
+- [.goreleaser.yml](https://github.com/binwiederhier/ntfy/blob/main/.goreleaser.yml) - Describes all build outputs (for [GoReleaser](https://goreleaser.com/))
+- [go.mod](https://github.com/binwiederhier/ntfy/blob/main/go.mod) - Go modules dependency file
+- [mkdocs.yml](https://github.com/binwiederhier/ntfy/blob/main/mkdocs.yml) - Config file for the docs (for [MkDocs](https://www.mkdocs.org/))
+- [web/package.json](https://github.com/binwiederhier/ntfy/blob/main/web/package.json) - Build and dependency file for web app (for npm)
The `web/` and `docs/` folder are the sources for web app and documentation. During the build process,
the generated output is copied to `server/site` (web app and landing page) and `server/docs` (documentation).
### Build/test on Gitpod
-To get a quick working development environment you can use [Gitpod](https://gitpod.io), an in-browser IDE
+
+To get a quick working development environment you can use [Gitpod](https://gitpod.io), an in-browser IDE
that makes it easy to develop ntfy without having to set up a desktop IDE. For any real development,
I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
@@ -52,19 +55,21 @@ I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
### Build requirements
-* [Go](https://go.dev/) (required for main server)
-* [gcc](https://gcc.gnu.org/) (required main server, for SQLite cgo-based bindings)
-* [Make](https://www.gnu.org/software/make/) (required for convenience)
-* [libsqlite3/libsqlite3-dev](https://www.sqlite.org/) (required for main server, for SQLite cgo-based bindings)
-* [GoReleaser](https://goreleaser.com/) (required for a proper main server build)
-* [Python](https://www.python.org/) (for `pip`, only to build the docs)
-* [nodejs](https://nodejs.org/en/) (for `npm`, only to build the web app)
+- [Go](https://go.dev/) (required for main server)
+- [gcc](https://gcc.gnu.org/) (required main server, for SQLite cgo-based bindings)
+- [Make](https://www.gnu.org/software/make/) (required for convenience)
+- [libsqlite3/libsqlite3-dev](https://www.sqlite.org/) (required for main server, for SQLite cgo-based bindings)
+- [GoReleaser](https://goreleaser.com/) (required for a proper main server build)
+- [Python](https://www.python.org/) (for `pip`, only to build the docs)
+- [nodejs](https://nodejs.org/en/) (for `npm`, only to build the web app)
### Install dependencies
+
These steps **assume Ubuntu**. Steps may vary on different Linux distributions.
First, install [Go](https://go.dev/) (see [official instructions](https://go.dev/doc/install)):
-``` shell
+
+```shell
wget https://go.dev/dl/go1.19.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.19.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
@@ -72,20 +77,23 @@ go version # verifies that it worked
```
Install [GoReleaser](https://goreleaser.com/) (see [official instructions](https://goreleaser.com/install/)):
-``` shell
+
+```shell
go install github.com/goreleaser/goreleaser@latest
goreleaser -v # verifies that it worked
```
Install [nodejs](https://nodejs.org/en/) (see [official instructions](https://nodejs.org/en/download/package-manager/)):
-``` shell
+
+```shell
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
npm -v # verifies that it worked
```
Then install a few other things required:
-``` shell
+
+```shell
sudo apt install \
build-essential \
libsqlite3-dev \
@@ -96,26 +104,30 @@ sudo apt install \
```
### Check out code
+
Now check out via git from the [GitHub repository](https://github.com/binwiederhier/ntfy):
=== "via HTTPS"
- ``` shell
+
+ ```shell
git clone https://github.com/binwiederhier/ntfy.git
cd ntfy
```
=== "via SSH"
- ``` shell
- git clone git@github.com:binwiederhier/ntfy.git
+
+ ```shell
+ git clone git@github.com:binwiederhier/ntfy.git
cd ntfy
```
### Build all the things
-Now you can finally build everything. There are tons of `make` targets, so maybe just review what's there first
+
+Now you can finally build everything. There are tons of `make` targets, so maybe just review what's there first
by typing `make`:
-``` shell
-$ make
+```shell
+$ make
Typical commands (more see below):
make build - Build web app, documentation and server/client (sloowwww)
make cli-linux-amd64 - Build server/client binary (amd64, no web app or docs)
@@ -126,20 +138,20 @@ Typical commands (more see below):
...
```
-If you want to build the **ntfy binary including web app and docs for all supported architectures** (amd64, armv7, and arm64),
+If you want to build the **ntfy binary including web app and docs for all supported architectures** (amd64, armv7, and arm64),
you can simply run `make build`:
-``` shell
+```shell
$ make build
...
-# This builds web app, docs, and the ntfy binary (for amd64, armv7 and arm64).
+# This builds web app, docs, and the ntfy binary (for amd64, armv7 and arm64).
# This will be SLOW (5+ minutes on my laptop on the first run). Maybe look at the other make targets?
```
You'll see all the outputs in the `dist/` folder afterwards:
-``` bash
-$ find dist
+```bash
+$ find dist
dist
dist/metadata.json
dist/ntfy_arm64_linux_arm64
@@ -152,10 +164,10 @@ dist/config.yaml
dist/artifacts.json
```
-If you also want to build the **Debian/RPM packages and the Docker images for all supported architectures**, you can
+If you also want to build the **Debian/RPM packages and the Docker images for all supported architectures**, you can
use the `make release-snapshot` target:
-``` shell
+```shell
$ make release-snapshot
...
# This will be REALLY SLOW (sometimes 5+ minutes on my laptop)
@@ -167,15 +179,16 @@ During development, you may want to be more picky and build only certain things.
This is useful to test the final build with web app, docs, and server without any dependencies locally
-``` shell
+```shell
$ make docker-dev
$ docker run --rm -p 80:80 binwiederhier/ntfy:dev serve
```
### Build the ntfy binary
+
To build only the `ntfy` binary **without the web app or documentation**, use the `make cli-...` targets:
-``` shell
+```shell
$ make
Build server & client (using GoReleaser, not release version):
make cli - Build server & client (all architectures)
@@ -191,15 +204,15 @@ So if you're on an amd64/x86_64-based machine, you may just want to run `make cl
system, this shouldn't take longer than 5-10 seconds. I often combine it with `install-linux-amd64` so I can run the binary
right away:
-``` shell
+```shell
$ make cli-linux-amd64 install-linux-amd64
$ ntfy serve
```
-**During development of the main app, you can also just use `go run main.go`**, as long as you run
+**During development of the main app, you can also just use `go run main.go`**, as long as you run
`make cli-deps-static-sites`at least once and `CGO_ENABLED=1`:
-``` shell
+```shell
$ export CGO_ENABLED=1
$ make cli-deps-static-sites
$ go run main.go serve
@@ -207,7 +220,8 @@ $ go run main.go serve
...
```
-If you don't run `cli-deps-static-sites`, you may see an error *`pattern ...: no matching files found`*:
+If you don't run `cli-deps-static-sites`, you may see an error _`pattern ...: no matching files found`_:
+
```
$ go run main.go serve
server/server.go:85:13: pattern docs: no matching files found
@@ -217,41 +231,43 @@ This is because we use `go:embed` to embed the documentation and web app, so the
present at `server/docs` and `server/site`. If they are not, you'll see the above error. The `cli-deps-static-sites`
target creates dummy files that ensure that you'll be able to build.
-While not officially supported (or released), you can build and run the server **on macOS** as well. Simply run
+While not officially supported (or released), you can build and run the server **on macOS** as well. Simply run
`make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it.
### Build the web app
-The sources for the web app live in `web/`. As long as you have `npm` installed (see above), building the web app
+
+The sources for the web app live in `web/`. As long as you have `npm` installed (see above), building the web app
is really simple. Just type `make web` and you're in business:
-``` shell
+```shell
$ make web
...
```
-This will build the web app using Create React App and then **copy the production build to the `server/site` folder**, so
+This will build the web app using Create React App and then **copy the production build to the `server/site` folder**, so
that when you `make cli` (or `make cli-linux-amd64`, ...), you will have the web app included in the `ntfy` binary.
If you're developing on the web app, it's best to just `cd web` and run `npm start` manually. This will open your browser
-at `http://127.0.0.1:3000` with the web app, and as you edit the source files, they will be recompiled and the browser
+at `http://127.0.0.1:3000` with the web app, and as you edit the source files, they will be recompiled and the browser
will automatically refresh:
-``` shell
+```shell
$ cd web
$ npm start
```
### Build the docs
-The sources for the docs live in `docs/`. Similarly to the web app, you can simply run `make docs` to build the
+
+The sources for the docs live in `docs/`. Similarly to the web app, you can simply run `make docs` to build the
documentation. As long as you have `mkdocs` installed (see above), this should work fine:
-``` shell
+```shell
$ make docs
...
```
-If you are changing the documentation, you should be running `mkdocs serve` directly. This will build the documentation,
-serve the files at `http://127.0.0.1:8000/`, and rebuild every time you save the source files:
+If you are changing the documentation, you should be running `mkdocs serve` directly. This will build the documentation,
+serve the files at `http://127.0.0.1:8000/`, and rebuild every time you save the source files:
```
$ mkdocs serve
@@ -264,33 +280,39 @@ INFO - [16:28:14] Serving on http://127.0.0.1:8000/
Then you can navigate to http://127.0.0.1:8000/ and whenever you change a markdown file in your text editor it'll automatically update.
## Android app
+
The ntfy Android app source code is available [on GitHub](https://github.com/binwiederhier/ntfy-android).
The Android app has two flavors:
-* **Google Play:** The `play` flavor includes [Firebase (FCM)](https://firebase.google.com/) and requires a Firebase account
-* **F-Droid:** The `fdroid` flavor does not include Firebase or Google dependencies
+- **Google Play:** The `play` flavor includes [Firebase (FCM)](https://firebase.google.com/) and requires a Firebase account
+- **F-Droid:** The `fdroid` flavor does not include Firebase or Google dependencies
### Navigating the code
-* [main/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/main) - Main Android app source code
-* [play/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/play) - Google Play / Firebase specific code
-* [fdroid/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/fdroid) - F-Droid Firebase stubs
-* [build.gradle](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle) - Main build file
+
+- [main/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/main) - Main Android app source code
+- [play/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/play) - Google Play / Firebase specific code
+- [fdroid/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/fdroid) - F-Droid Firebase stubs
+- [build.gradle](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle) - Main build file
### IDE/Environment
-You should download [Android Studio](https://developer.android.com/studio) (or [IntelliJ IDEA](https://www.jetbrains.com/idea/)
-with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀
+
+You should download [Android Studio](https://developer.android.com/studio) (or [IntelliJ IDEA](https://www.jetbrains.com/idea/)
+with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀
### Check out the code
+
First check out the repository:
=== "via HTTPS"
- ``` shell
+
+ ```shell
git clone https://github.com/binwiederhier/ntfy-android.git
cd ntfy-android
```
=== "via SSH"
- ``` shell
+
+ ```shell
git clone git@github.com:binwiederhier/ntfy-android.git
cd ntfy-android
```
@@ -298,12 +320,14 @@ First check out the repository:
Then either follow the steps for building with or without Firebase.
### Build F-Droid flavor (no FCM)
+
!!! info
- I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
- work without issues. Please give me feedback if it does/doesn't work for you.
+I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
+work without issues. Please give me feedback if it does/doesn't work for you.
Without Firebase, you may want to still change the default `app_base_url` in [values.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml)
if you're self-hosting the server. Then run:
+
```
# Remove Google dependencies (FCM)
sed -i -e '/google-services/d' build.gradle
@@ -317,16 +341,18 @@ sed -i -e '/google-services/d' app/build.gradle
```
### Build Play flavor (FCM)
+
!!! info
- I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
- work without issues. Please give me feedback if it does/doesn't work for you.
+I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
+work without issues. Please give me feedback if it does/doesn't work for you.
To build your own version with Firebase, you must:
-* Create a Firebase/FCM account
-* Place your account file at `app/google-services.json`
-* And change `app_base_url` in [values.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml)
-* Then run:
+- Create a Firebase/FCM account
+- Place your account file at `app/google-services.json`
+- And change `app_base_url` in [values.xml](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/values.xml)
+- Then run:
+
```
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
./gradlew assemblePlayRelease
@@ -336,10 +362,12 @@ To build your own version with Firebase, you must:
```
## iOS app
-Building the iOS app is very involved. Please report any inconsistencies or issues with it. The requirements are
+
+Building the iOS app is very involved. Please report any inconsistencies or issues with it. The requirements are
strictly based off of my development on this app. There may be other versions of macOS / XCode that work.
### Requirements
+
1. macOS Monterey or later
1. XCode 13.2+
1. A physical iOS device (for push notifications, Firebase does not work in the XCode simulator)
@@ -349,17 +377,17 @@ strictly based off of my development on this app. There may be other versions of
### Apple setup
!!! info
- Along with this step, the [PLIST Deployment](#plist-deployment-and-configuration) step is also required
- for these changes to take effect in the iOS app.
+Along with this step, the [PLIST Deployment](#plist-deployment-and-configuration) step is also required
+for these changes to take effect in the iOS app.
1. [Create a new key in Apple Developer Member Center](https://developer.apple.com/account/resources/authkeys/add)
- 1. Select "Apple Push Notifications service (APNs)"
+1. Select "Apple Push Notifications service (APNs)"
1. Download the newly created key (should have a file name similar to `AuthKey_ZZZZZZ.p8`, where `ZZZZZZ` is the **Key ID**)
1. Record your **Team ID** - it can be seen in the top-right corner of the page, or on your Account > Membership page
1. Next, navigate to "Project Settings" in the firebase console for your project, and select the iOS app you created. Then, click "Cloud Messaging" in the left sidebar, and scroll down to the "APNs Authentication Key" section. Click "Upload Key", and upload the key you downloaded from Apple Developer.
!!! warning
- If you don't do the above setups for APNS, **notifications will not post instantly or sometimes at all**. This is because of the missing APNS key, which is required for firebase to send notifications to the iOS app. See below for a snip from the firebase docs.
+ If you don't do the above setups for APNS, **notifications will not post instantly or sometimes at all**. This is because of the missing APNS key, which is required for firebase to send notifications to the iOS app. See below for a snip from the firebase docs.
If you don't have an APNs authentication key, you can still send notifications to iOS devices, but they won't be delivered
instantly. Instead, they'll be delivered when the device wakes up to check for new notifications or when your application
@@ -372,17 +400,18 @@ recommended.
1. If you haven't already, create a Google / Firebase account
1. Visit the [Firebase console](https://console.firebase.google.com)
1. Create a new Firebase project:
- 1. Enter a project name
- 1. Disable Google Analytics (currently iOS app does not support analytics)
+1. Enter a project name
+1. Disable Google Analytics (currently iOS app does not support analytics)
1. On the "Project settings" page, add an iOS app
- 1. Apple bundle ID - "com.copephobia.ntfy-ios" (this can be changed to match XCode's ntfy.sh target > "Bundle Identifier" value)
- 1. Register the app
- 1. Download the config file - GoogleInfo.plist (this will need to be included in the ntfy-ios repository / XCode)
+1. Apple bundle ID - "com.copephobia.ntfy-ios" (this can be changed to match XCode's ntfy.sh target > "Bundle Identifier" value)
+1. Register the app
+1. Download the config file - GoogleInfo.plist (this will need to be included in the ntfy-ios repository / XCode)
1. Generate a new service account private key for the ntfy server
- 1. Go to "Project settings" > "Service accounts"
- 1. Click "Generate new private key" to generate and download a private key to use for sending messages via the ntfy server
+1. Go to "Project settings" > "Service accounts"
+1. Click "Generate new private key" to generate and download a private key to use for sending messages via the ntfy server
### ntfy server
+
Note that the ntfy server is not officially supported on macOS. It should, however, be able to run on macOS using these
steps:
@@ -394,18 +423,19 @@ steps:
### XCode setup
-1. Follow step 4 of [https://firebase.google.com/docs/ios/setup](Add Firebase to your Apple project) to install the
+1. Follow step 4 of [https://firebase.google.com/docs/ios/setup](Add Firebase to your Apple project) to install the
`firebase-ios-sdk` in XCode, if it's not already present - you can select any packages in addition to Firebase Core / Firebase Messaging
1. Similarly, install the SQLite.swift package dependency in XCode
1. When running the debug build, ensure XCode is pointed to the connected iOS device - registering for push notifications does not work in the iOS simulators
### PLIST config
-To have instant notifications/better notification delivery when using firebase, you will need to add the
+
+To have instant notifications/better notification delivery when using firebase, you will need to add the
`GoogleService-Info.plist` file to your project. Here's how to do that:
1. In XCode, find the NTFY app target. **Not** the NSE app target.
1. Find the Asset/ folder in the project navigator
-1. Drag the `GoogleService-Info.plist` file into the Asset/ folder that you get from the firebase console. It can be
- found in the "Project settings" > "General" > "Your apps" with a button labled "GoogleService-Info.plist"
+1. Drag the `GoogleService-Info.plist` file into the Asset/ folder that you get from the firebase console. It can be
+ found in the "Project settings" > "General" > "Your apps" with a button labled "GoogleService-Info.plist"
After that, you should be all set!
diff --git a/docs/examples.md b/docs/examples.md
index 8164e2bf..06c5d14a 100644
--- a/docs/examples.md
+++ b/docs/examples.md
@@ -5,18 +5,19 @@ There are a million ways to use ntfy, but here are some inspirations. I try to c
those out, too.
!!! info
- Many of these examples were contributed by ntfy users. If you have other examples of how you use ntfy, please
- [create a pull request](https://github.com/binwiederhier/ntfy/pulls), and I'll happily include it. Also note, that
- I cannot guarantee that all of these examples are functional. Many of them I have not tried myself.
+Many of these examples were contributed by ntfy users. If you have other examples of how you use ntfy, please
+[create a pull request](https://github.com/binwiederhier/ntfy/pulls), and I'll happily include it. Also note, that
+I cannot guarantee that all of these examples are functional. Many of them I have not tried myself.
## Cronjobs
+
ntfy is perfect for any kind of cronjobs or just when long processes are done (backups, pipelines, rsync copy commands, ...).
I started adding notifications pretty much all of my scripts. Typically, I just chain the curl call
directly to the command I'm running. The following example will either send Laptop backup succeeded
or ⚠️ Laptop backup failed directly to my phone:
-``` bash
+```bash
rsync -a root@laptop /backups/laptop \
&& zfs snapshot ... \
&& curl -H prio:low -d "Laptop backup succeeded" ntfy.sh/backups \
@@ -31,12 +32,12 @@ GitHub have been hopeless. In case it ever becomes available, I want to know imm
*/6 * * * * if curl -s https://api.github.com/users/ntfy | grep "Not Found"; then curl -d "github.com/ntfy is available" -H "Tags: tada" -H "Prio: high" ntfy.sh/my-alerts; fi
```
-
## Low disk space alerts
-Here's a simple cronjob that I use to alert me when the disk space on the root disk is running low. It's simple, but
-effective.
-``` bash
+Here's a simple cronjob that I use to alert me when the disk space on the root disk is running low. It's simple, but
+effective.
+
+```bash
#!/bin/bash
mingigs=10
@@ -54,17 +55,20 @@ fi
```
## SSH login alerts
+
Years ago my home server was broken into. That shook me hard, so every time someone logs into any machine that I
own, I now message myself. Here's an example of how to use PAM
to notify yourself on SSH login.
=== "/etc/pam.d/sshd"
+
```
# at the end of the file
session optional pam_exec.so /usr/bin/ntfy-ssh-login.sh
```
=== "/usr/bin/ntfy-ssh-login.sh"
+
```bash
#!/bin/bash
if [ "${PAM_TYPE}" = "open_session" ]; then
@@ -77,31 +81,36 @@ to notify yourself on SSH login.
```
## Collect data from multiple machines
+
The other day I was running tasks on 20 servers, and I wanted to collect the interim results
-as a CSV in one place. Each of the servers was publishing to a topic as the results completed (`publish-result.sh`),
+as a CSV in one place. Each of the servers was publishing to a topic as the results completed (`publish-result.sh`),
and I had one central collector to grab the results as they came in (`collect-results.sh`).
It looked something like this:
=== "collect-results.sh"
+
```bash
while read result; do
[ -n "$result" ] && echo "$result" >> results.csv
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
```
-=== "publish-result.sh"
+
+=== "publish-result.sh"
+
```bash
// This script was run on each of the 20 servers. It was doing heavy processing ...
-
+
// Publish script results
curl -d "$(hostname),$count,$time" ntfy.sh/results
```
## Ansible, Salt and Puppet
+
You can easily integrate ntfy into Ansible, Salt, or Puppet to notify you when runs are done or are highstated.
One of my co-workers uses the following Ansible task to let him know when things are done:
-``` yaml
+```yaml
- name: Send ntfy.sh update
uri:
url: "https://ntfy.sh/{{ ntfy_channel }}"
@@ -113,18 +122,20 @@ There's also a dedicated Ansible action plugin (one which runs on the Ansible co
[ansible-ntfy](https://github.com/jpmens/ansible-ntfy). The following task posts a message
to ntfy at its default URL (`attrs` and other attributes are optional):
-``` yaml
+```yaml
- name: "Notify ntfy that we're done"
ntfy:
- msg: "deployment on {{ inventory_hostname }} is complete. 🐄"
- attrs:
- tags: [ heavy_check_mark ]
- priority: 1
+ msg: "deployment on {{ inventory_hostname }} is complete. 🐄"
+ attrs:
+ tags: [heavy_check_mark]
+ priority: 1
```
## GitHub Actions
+
You can send a message during a workflow run with curl. Here is an example sending info about the repo, commit and job status.
-``` yaml
+
+```yaml
- name: Actions Ntfy
run: |
curl \
@@ -136,12 +147,13 @@ You can send a message during a workflow run with curl. Here is an example sendi
```
## Watchtower (shoutrrr)
-You can use [shoutrrr](https://containrrr.dev/shoutrrr/latest/services/ntfy/) to send
+
+You can use [shoutrrr](https://containrrr.dev/shoutrrr/latest/services/ntfy/) to send
[Watchtower](https://github.com/containrrr/watchtower/) notifications to your ntfy topic.
Example docker-compose.yml:
-``` yaml
+```yaml
services:
watchtower:
image: containrrr/watchtower
@@ -151,6 +163,7 @@ services:
```
Or, if you only want to send notifications using shoutrrr:
+
```
shoutrrr send -u "ntfy://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
```
@@ -165,90 +178,76 @@ Sonarr v3, Readarr, and SABnzbd support custom scripts for downloads, warnings,
Some simple bash scripts to achieve this are kindly provided in [nickexyz's ntfy-shellscripts repository](https://github.com/nickexyz/ntfy-shellscripts).
## Node-RED
+
You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples:
Example: Send a message (click to expand)
-``` json
+```json
[
- {
- "id": "c956e688cc74ad8e",
- "type": "http request",
- "z": "fabdd7a3.4045a",
- "name": "ntfy.sh",
- "method": "POST",
- "ret": "txt",
- "paytoqs": "ignore",
- "url": "https://ntfy.sh/mytopic",
- "tls": "",
- "persist": false,
- "proxy": "",
- "authType": "",
- "senderr": false,
- "credentials":
- {
- "user": "",
- "password": ""
- },
- "x": 590,
- "y": 3160,
- "wires":
- [
- []
- ]
+ {
+ "id": "c956e688cc74ad8e",
+ "type": "http request",
+ "z": "fabdd7a3.4045a",
+ "name": "ntfy.sh",
+ "method": "POST",
+ "ret": "txt",
+ "paytoqs": "ignore",
+ "url": "https://ntfy.sh/mytopic",
+ "tls": "",
+ "persist": false,
+ "proxy": "",
+ "authType": "",
+ "senderr": false,
+ "credentials": {
+ "user": "",
+ "password": ""
},
- {
- "id": "32ee1eade51fae50",
- "type": "function",
- "z": "fabdd7a3.4045a",
- "name": "data",
- "func": "msg.payload = \"Something happened\";\nmsg.headers = {};\nmsg.headers['tags'] = 'house';\nmsg.headers['X-Title'] = 'Home Assistant';\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 470,
- "y": 3160,
- "wires":
- [
- [
- "c956e688cc74ad8e"
- ]
- ]
- },
- {
- "id": "b287e59cd2311815",
- "type": "inject",
- "z": "fabdd7a3.4045a",
- "name": "Manual start",
- "props":
- [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": "20",
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 330,
- "y": 3160,
- "wires":
- [
- [
- "32ee1eade51fae50"
- ]
- ]
- }
+ "x": 590,
+ "y": 3160,
+ "wires": [[]]
+ },
+ {
+ "id": "32ee1eade51fae50",
+ "type": "function",
+ "z": "fabdd7a3.4045a",
+ "name": "data",
+ "func": "msg.payload = \"Something happened\";\nmsg.headers = {};\nmsg.headers['tags'] = 'house';\nmsg.headers['X-Title'] = 'Home Assistant';\n\nreturn msg;",
+ "outputs": 1,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 470,
+ "y": 3160,
+ "wires": [["c956e688cc74ad8e"]]
+ },
+ {
+ "id": "b287e59cd2311815",
+ "type": "inject",
+ "z": "fabdd7a3.4045a",
+ "name": "Manual start",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": "20",
+ "topic": "",
+ "payload": "",
+ "payloadType": "date",
+ "x": 330,
+ "y": 3160,
+ "wires": [["32ee1eade51fae50"]]
+ }
]
```
@@ -259,113 +258,92 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
Example: Send a picture (click to expand)
-``` json
+```json
[
- {
- "id": "d135a13eadeb9d6d",
- "type": "http request",
- "z": "fabdd7a3.4045a",
- "name": "Download image",
- "method": "GET",
- "ret": "bin",
- "paytoqs": "ignore",
- "url": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
- "tls": "",
- "persist": false,
- "proxy": "",
- "authType": "",
- "senderr": false,
- "credentials":
- {
- "user": "",
- "password": ""
- },
- "x": 490,
- "y": 3320,
- "wires":
- [
- [
- "6e75bc41d2ec4a03"
- ]
- ]
+ {
+ "id": "d135a13eadeb9d6d",
+ "type": "http request",
+ "z": "fabdd7a3.4045a",
+ "name": "Download image",
+ "method": "GET",
+ "ret": "bin",
+ "paytoqs": "ignore",
+ "url": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png",
+ "tls": "",
+ "persist": false,
+ "proxy": "",
+ "authType": "",
+ "senderr": false,
+ "credentials": {
+ "user": "",
+ "password": ""
},
- {
- "id": "6e75bc41d2ec4a03",
- "type": "function",
- "z": "fabdd7a3.4045a",
- "name": "data",
- "func": "msg.payload = msg.payload;\nmsg.headers = {};\nmsg.headers['tags'] = 'house';\nmsg.headers['X-Title'] = 'Home Assistant - Picture';\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 650,
- "y": 3320,
- "wires":
- [
- [
- "eb160615b6ceda98"
- ]
- ]
+ "x": 490,
+ "y": 3320,
+ "wires": [["6e75bc41d2ec4a03"]]
+ },
+ {
+ "id": "6e75bc41d2ec4a03",
+ "type": "function",
+ "z": "fabdd7a3.4045a",
+ "name": "data",
+ "func": "msg.payload = msg.payload;\nmsg.headers = {};\nmsg.headers['tags'] = 'house';\nmsg.headers['X-Title'] = 'Home Assistant - Picture';\n\nreturn msg;",
+ "outputs": 1,
+ "noerr": 0,
+ "initialize": "",
+ "finalize": "",
+ "libs": [],
+ "x": 650,
+ "y": 3320,
+ "wires": [["eb160615b6ceda98"]]
+ },
+ {
+ "id": "eb160615b6ceda98",
+ "type": "http request",
+ "z": "fabdd7a3.4045a",
+ "name": "ntfy.sh",
+ "method": "PUT",
+ "ret": "bin",
+ "paytoqs": "ignore",
+ "url": "https://ntfy.sh/mytopic",
+ "tls": "",
+ "persist": false,
+ "proxy": "",
+ "authType": "",
+ "senderr": false,
+ "credentials": {
+ "user": "",
+ "password": ""
},
- {
- "id": "eb160615b6ceda98",
- "type": "http request",
- "z": "fabdd7a3.4045a",
- "name": "ntfy.sh",
- "method": "PUT",
- "ret": "bin",
- "paytoqs": "ignore",
- "url": "https://ntfy.sh/mytopic",
- "tls": "",
- "persist": false,
- "proxy": "",
- "authType": "",
- "senderr": false,
- "credentials":
- {
- "user": "",
- "password": ""
- },
- "x": 770,
- "y": 3320,
- "wires":
- [
- []
- ]
- },
- {
- "id": "5b8dbf15c8a7a3a5",
- "type": "inject",
- "z": "fabdd7a3.4045a",
- "name": "Manual start",
- "props":
- [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": "20",
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 310,
- "y": 3320,
- "wires":
- [
- [
- "d135a13eadeb9d6d"
- ]
- ]
- }
+ "x": 770,
+ "y": 3320,
+ "wires": [[]]
+ },
+ {
+ "id": "5b8dbf15c8a7a3a5",
+ "type": "inject",
+ "z": "fabdd7a3.4045a",
+ "name": "Manual start",
+ "props": [
+ {
+ "p": "payload"
+ },
+ {
+ "p": "topic",
+ "vt": "str"
+ }
+ ],
+ "repeat": "",
+ "crontab": "",
+ "once": false,
+ "onceDelay": "20",
+ "topic": "",
+ "payload": "",
+ "payloadType": "date",
+ "x": 310,
+ "y": 3320,
+ "wires": [["d135a13eadeb9d6d"]]
+ }
]
```
@@ -374,6 +352,7 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder

## Gatus
+
To use ntfy with [Gatus](https://github.com/TwiN/gatus), you can use the `ntfy` alerting provider like so:
```yaml
@@ -416,24 +395,25 @@ alerting:
-
## Jellyseerr/Overseerr webhook
+
Here is an example for [jellyseerr](https://github.com/Fallenbagel/jellyseerr)/[overseerr](https://overseerr.dev/) webhook
-JSON payload. Remember to change the `https://request.example.com` to your URL as the value of the JSON key click.
+JSON payload. Remember to change the `https://request.example.com` to your URL as the value of the JSON key click.
And if you're not using the request `topic`, make sure to change it in the JSON payload to your topic.
-``` json
+```json
{
- "topic": "requests",
- "title": "{{event}}",
- "message": "{{subject}}\n{{message}}\n\nRequested by: {{requestedBy_username}}\n\nStatus: {{media_status}}\nRequest Id: {{request_id}}",
- "priority": 4,
- "attach": "{{image}}",
- "click": "https://requests.example.com/{{media_type}}/{{media_tmdbid}}"
+ "topic": "requests",
+ "title": "{{event}}",
+ "message": "{{subject}}\n{{message}}\n\nRequested by: {{requestedBy_username}}\n\nStatus: {{media_status}}\nRequest Id: {{request_id}}",
+ "priority": 4,
+ "attach": "{{image}}",
+ "click": "https://requests.example.com/{{media_type}}/{{media_tmdbid}}"
}
```
## Home Assistant
+
Here is an example for the configuration.yml file to setup a REST notify component.
Since Home Assistant is going to POST JSON, you need to specify the root of your ntfy resource.
@@ -482,6 +462,7 @@ notify:
```
## Uptime Kuma
+
Go to your [Uptime Kuma](https://github.com/louislam/uptime-kuma) Settings > Notifications, click on **Setup Notification**.
Then set your desired **title** (e.g. "Uptime Kuma"), **ntfy topic**, **Server URL** and **priority (1-5)**:
@@ -499,6 +480,7 @@ You can now test the notifications and apply them to monitors:
## UptimeRobot
+
Go to your [UptimeRobot](https://github.com/uptimerobot) My Settings > Alert Contacts > Add Alert Contact
Select **Alert Contact Type** = Webhook. Then set your desired **Friendly Name** (e.g. "ntfy-sh-UP"), **URL to Notify**, **POST value** and select checkbox **Send as JSON (application/json)**. Make sure to send the JSON POST request to ntfy.domain.com without the topic name in the url and include the "topic" name in the JSON body.
@@ -506,37 +488,39 @@ Select **Alert Contact Type** = Webhook. Then set your desired **Friendly Name**
-``` json
+```json
{
"topic":"myTopic",
"title": "*monitorFriendlyName* *alertTypeFriendlyName*",
- "message": "*alertDetails*",
+ "message": "*alertDetails*",
"tags": ["green_circle"],
"priority": 3,
"click": https://uptimerobot.com/dashboard#*monitorID*
}
```
+
You can create two Alert Contacts each with a different icon and priority, for example:
-``` json
+```json
{
"topic":"myTopic",
"title": "*monitorFriendlyName* *alertTypeFriendlyName*",
- "message": "*alertDetails*",
+ "message": "*alertDetails*",
"tags": ["red_circle"],
"priority": 3,
"click": https://uptimerobot.com/dashboard#*monitorID*
}
```
+
You can now add the created Alerts Contact(s) to the monitor(s) and test the notifications:
-
## Apprise
-ntfy is integrated natively into [Apprise](https://github.com/caronc/apprise) (also check out the
+
+ntfy is integrated natively into [Apprise](https://github.com/caronc/apprise) (also check out the
[Apprise/ntfy wiki page](https://github.com/caronc/apprise/wiki/Notify_ntfy)).
You can use it like this:
@@ -553,9 +537,9 @@ apprise -vv -t "Test Message Title" -b "Test Message Body" \
ntfy://ntfy.example.com/mytopic
```
-
## Rundeck
-Rundeck by default sends only HTML email which is not processed by ntfy SMTP server. Append following configurations to
+
+Rundeck by default sends only HTML email which is not processed by ntfy SMTP server. Append following configurations to
[rundeck-config.properties](https://docs.rundeck.com/docs/administration/configuration/config-file-reference.html) :
```
@@ -565,13 +549,14 @@ rundeck.mail.template.log.formatted=false
```
Example `template.html`:
+
```html
Execution ${execution.id} was ${execution.status}
```
@@ -579,11 +564,13 @@ Add notification on Rundeck (attachment type must be: `Attached as file to email

## Traccar
+
This will only work on selfhosted [traccar](https://www.traccar.org/) ([Github](https://github.com/traccar/traccar)) instances, as you need to be able to set `sms.http.*` keys, which is not possible through the UI attributes
The easiest way to integrate traccar with ntfy, is to configure ntfy as the SMS provider for your instance. You then can set your ntfy topic as your account's phone number in traccar. Sending the email notifications to ntfy will not work, as ntfy does not support HTML emails.
**Caution:** JSON publishing is only possible, when POST-ing to the root URL of the ntfy instance. (see [documentation](publish.md#publish-as-json))
+
```xml
https://ntfy.sh
@@ -593,11 +580,15 @@ The easiest way to integrate traccar with ntfy, is to configure ntfy as the SMS
}
```
+
If [access control](config.md#access-control) is enabled, and the target topic does not support anonymous writes, you'll also have to provide an authorization header, for example in form of a privileged token
+
```xml
Bearer tk_JhbsnoMrgy2FcfHeofv97Pi5uXaZZ
```
+
or by simply providing traccar with a valid username/password combination.
+
```xml
phil
mypass
diff --git a/docs/faq.md b/docs/faq.md
index d7977a5f..f4c5f3ad 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -1,82 +1,96 @@
# Frequently asked questions (FAQ)
## Isn't this like ...?
+
Who knows. I didn't do a lot of research before making this. It was fun making it.
## Can I use this in my app? Will it stay free?
+
Yes. As long as you don't abuse it, it'll be available and free of charge. While I will always allow usage of the ntfy.sh
server without signup and free of charge, I may also offer paid plans in the future.
## What are the uptime guarantees?
-Best effort.
+
+Best effort.
ntfy currently runs on a single DigitalOcean droplet, without any scale out strategy or redundancies. When the time comes,
I'll add scale out features, but for now it is what it is.
-In the first year of its life, and to this day (Dec'22), ntfy had **no outages** that I can remember. Other than short
-blips and some HTTP 500 spikes, it has been rock solid.
+In the first year of its life, and to this day (Dec'22), ntfy had **no outages** that I can remember. Other than short
+blips and some HTTP 500 spikes, it has been rock solid.
-There is a [status page](https://ntfy.statuspage.io/) which is updated based on some automated checks via the amazingly
+There is a [status page](https://ntfy.statuspage.io/) which is updated based on some automated checks via the amazingly
awesome [healthchecks.io](https://healthchecks.io/) (_no affiliation, just a fan_).
## What happens if there are multiple subscribers to the same topic?
+
As per usual with pub-sub, all subscribers receive notifications if they are subscribed to a topic.
## Will you know what topics exist, can you spy on me?
+
If you don't trust me or your messages are sensitive, run your own server. It's open source.
That said, the logs do contain topic names and IP addresses, but I don't use them for anything other than
-troubleshooting and rate limiting. Messages are cached for the duration configured in `server.yml` (12h by default)
+troubleshooting and rate limiting. Messages are cached for the duration configured in `server.yml` (12h by default)
to facilitate service restarts, message polling and to overcome client network disruptions.
## Can I self-host it?
+
Yes. The server (including this Web UI) can be self-hosted, and the Android/iOS app supports adding topics from
your own server as well. Check out the [install instructions](install.md).
## Is Firebase used?
+
In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
published to Firebase Cloud Messaging (FCM) (if `FirebaseKeyFile` is set, which it is on ntfy.sh). This
-is to facilitate notifications on Android.
+is to facilitate notifications on Android.
If you do not care for Firebase, I suggest you install the [F-Droid version](https://f-droid.org/en/packages/io.heckel.ntfy/)
of the app and [self-host your own ntfy server](install.md).
## How much battery does the Android app use?
-If you use the ntfy.sh server, and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature,
-the Android/iOS app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server,
-or you use *instant delivery* (Android only), or install from F-droid ([which does not support FCM](https://f-droid.org/docs/Inclusion_Policy/)),
-the app has to maintain a constant connection to the server, which consumes about 0-1% of battery in 17h of use (on my phone).
+
+If you use the ntfy.sh server, and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature,
+the Android/iOS app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server,
+or you use _instant delivery_ (Android only), or install from F-droid ([which does not support FCM](https://f-droid.org/docs/Inclusion_Policy/)),
+the app has to maintain a constant connection to the server, which consumes about 0-1% of battery in 17h of use (on my phone).
There has been a ton of testing and improvement around this. I think it's pretty decent now.
## Paid plans? I thought it was open source?
+
All of ntfy will remain open source, with a free software license (Apache 2.0 and GPLv2). If you'd like to self-host, you
can (and should do that). The paid plans I am offering are for people that do not want to self-host, and/or need higher
limits.
## What is instant delivery?
+
[Instant delivery](subscribe/phone.md#instant-delivery) is a feature in the Android app. If turned on, the app maintains a constant connection to the
server and listens for incoming notifications. This consumes additional battery (see above),
but delivers notifications instantly.
## Can you implement feature X?
+
Yes, maybe. Check out [existing GitHub issues](https://github.com/binwiederhier/ntfy/issues) to see if somebody else had
the same idea before you, or file a new issue. I'll likely get back to you within a few days.
## I'm having issues with iOS, can you help? The iOS app is behind compared to the Android app, can you fix that?
+
The iOS is very bare bones and quite frankly a little buggy. I wanted to get something out the door to make the iOS users
happy, but halfway through I got frustrated with iOS development and paused development. I will eventually get back to
it, or hopefully, somebody else will come along and help out. Please review the [known issues](known-issues.md) for details.
## Can I disable the web app? Can I protect it with a login screen?
+
The web app is a static website without a backend (other than the ntfy API). All data is stored locally in the browser
-cache and local storage. That means it does not need to be protected with a login screen, and it poses no additional
+cache and local storage. That means it does not need to be protected with a login screen, and it poses no additional
security risk. So technically, it does not need to be disabled.
-However, if you still want to disable it, you can do so with the `web-root: disable` option in the `server.yml` file.
+However, if you still want to disable it, you can do so with the `web-root: disable` option in the `server.yml` file.
Think of the ntfy web app like an Android/iOS app. It is freely available and accessible to anyone, yet useless without
a proper backend. So as long as you secure your backend with ACLs, exposing the ntfy web app to the Internet is harmless.
## Where can I donate?
+
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier).
I would be humbled if you helped me carry the server and developer account costs. Even small donations are very much
appreciated.
diff --git a/docs/index.md b/docs/index.md
index 27314f1a..0d058dfa 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,16 +1,18 @@
# Getting started
+
ntfy lets you **send push notifications to your phone or desktop via scripts from any computer**, using simple HTTP PUT
or POST requests. I use it to notify myself when scripts fail, or long-running commands complete.
## Step 1: Get the app
+
To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play or F-Droid.
Once installed, open it and subscribe to a topic of your choosing. Topics don't have to explicitly be created, so just
-pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise
-to choose something that cannot be guessed easily.**
+pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise
+to choose something that cannot be guessed easily.**
For this guide, we'll just use `mytopic` as our topic name:
@@ -22,30 +24,35 @@ For this guide, we'll just use `mytopic` as our topic name:
That's it. After you tap "Subscribe", the app is listening for new messages on that topic.
## Step 2: Send a message
+
Now let's [send a message](publish.md) to our topic. It's easy in every language, since we're just using HTTP PUT/POST,
-or with the [ntfy CLI](install.md). The message is in the request body. Here's an example showing how to publish a
+or with the [ntfy CLI](install.md). The message is in the request body. Here's an example showing how to publish a
simple message using a POST request:
=== "Command line (curl)"
- ```
+
+ ```sh
curl -d "Backup successful 😀" ntfy.sh/mytopic
```
=== "ntfy CLI"
- ```
+
+ ```sh
ntfy publish mytopic "Backup successful 😀"
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mytopic HTTP/1.1
Host: ntfy.sh
-
+
Backup successful 😀
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST', // PUT works too
body: 'Backup successful 😀'
@@ -53,19 +60,22 @@ simple message using a POST request:
```
=== "Go"
- ``` go
+
+ ```go
http.Post("https://ntfy.sh/mytopic", "text/plain",
strings.NewReader("Backup successful 😀"))
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/mytopic",
data="Backup successful 😀".encode(encoding='utf-8'))
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -91,5 +101,3 @@ Here's another video showing the entire process:
Sending push notifications to your Android phone
-
-
diff --git a/docs/install.md b/docs/install.md
index 1d284956..efe879c7 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -1,14 +1,16 @@
# Installing ntfy
+
The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to
-self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image,
-configure it and run it. Just like any other software. No fuzz.
+self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image,
+configure it and run it. Just like any other software. No fuzz.
!!! info
- The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**.
- If you just want to [send messages using ntfy.sh](publish.md), you don't need to install anything. You can just use
- `curl`.
+The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**.
+If you just want to [send messages using ntfy.sh](publish.md), you don't need to install anything. You can just use
+`curl`.
## General steps
+
The ntfy server comes as a statically linked binary and is shipped as tarball, deb/rpm packages and as a Docker image.
We support amd64, armv7 and arm64.
@@ -18,16 +20,18 @@ We support amd64, armv7 and arm64.
To run the ntfy server, then just run `ntfy serve` (or `systemctl start ntfy` when using the deb/rpm).
To send messages, use `ntfy publish`. To subscribe to topics, use `ntfy subscribe` (see [subscribing via CLI](subscribe/cli.md)
-for details).
+for details).
-If you like video tutorials, check out :simple-youtube: [Kris Occhipinti's ntfy install guide](https://www.youtube.com/watch?v=bZzqrX05mNU).
+If you like video tutorials, check out :simple-youtube: [Kris Occhipinti's ntfy install guide](https://www.youtube.com/watch?v=bZzqrX05mNU).
It's short and to the point. _I am not affiliated with Kris, I just liked the video._
## Linux binaries
+
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
deb/rpm packages.
=== "x86_64/amd64"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_x86_64.tar.gz
tar zxvf ntfy_2.5.0_linux_x86_64.tar.gz
@@ -37,6 +41,7 @@ deb/rpm packages.
```
=== "armv6"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.tar.gz
tar zxvf ntfy_2.5.0_linux_armv6.tar.gz
@@ -46,6 +51,7 @@ deb/rpm packages.
```
=== "armv7/armhf"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.tar.gz
tar zxvf ntfy_2.5.0_linux_armv7.tar.gz
@@ -55,6 +61,7 @@ deb/rpm packages.
```
=== "arm64"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.tar.gz
tar zxvf ntfy_2.5.0_linux_arm64.tar.gz
@@ -64,15 +71,17 @@ deb/rpm packages.
```
## Debian/Ubuntu repository
+
Installation via Debian repository:
=== "x86_64/amd64"
+
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
- > /etc/apt/sources.list.d/archive.heckel.io.list"
+ > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
@@ -80,6 +89,7 @@ Installation via Debian repository:
```
=== "armv7/armhf"
+
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
@@ -93,6 +103,7 @@ Installation via Debian repository:
```
=== "arm64"
+
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
@@ -108,6 +119,7 @@ Installation via Debian repository:
Manually installing the .deb file:
=== "x86_64/amd64"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_amd64.deb
sudo dpkg -i ntfy_*.deb
@@ -116,6 +128,7 @@ Manually installing the .deb file:
```
=== "armv6"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.deb
sudo dpkg -i ntfy_*.deb
@@ -124,6 +137,7 @@ Manually installing the .deb file:
```
=== "armv7/armhf"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.deb
sudo dpkg -i ntfy_*.deb
@@ -132,6 +146,7 @@ Manually installing the .deb file:
```
=== "arm64"
+
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.deb
sudo dpkg -i ntfy_*.deb
@@ -142,13 +157,15 @@ Manually installing the .deb file:
## Fedora/RHEL/CentOS
=== "x86_64/amd64"
+
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_amd64.rpm
- sudo systemctl enable ntfy
+ sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv6"
+
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.rpm
sudo systemctl enable ntfy
@@ -156,26 +173,31 @@ Manually installing the .deb file:
```
=== "armv7/armhf"
+
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.rpm
- sudo systemctl enable ntfy
+ sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
+
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.rpm
- sudo systemctl enable ntfy
+ sudo systemctl enable ntfy
sudo systemctl start ntfy
```
## Arch Linux
+
ntfy can be installed using an [AUR package](https://aur.archlinux.org/packages/ntfysh-bin/). You can use an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers) like `paru`, `yay` or others to download, build and install ntfy and keep it up to date.
+
```
paru -S ntfysh-bin
```
Alternatively, run the following commands to install ntfy manually:
+
```
curl https://aur.archlinux.org/cgit/aur.git/snapshot/ntfysh-bin.tar.gz | tar xzv
cd ntfysh-bin
@@ -183,46 +205,51 @@ makepkg -si
```
## NixOS / Nix
+
ntfy is packaged in nixpkgs as `ntfy-sh`. It can be installed by adding the package name to the configuration file and calling `nixos-rebuild`. Alternatively, the following command can be used to install ntfy in the current user environment:
+
```
nix-env -iA ntfy-sh
```
-NixOS also supports [declarative setup of the ntfy server](https://search.nixos.org/options?channel=unstable&show=services.ntfy-sh.enable&from=0&size=50&sort=relevance&type=packages&query=ntfy).
+NixOS also supports [declarative setup of the ntfy server](https://search.nixos.org/options?channel=unstable&show=services.ntfy-sh.enable&from=0&size=50&sort=relevance&type=packages&query=ntfy).
## macOS
-The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
-To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_macOS_all.tar.gz),
-extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
-If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at
+The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
+To install, please [download the tarball](https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_macOS_all.tar.gz),
+extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
+
+If run as `root`, ntfy will look for its config at `/etc/ntfy/client.yml`. For all other users, it'll look for it at
`~/Library/Application Support/ntfy/client.yml` (sample included in the tarball).
```bash
curl -L https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_macOS_all.tar.gz > ntfy_2.5.0_macOS_all.tar.gz
tar zxvf ntfy_2.5.0_macOS_all.tar.gz
sudo cp -a ntfy_2.5.0_macOS_all/ntfy /usr/local/bin/ntfy
-mkdir ~/Library/Application\ Support/ntfy
+mkdir ~/Library/Application\ Support/ntfy
cp ntfy_2.5.0_macOS_all/client/client.yml ~/Library/Application\ Support/ntfy/client.yml
ntfy --help
```
!!! info
- Only the ntfy CLI is supported on macOS. ntfy server is currently not supported, but you can build and run it for
- development as well. Check out the [build instructions](develop.md) for details.
+Only the ntfy CLI is supported on macOS. ntfy server is currently not supported, but you can build and run it for
+development as well. Check out the [build instructions](develop.md) for details.
## Homebrew
+
To install the [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) via Homebrew (Linux and macOS),
simply run:
+
```
brew install ntfy
```
-
## Windows
+
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well.
To install, please [download the latest ZIP](https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_windows_x86_64.zip),
-extract it and place the `ntfy.exe` binary somewhere in your `%Path%`.
+extract it and place the `ntfy.exe` binary somewhere in your `%Path%`.
The default path for the client config file is at `%AppData%\ntfy\client.yml` (not created automatically, sample in the ZIP file).
@@ -231,28 +258,31 @@ Also available in [Scoop's](https://scoop.sh) Main repository:
`scoop install ntfy`
!!! info
- There is currently no installer for Windows, and the binary is not signed. If this is desired, please create a
- [GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.
+There is currently no installer for Windows, and the binary is not signed. If this is desired, please create a
+[GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.
## Docker
-The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for amd64, armv6, armv7 and arm64. It should
+
+The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for amd64, armv6, armv7 and arm64. It should
be pretty straight forward to use.
-The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent
-[message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings,
+The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent
+[message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings,
you should map `/etc/ntfy`, so you can edit `/etc/ntfy/server.yml`.
!!! info
- Note that the Docker image **does not contain a `/etc/ntfy/server.yml` file**. If you'd like to use a config file,
- please manually create one outside the image and map it as a volume, e.g. via `-v /etc/ntfy:/etc/ntfy`. You may
- use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template.
+Note that the Docker image **does not contain a `/etc/ntfy/server.yml` file**. If you'd like to use a config file,
+please manually create one outside the image and map it as a volume, e.g. via `-v /etc/ntfy:/etc/ntfy`. You may
+use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template.
Basic usage (no cache or additional config):
+
```
docker run -p 80:80 -it binwiederhier/ntfy serve
```
With persistent cache (configured as command line arguments):
+
```bash
docker run \
-v /var/cache/ntfy:/var/cache/ntfy \
@@ -264,6 +294,7 @@ docker run \
```
With other config options, timezone, and non-root user (configured via `/etc/ntfy/server.yml`, see [configuration](config.md) for details):
+
```bash
docker run \
-v /etc/ntfy:/etc/ntfy \
@@ -276,6 +307,7 @@ docker run \
```
Using docker-compose with non-root user and healthchecks enabled:
+
```yaml
version: "2.1"
@@ -286,7 +318,7 @@ services:
command:
- serve
environment:
- - TZ=UTC # optional: set desired timezone
+ - TZ=UTC # optional: set desired timezone
user: UID:GID # optional: replace with your own user/group or uid/gid
volumes:
- /var/cache/ntfy:/var/cache/ntfy
@@ -294,22 +326,28 @@ services:
ports:
- 80: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
+ 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
```
If using a non-root user when running the docker version, be sure to chown the server.yml, user.db, and cache.db files and attachments directory to the same uid/gid.
Alternatively, you may wish to build a customized Docker image that can be run with fewer command-line arguments and without delivering the configuration file separately.
+
```
FROM binwiederhier/ntfy
COPY server.yml /etc/ntfy/server.yml
ENTRYPOINT ["ntfy", "serve"]
```
+
This image can be pushed to a container registry and shipped independently. All that's needed when running it is mapping ntfy's port to a host port.
## Kubernetes
@@ -318,8 +356,8 @@ The setup for Kubernetes is very similar to that for Docker, and requires a fair
are a few options to mix and match, including a deployment without a cache file, a stateful set with a persistent cache, and a standalone
unmanned pod.
-
=== "deployment"
+
```yaml
apiVersion: apps/v1
kind: Deployment
@@ -368,6 +406,7 @@ unmanned pod.
```
=== "stateful set"
+
```yaml
apiVersion: apps/v1
kind: StatefulSet
@@ -411,6 +450,7 @@ unmanned pod.
```
=== "pod"
+
```yaml
apiVersion: v1
kind: Pod
@@ -442,6 +482,7 @@ unmanned pod.
Configuration is relatively straightforward. As an example, a minimal configuration is provided.
=== "resource definition"
+
```yaml
apiVersion: v1
kind: ConfigMap
@@ -454,8 +495,9 @@ Configuration is relatively straightforward. As an example, a minimal configurat
```
=== "from-file"
+
```bash
- kubectl create configmap ntfy --from-file=server.yml
+ kubectl create configmap ntfy --from-file=server.yml
```
## Kustomize
@@ -464,22 +506,23 @@ ntfy can be deployed in a Kubernetes cluster with [Kustomize](https://github.com
to customize Kubernetes objects using a `kustomization.yaml` file.
1. Create new folder - `ntfy`
-2. Add all files listed below
- 1. `kustomization.yaml` - stores all configmaps and resources used in a deployment
- 2. `ntfy-deployment.yaml` - define deployment type and its parameters
- 3. `ntfy-pvc.yaml` - describes how [persistent volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) will be created
- 4. `ntfy-svc.yaml` - expose application to the internal kubernetes network
- 5. `ntfy-ingress.yaml` - expose service to outside the network using [ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)
- 6. `server.yaml` - simple server configuration
-3. Replace **TESTNAMESPACE** within `kustomization.yaml` with designated namespace
+2. Add all files listed below
+ 1. `kustomization.yaml` - stores all configmaps and resources used in a deployment
+ 2. `ntfy-deployment.yaml` - define deployment type and its parameters
+ 3. `ntfy-pvc.yaml` - describes how [persistent volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) will be created
+ 4. `ntfy-svc.yaml` - expose application to the internal kubernetes network
+ 5. `ntfy-ingress.yaml` - expose service to outside the network using [ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)
+ 6. `server.yaml` - simple server configuration
+3. Replace **TESTNAMESPACE** within `kustomization.yaml` with designated namespace
4. Replace **ntfy.test** within `ntfy-ingress.yaml` with desired DNS name
-5. Apply configuration to cluster set in current context:
+5. Apply configuration to cluster set in current context:
```bash
kubectl apply -k /ntfy
```
=== "kustomization.yaml"
+
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
@@ -490,11 +533,13 @@ kubectl apply -k /ntfy
- ntfy-ingress.yaml # ingress definition
configMapGenerator: # will parse config from raw config to configmap,it allows for dynamic reload of application if additional app is deployed ie https://github.com/stakater/Reloader
- name: server-config
- files:
+ files:
- server.yml
- namespace: TESTNAMESPACE # select namespace for whole application
+ namespace: TESTNAMESPACE # select namespace for whole application
```
+
=== "ntfy-deployment.yaml"
+
```yaml
apiVersion: apps/v1
kind: Deployment
@@ -514,7 +559,7 @@ kubectl apply -k /ntfy
app: ntfy-pod
spec:
containers:
- - name: ntfy
+ - name: ntfy
image: binwiederhier/ntfy:v1.28.0 # set deployed version
args: ["serve"]
env: #example of adjustments made in environmental variables
@@ -525,8 +570,8 @@ kubectl apply -k /ntfy
- name: NTFY_LOG_LEVEL # adjust log level
value: INFO
- name: NTFY_BASE_URL # add base url
- value: XXXXXXXXXX
- ports:
+ value: XXXXXXXXXX
+ ports:
- containerPort: 80
name: http-ntfy
resources:
@@ -550,8 +595,9 @@ kubectl apply -k /ntfy
persistentVolumeClaim: # stores /cache/ntfy in defined pv
claimName: ntfy-pvc
```
-
+
=== "ntfy-pvc.yaml"
+
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
@@ -567,11 +613,12 @@ kubectl apply -k /ntfy
```
=== "ntfy-svc.yaml"
+
```yaml
apiVersion: v1
kind: Service
metadata:
- name: ntfy-svc
+ name: ntfy-svc
spec:
type: ClusterIP
selector:
@@ -584,6 +631,7 @@ kubectl apply -k /ntfy
```
=== "ntfy-ingress.yaml"
+
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
@@ -604,6 +652,7 @@ kubectl apply -k /ntfy
```
=== "server.yml"
+
```yaml
cache-file: "/var/cache/ntfy/cache.db"
attachment-cache-dir: "/var/cache/ntfy/attachments"
diff --git a/docs/integrations.md b/docs/integrations.md
index d1a4d42c..dd9b7fd8 100644
--- a/docs/integrations.md
+++ b/docs/integrations.md
@@ -41,7 +41,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [FindMyDevice](https://gitlab.com/Nulide/findmydevice/) - Find your Device with an SMS or online with the help of FMDServer
- [Tox Push Message App](https://github.com/zoff99/tox_push_msg_app) - Tox Push Message App
-## Libraries
+## Libraries
- [ntfy-php-library](https://github.com/VerifiedJoseph/ntfy-php-library) - PHP library for sending messages using a ntfy server (PHP)
- [ntfy-notifier](https://github.com/DAcodedBEAT/ntfy-notifier) - Symfony Notifier integration for ntfy (PHP)
@@ -66,7 +66,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [ntfyr](https://github.com/haxwithaxe/ntfyr) - A simple commandline tool to send notifications to ntfy
- [ntfy.py](https://github.com/ioqy/ntfy-client-python) - ntfy.py is a simple nfty.sh client for sending notifications
-## Projects + scripts
+## Projects + scripts
- [Grafana-to-ntfy](https://github.com/kittyandrew/grafana-to-ntfy) - Grafana-to-ntfy alerts channel (Rust)
- [Grafana-ntfy-webhook-integration](https://github.com/academo/grafana-alerting-ntfy-webhook-integration) - Integrates Grafana alerts webhooks (Go)
@@ -77,9 +77,9 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [ntfy.el](https://github.com/shombando/ntfy) - Send notifications from Emacs (Emacs)
- [backup-projects](https://gist.github.com/anthonyaxenov/826ba65abbabd5b00196bc3e6af76002) - Stupidly simple backup script for own projects (Shell)
- [grav-plugin-whistleblower](https://github.com/Himmlisch-Studios/grav-plugin-whistleblower) - Grav CMS plugin to get notifications via ntfy (PHP)
-- [ntfy-server-status](https://github.com/filip2cz/ntfy-server-status) - Checking if server is online and reporting through ntfy (C)
+- [ntfy-server-status](https://github.com/filip2cz/ntfy-server-status) - Checking if server is online and reporting through ntfy (C)
- [borg-based backup](https://github.com/davidhi7/backup) - Simple borg-based backup script with notifications based on ntfy.sh or Discord webhooks (Python/Shell)
-- [ntfy.sh *arr script](https://github.com/agent-squirrel/nfty-arr-script) - Quick and hacky script to get sonarr/radarr to notify the ntfy.sh service (Shell)
+- [ntfy.sh \*arr script](https://github.com/agent-squirrel/nfty-arr-script) - Quick and hacky script to get sonarr/radarr to notify the ntfy.sh service (Shell)
- [website-watcher](https://github.com/muety/website-watcher) - A small tool to watch websites for changes (with XPath support) (Python)
- [siteeagle](https://github.com/tpanum/siteeagle) - A small Python script to monitor websites and notify changes (Python)
- [send_to_phone](https://github.com/whipped-cream/send_to_phone) - Scripts to upload a file to Transfer.sh and ping ntfy with the download link (Python)
@@ -103,7 +103,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [ntfy-notification-channel](https://github.com/wijourdil/ntfy-notification-channel) - Laravel Notification channel for ntfy (PHP)
- [ntfy_on_a_chip](https://github.com/gergepalfi/ntfy_on_a_chip) - ESP8266 and ESP32 client code to communicate with ntfy
- [ntfy-sdk](https://github.com/yukibtc/ntfy-sdk) - ntfy client library to send notifications (Rust)
-- [ntfy_ynh](https://github.com/YunoHost-Apps/ntfy_ynh) - ntfy app for YunoHost
+- [ntfy_ynh](https://github.com/YunoHost-Apps/ntfy_ynh) - ntfy app for YunoHost
- [woodpecker-ntfy](https://codeberg.org/l-x/woodpecker-ntfy)- Woodpecker CI plugin for sending ntfy notfication from a pipeline (Go)
- [drone-ntfy](https://github.com/Clortox/drone-ntfy) - Drone.io plugin for sending ntfy notifications from a pipeline (Shell)
- [ignition-ntfy-module](https://github.com/Kyvis-Labs/ignition-ntfy-module) - Adds support for sending notifications via a ntfy server to Ignition (Java)
@@ -125,31 +125,31 @@ I've added a ⭐ to projects or posts that have a significant following, or had
## Blog + forum posts
- [ntfy: des notifications instantanées](https://blogmotion.fr/diy/ntfy-notification-push-domotique-20708) - blogmotion.fr - 5/2023
-- [桌面通知:ntfy](https://www.cnblogs.com/xueweihan/archive/2023/05/04/17370060.html) - cnblogs.com - 5/2023
-- [ntfy.sh - Open source push notifications via PUT/POST](https://lobste.rs/s/5drapz/ntfy_sh_open_source_push_notifications) - lobste.rs - 5/2023
-- [Install ntfy Inside Docker Container in Linux](https://lindevs.com/install-ntfy-inside-docker-container-in-linux) - lindevs.com - 4/2023
-- [ntfy.sh](https://neo-sahara.com/wp/2023/03/25/ntfy-sh/) - neo-sahara.com - 3/2023
-- [Using Ntfy to send and receive push notifications - Samuel Rosa de Oliveria - Delphicon 2023](https://www.youtube.com/watch?v=feu0skpI9QI) - youtube.com - 3/2023
-- [ntfy: własny darmowy system powiadomień](https://sprawdzone.it/ntfy-wlasny-darmowy-system-powiadomien/) - sprawdzone.it - 3/2023
+- [桌面通知:ntfy](https://www.cnblogs.com/xueweihan/archive/2023/05/04/17370060.html) - cnblogs.com - 5/2023
+- [ntfy.sh - Open source push notifications via PUT/POST](https://lobste.rs/s/5drapz/ntfy_sh_open_source_push_notifications) - lobste.rs - 5/2023
+- [Install ntfy Inside Docker Container in Linux](https://lindevs.com/install-ntfy-inside-docker-container-in-linux) - lindevs.com - 4/2023
+- [ntfy.sh](https://neo-sahara.com/wp/2023/03/25/ntfy-sh/) - neo-sahara.com - 3/2023
+- [Using Ntfy to send and receive push notifications - Samuel Rosa de Oliveria - Delphicon 2023](https://www.youtube.com/watch?v=feu0skpI9QI) - youtube.com - 3/2023
+- [ntfy: własny darmowy system powiadomień](https://sprawdzone.it/ntfy-wlasny-darmowy-system-powiadomien/) - sprawdzone.it - 3/2023
- [Deploying ntfy on railway](https://www.youtube.com/watch?v=auJICXtxoNA) - youtube.com - 3/2023
-- [Start-Job,Variables, and ntfy.sh](https://klingele.dev/2023/03/01/start-jobvariables-and-ntfy-sh/) - klingele.dev - 3/2023
-- [enviar notificaciones automáticas usando ntfy.sh](https://osiux.com/2023-02-15-send-automatic-notifications-using-ntfy.html) - osiux.com - 2/2023
-- [Carnet IP动态解析以及通过ntfy推送IP信息](https://blog.wslll.cn/index.php/archives/201/) - blog.wslll.cn - 2/2023
-- [Open-Source-Brieftaube: ntfy verschickt Push-Meldungen auf Smartphone und PC](https://www.heise.de/news/Open-Source-Brieftaube-ntfy-verschickt-Push-Meldungen-auf-Smartphone-und-PC-7521583.html) ⭐ - heise.de - 2/2023
+- [Start-Job,Variables, and ntfy.sh](https://klingele.dev/2023/03/01/start-jobvariables-and-ntfy-sh/) - klingele.dev - 3/2023
+- [enviar notificaciones automáticas usando ntfy.sh](https://osiux.com/2023-02-15-send-automatic-notifications-using-ntfy.html) - osiux.com - 2/2023
+- [Carnet IP 动态解析以及通过 ntfy 推送 IP 信息](https://blog.wslll.cn/index.php/archives/201/) - blog.wslll.cn - 2/2023
+- [Open-Source-Brieftaube: ntfy verschickt Push-Meldungen auf Smartphone und PC](https://www.heise.de/news/Open-Source-Brieftaube-ntfy-verschickt-Push-Meldungen-auf-Smartphone-und-PC-7521583.html) ⭐ - heise.de - 2/2023
- [Video: Simple Push Notifications ntfy](https://www.youtube.com/watch?v=u9EcWrsjE20) ⭐ - youtube.com - 2/2023
-- [Use ntfy.sh with Home Assistant](https://diecknet.de/en/2023/02/12/ntfy-sh-with-homeassistant/) - diecknet.de - 2/2023
-- [On installe Ntfy sur Synology Docker](https://www.maison-et-domotique.com/140356-serveur-notification-jeedom-ntfy-synology-docker/) - maison-et-domotique.co - 1/2023
+- [Use ntfy.sh with Home Assistant](https://diecknet.de/en/2023/02/12/ntfy-sh-with-homeassistant/) - diecknet.de - 2/2023
+- [On installe Ntfy sur Synology Docker](https://www.maison-et-domotique.com/140356-serveur-notification-jeedom-ntfy-synology-docker/) - maison-et-domotique.co - 1/2023
- [January 2023 Developer Update](https://community.nodebb.org/topic/16908/january-2023-developer-update) - nodebb.org - 1/2023
- [Comment envoyer des notifications push sur votre téléphone facilement et gratuitement?](https://korben.info/notifications-push-telephone.html) - 1/2023
- [UnifiedPush: a decentralized, open-source push notification protocol](https://f-droid.org/en/2022/12/18/unifiedpush.html) ⭐ - 12/2022
- [ntfy setup instructions](https://docs.benjamin-altpeter.de/network/vms/1001029-ntfy/) - benjamin-altpeter.de - 12/2022
-- [Ntfy Self-Hosted Push Notifications](https://lachlanlife.net/posts/2022-12-ntfy/) - lachlanlife.net - 12/2022
+- [Ntfy Self-Hosted Push Notifications](https://lachlanlife.net/posts/2022-12-ntfy/) - lachlanlife.net - 12/2022
- [NTFY - système de notification hyper simple et complet](https://www.youtube.com/watch?v=UieZYWVVgA4) - youtube.com - 12/2022
- [ntfy.sh](https://paramdeo.com/til/ntfy-sh) - paramdeo.com - 11/2022
- [Using ntfy to warn me when my computer is discharging](https://ulysseszh.github.io/programming/2022/11/28/ntfy-warn-discharge.html) - ulysseszh.github.io - 11/2022
-- [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022
+- [ntfy - Push Notification Service](https://dizzytech.de/posts/ntfy/) - dizzytech.de - 11/2022
- [Console #132](https://console.substack.com/p/console-132) ⭐ - console.substack.com - 11/2022
-- [How to make my phone buzz*](https://evbogue.com/howtomakemyphonebuzz) - evbogue.com - 11/2022
+- [How to make my phone buzz\*](https://evbogue.com/howtomakemyphonebuzz) - evbogue.com - 11/2022
- [MeshCentral - Ntfy Push Notifications ](https://www.youtube.com/watch?v=wyE4rtUd4Bg) - youtube.com - 11/2022
- [Changelog | Tracking layoffs, tech worker demand still high, ntfy, ...](https://changelog.com/news/tracking-layoffs-tech-worker-demand-still-high-ntfy-devenv-markdoc-mike-bifulco-Y1jW) ⭐ - changelog.com - 11/2022
- [Pointer | Issue #367](https://www.pointer.io/archives/a9495a2a6f/) - pointer.io - 11/2022
@@ -161,20 +161,20 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [Crea tu propio servidor de notificaciones con Ntfy](https://blog.parravidales.es/crea-tu-propio-servidor-de-notificaciones-con-ntfy/) - blog.parravidales.es - 11/2022
- [unRAID Notifications with ntfy.sh](https://lder.dev/posts/ntfy-Notifications-With-unRAID/) - lder.dev - 10/2022
- [Zero-cost push notifications to your phone or desktop via PUT/POST ](https://lobste.rs/s/41dq13/zero_cost_push_notifications_your_phone) - lobste.rs - 10/2022
-- [A nifty push notification system: ntfy](https://jpmens.net/2022/10/30/a-nifty-push-notification-system-ntfy/) - jpmens.net - 10/2022
+- [A nifty push notification system: ntfy](https://jpmens.net/2022/10/30/a-nifty-push-notification-system-ntfy/) - jpmens.net - 10/2022
- [Alarmanlage der dritten Art (YouTube video)](https://www.youtube.com/watch?v=altb5QLHbaU&feature=youtu.be) - youtube.com - 10/2022
- [Neue Services: Ntfy, TikTok und RustDesk](https://adminforge.de/tools/neue-services-ntfy-tiktok-und-rustdesk/) - adminforge.de - 9/2022
- [Ntfy, le service de notifications qu’il vous faut](https://www.cachem.fr/ntfy-le-service-de-notifications-quil-vous-faut/) - cachem.fr - 9/2022
-- [NAS Synology et notifications avec ntfy](https://www.cachem.fr/synology-notifications-ntfy/) - cachem.fr - 9/2022
+- [NAS Synology et notifications avec ntfy](https://www.cachem.fr/synology-notifications-ntfy/) - cachem.fr - 9/2022
- [Self hosted Mobile Push Notifications using NTFY | Thejesh GN](https://thejeshgn.com/2022/08/23/self-hosted-mobile-push-notifications-using-ntfy/) - thejeshgn.com - 8/2022
- [Fedora Magazine | 4 cool new projects to try in Copr](https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-for-august-2022/) - fedoramagazine.org - 8/2022
- [Docker로 오픈소스 푸시알람 프로젝트 ntfy.sh 설치 및 사용하기.(Feat. Uptimekuma)](https://svrforum.com/svr/398979) - svrforum.com - 8/2022
- [Easy notifications from R](https://sometimesir.com/posts/easy-notifications-from-r/) - sometimesir.com - 6/2022
- [ntfy is finally coming to iOS, and Matrix/UnifiedPush gateway support](https://www.reddit.com/r/selfhosted/comments/vdzvxi/ntfy_is_finally_coming_to_ios_with_full/) ⭐ - reddit.com - 6/2022
- [Install guide (with Docker)](https://chowdera.com/2022/150/202205301257379077.html) - chowdera.com - 5/2022
-- [无需注册的通知服务ntfy](https://blog.csdn.net/wbsu2004/article/details/125040247) - blog.csdn.net - 5/2022
+- [无需注册的通知服务 ntfy](https://blog.csdn.net/wbsu2004/article/details/125040247) - blog.csdn.net - 5/2022
- [Updated review post (Jan-Lukas Else)](https://jlelse.blog/thoughts/2022/04/ntfy) - jlelse.blog - 4/2022
-- [Using ntfy and Tasker together](https://lachlanlife.net/posts/2022-04-tasker-ntfy/) - lachlanlife.net - 4/2022
+- [Using ntfy and Tasker together](https://lachlanlife.net/posts/2022-04-tasker-ntfy/) - lachlanlife.net - 4/2022
- [Reddit feature update post](https://www.reddit.com/r/selfhosted/comments/uetlso/ntfy_is_a_tool_to_send_push_notifications_to_your/) ⭐ - reddit.com - 4/2022
- [無料で簡単に通知の送受信ができつつオープンソースでセルフホストも可能な「ntfy」を使ってみた](https://gigazine.net/news/20220404-ntfy-push-notification/) - gigazine.net - 4/2022
- [Pocketmags ntfy review](https://pocketmags.com/us/linux-format-magazine/march-2022/articles/1104187/ntfy) - pocketmags.com - 3/2022
@@ -188,15 +188,14 @@ I've added a ⭐ to projects or posts that have a significant following, or had
- [Show HN: A tool to send push notifications to your phone, written in Go](https://news.ycombinator.com/item?id=29715464) ⭐ - news.ycombinator.com - 12/2021
- [Reddit selfhostable post](https://www.reddit.com/r/selfhosted/comments/qxlsm9/my_open_source_notification_android_app_and/) ⭐ - reddit.com - 11/2021
-
## Alternative ntfy servers
Here's a list of public ntfy servers. As of right now, there is only one official server. The others are provided by the
ntfy community. Thanks to everyone running a public server. **You guys rock!**
-| URL | Country |
-|---------------------------------------------------|--------------------|
-| [ntfy.sh](https://ntfy.sh/) (*Official*) | 🇺🇸 United States |
+| URL | Country |
+| ------------------------------------------------- | ---------------- |
+| [ntfy.sh](https://ntfy.sh/) (_Official_) | 🇺🇸 United States |
| [ntfy.tedomum.net](https://ntfy.tedomum.net/) | 🇫🇷 France |
| [ntfy.jae.fi](https://ntfy.jae.fi/) | 🇫🇮 Finland |
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
diff --git a/docs/known-issues.md b/docs/known-issues.md
index f0528422..8f89e704 100644
--- a/docs/known-issues.md
+++ b/docs/known-issues.md
@@ -1,9 +1,11 @@
# Known issues
+
This is an incomplete list of known issues with the ntfy server, Android app, and iOS app. You can find a complete
list [on GitHub](https://github.com/binwiederhier/ntfy/labels/%F0%9F%AA%B2%20bug), but I thought it may be helpful
to have the prominent ones here to link to.
## iOS app not refreshing (see [#267](https://github.com/binwiederhier/ntfy/issues/267))
+
For some (many?) users, the iOS app is not refreshing the view when new notifications come in. Until you manually
swipe down, you do not see the newly arrived messages, even though the popup appeared before.
@@ -13,16 +15,17 @@ clueless on how to fix it, sadly, as it is ephemeral and not clear to me what is
Please send experienced iOS developers my way to help me figure this out.
## iOS app not receiving notifications (anymore)
+
If notifications do not show up at all anymore, there are a few causes for it (that I know of):
-**Firebase+APNS are being weird and buggy**:
-If this is the case, usually it helps to **remove the topic/subscription and re-add it**. That will force Firebase to
+**Firebase+APNS are being weird and buggy**:
+If this is the case, usually it helps to **remove the topic/subscription and re-add it**. That will force Firebase to
re-subscribe to the Firebase topic.
-**Self-hosted only: No `upstream-base-url` set, or `base-url` mismatch**:
+**Self-hosted only: No `upstream-base-url` set, or `base-url` mismatch**:
To make self-hosted servers work with the iOS
app, I had to do some horrible things (see [iOS instant notifications](config.md#ios-instant-notifications) for details).
Be sure that in your selfhosted server:
-* Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**)
-* Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to
+- Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**)
+- Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to
diff --git a/docs/privacy.md b/docs/privacy.md
index f89f9aaa..e2934eeb 100644
--- a/docs/privacy.md
+++ b/docs/privacy.md
@@ -8,5 +8,5 @@ any outside service. All data is exclusively used to make the service function p
I use is Firebase Cloud Messaging (FCM) service, which is required to provide instant Android notifications (see
[FAQ](faq.md) for details). To avoid FCM altogether, download the F-Droid version.
-For debugging purposes, the ntfy server may temporarily log request paths, remote IP addresses or even topics
+For debugging purposes, the ntfy server may temporarily log request paths, remote IP addresses or even topics
or messages, though typically this is turned off.
diff --git a/docs/publish.md b/docs/publish.md
index 11e33e61..bac8f8cb 100644
--- a/docs/publish.md
+++ b/docs/publish.md
@@ -1,29 +1,35 @@
# Publishing
-Publishing messages can be done via HTTP PUT/POST or via the [ntfy CLI](install.md). Topics are created on the fly by
-subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick
+
+Publishing messages can be done via HTTP PUT/POST or via the [ntfy CLI](install.md). Topics are created on the fly by
+subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick
something that's not easily guessable.
Here's an example showing how to publish a simple message using a POST request:
=== "Command line (curl)"
+
```
curl -d "Backup successful 😀" ntfy.sh/mytopic
```
=== "ntfy CLI"
+
```
ntfy publish mytopic "Backup successful 😀"
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Backup successful 😀
```
+
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST', // PUT works too
body: 'Backup successful 😀'
@@ -31,13 +37,15 @@ Here's an example showing how to publish a simple message using a POST request:
```
=== "Go"
- ``` go
+
+ ```go
http.Post("https://ntfy.sh/mytopic", "text/plain",
strings.NewReader("Backup successful 😀"))
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/mytopic"
@@ -47,13 +55,15 @@ Here's an example showing how to publish a simple message using a POST request:
```
=== "Python"
- ``` python
- requests.post("https://ntfy.sh/mytopic",
+
+ ```python
+ requests.post("https://ntfy.sh/mytopic",
data="Backup successful 😀".encode(encoding='utf-8'))
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -70,10 +80,11 @@ If you have the [Android app](subscribe/phone.md) installed on your phone, this
Android notification
-There are more features related to publishing messages: You can set a [notification priority](#message-priority),
+There are more features related to publishing messages: You can set a [notification priority](#message-priority),
a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an example that uses some of them at together:
=== "Command line (curl)"
+
```
curl \
-H "Title: Unauthorized access detected" \
@@ -84,6 +95,7 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
```
=== "ntfy CLI"
+
```
ntfy publish \
--title "Unauthorized access detected" \
@@ -94,18 +106,20 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
```
=== "HTTP"
- ``` http
+
+ ```http
POST /phil_alerts HTTP/1.1
Host: ntfy.sh
Title: Unauthorized access detected
Priority: urgent
Tags: warning,skull
-
+
Remote access to phils-laptop detected. Act right away.
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/phil_alerts', {
method: 'POST', // PUT works too
body: 'Remote access to phils-laptop detected. Act right away.',
@@ -118,17 +132,19 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
```
=== "Go"
- ``` go
- req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts",
- strings.NewReader("Remote access to phils-laptop detected. Act right away."))
- req.Header.Set("Title", "Unauthorized access detected")
- req.Header.Set("Priority", "urgent")
- req.Header.Set("Tags", "warning,skull")
- http.DefaultClient.Do(req)
+
+ ```go
+ req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts",
+ strings.NewReader("Remote access to phils-laptop detected. Act right away."))
+ req.Header.Set("Title", "Unauthorized access detected")
+ req.Header.Set("Priority", "urgent")
+ req.Header.Set("Tags", "warning,skull")
+ http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/phil_alerts"
@@ -138,12 +154,13 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
Tags = "warning,skull"
}
Body = "Remote access to phils-laptop detected. Act right away."
- }
+ }
Invoke-RestMethod @Request
```
-
+
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/phil_alerts",
data="Remote access to phils-laptop detected. Act right away.",
headers={
@@ -154,7 +171,8 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -177,6 +195,7 @@ You can also do multi-line messages. Here's an example using a [click action](#c
an [external image attachment](#attach-file-from-a-url) and [email publishing](#e-mail-publishing):
=== "Command line (curl)"
+
```
curl \
-H "Click: https://home.nest.com/" \
@@ -184,74 +203,79 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
-H "Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true" \
-H "Email: phil@example.com" \
-d "There's someone at the door. 🐶
-
- Please check if it's a good boy or a hooman.
+
+ Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell." \
ntfy.sh/mydoorbell
```
=== "ntfy CLI"
+
```
ntfy publish \
- --click="https://home.nest.com/" \
+ --click="https://home.nest.com/" \
--attach="https://nest.com/view/yAxkasd.jpg" \
--actions="http, Open door, https://api.nest.com/open/yAxkasd, clear=true" \
--email="phil@example.com" \
mydoorbell \
"There's someone at the door. 🐶
-
- Please check if it's a good boy or a hooman.
+
+ Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell."
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mydoorbell HTTP/1.1
Host: ntfy.sh
Click: https://home.nest.com/
Attach: https://nest.com/view/yAxkasd.jpg
Actions: http, Open door, https://api.nest.com/open/yAxkasd, clear=true
Email: phil@example.com
-
+
There's someone at the door. 🐶
-
- Please check if it's a good boy or a hooman.
+
+ Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell.
```
-
+
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mydoorbell', {
method: 'POST', // PUT works too
headers: {
'Click': 'https://home.nest.com/',
'Attach': 'https://nest.com/view/yAxkasd.jpg',
- 'Actions': 'http, Open door, https://api.nest.com/open/yAxkasd, clear=true',
- 'Email': 'phil@example.com'
+ 'Actions': 'http, Open door, https://api.nest.com/open/yAxkasd, clear=true',
+ 'Email': 'phil@example.com'
},
body: `There's someone at the door. 🐶
-
- Please check if it's a good boy or a hooman.
+
+ Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell.`,
})
```
=== "Go"
- ``` go
- req, _ := http.NewRequest("POST", "https://ntfy.sh/mydoorbell",
- strings.NewReader(`There's someone at the door. 🐶
-
- Please check if it's a good boy or a hooman.
+
+ ```go
+ req, _ := http.NewRequest("POST", "https://ntfy.sh/mydoorbell",
+ strings.NewReader(`There's someone at the door. 🐶
+
+ Please check if it's a good boy or a hooman.
Doggies have been known to ring the doorbell.`))
- req.Header.Set("Click", "https://home.nest.com/")
- req.Header.Set("Attach", "https://nest.com/view/yAxkasd.jpg")
- req.Header.Set("Actions", "http, Open door, https://api.nest.com/open/yAxkasd, clear=true")
- req.Header.Set("Email", "phil@example.com")
- http.DefaultClient.Do(req)
+ req.Header.Set("Click", "https://home.nest.com/")
+ req.Header.Set("Attach", "https://nest.com/view/yAxkasd.jpg")
+ req.Header.Set("Actions", "http, Open door, https://api.nest.com/open/yAxkasd, clear=true")
+ req.Header.Set("Email", "phil@example.com")
+ http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/mydoorbell"
@@ -270,7 +294,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/mydoorbell",
data="""There's someone at the door. 🐶
@@ -285,7 +310,8 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mydoorbell', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -296,7 +322,7 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
"Actions": "http, Open door, https://api.nest.com/open/yAxkasd, clear=true\r\n" .
"Email": "phil@example.com\r\n",
'content' => 'There\'s someone at the door. 🐶
-
+
Please check if it\'s a good boy or a hooman.
Doggies have been known to ring the doorbell.'
]
@@ -309,12 +335,14 @@ an [external image attachment](#attach-file-from-a-url) and [email publishing](#
## Message title
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title,
+The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title,
you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
=== "Command line (curl)"
+
```
curl -H "X-Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
curl -H "Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
@@ -322,6 +350,7 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
```
=== "ntfy CLI"
+
```
ntfy publish \
-t "Dogs are better than cats" \
@@ -329,16 +358,18 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
```
=== "HTTP"
- ``` http
+
+ ```http
POST /controversial HTTP/1.1
Host: ntfy.sh
Title: Dogs are better than cats
-
+
Oh my ...
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/controversial', {
method: 'POST',
body: 'Oh my ...',
@@ -347,14 +378,16 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/controversial", strings.NewReader("Oh my ..."))
req.Header.Set("Title", "Dogs are better than cats")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/controversial"
@@ -367,14 +400,16 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/controversial",
data="Oh my ...",
headers={ "Title": "Dogs are better than cats" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/controversial', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -392,12 +427,13 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
!!! info
- ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
- If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including the title)
- as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
- or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
+ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
+If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including the title)
+as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
## Message priority
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
All messages have a priority, which defines how urgently your phone notifies you. On Android, you can set custom
@@ -406,16 +442,17 @@ notification sounds and vibration patterns on your phone to map to these priorit
The following priorities exist:
| Priority | Icon | ID | Name | Description |
-|----------------------|--------------------------------------------|-----|----------------|--------------------------------------------------------------------------------------------------------|
+| -------------------- | ------------------------------------------ | --- | -------------- | ------------------------------------------------------------------------------------------------------ |
| Max priority |  | `5` | `max`/`urgent` | Really long vibration bursts, default notification sound with a pop-over notification. |
| High priority |  | `4` | `high` | Long vibration burst, default notification sound with a pop-over notification. |
-| **Default priority** | *(none)* | `3` | `default` | Short default vibration and sound. Default notification behavior. |
+| **Default priority** | _(none)_ | `3` | `default` | Short default vibration and sound. Default notification behavior. |
| Low priority |  | `2` | `low` | No vibration or sound. Notification will not visibly show up until notification drawer is pulled down. |
| Min priority |  | `1` | `min` | No vibration or sound. The notification will be under the fold in "Other notifications". |
You can set the priority with the header `X-Priority` (or any of its aliases: `Priority`, `prio`, or `p`).
=== "Command line (curl)"
+
```
curl -H "X-Priority: 5" -d "An urgent message" ntfy.sh/phil_alerts
curl -H "Priority: low" -d "Low priority message" ntfy.sh/phil_alerts
@@ -423,14 +460,16 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
```
=== "ntfy CLI"
+
```
- ntfy publish \
+ ntfy publish \
-p 5 \
phil_alerts An urgent message
```
=== "HTTP"
- ``` http
+
+ ```http
POST /phil_alerts HTTP/1.1
Host: ntfy.sh
Priority: 5
@@ -439,7 +478,8 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/phil_alerts', {
method: 'POST',
body: 'An urgent message',
@@ -448,14 +488,16 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts", strings.NewReader("An urgent message"))
req.Header.Set("Priority", "5")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
URI = "https://ntfy.sh/phil_alerts"
Headers = @{
@@ -465,16 +507,18 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
}
Invoke-RestMethod @Request
```
-
+
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/phil_alerts",
data="An urgent message",
headers={ "Priority": "5" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -492,16 +536,17 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
## Tags & emojis 🥳 🎉
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
You can tag messages with emojis and other relevant strings:
-* **Emojis**: If a tag matches an [emoji short code](emojis.md), it'll be converted to an emoji and prepended
+- **Emojis**: If a tag matches an [emoji short code](emojis.md), it'll be converted to an emoji and prepended
to title or message.
-* **Other tags:** If a tag doesn't match, it will be listed below the notification.
+- **Other tags:** If a tag doesn't match, it will be listed below the notification.
-This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script
-names, hostnames, etc.). Use [the emoji short code list](emojis.md) to figure out what tags can be converted to emojis.
+This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script
+names, hostnames, etc.). Use [the emoji short code list](emojis.md) to figure out what tags can be converted to emojis.
Here's an **excerpt of emojis** I've found very useful in alert messages:
@@ -541,6 +586,7 @@ You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, `tag`,
them with a comma, e.g. `tag1,tag2,tag3`.
=== "Command line (curl)"
+
```
curl -H "X-Tags: warning,mailsrv13,daily-backup" -d "Backup of mailsrv13 failed" ntfy.sh/backups
curl -H "Tags: horse,unicorn" -d "Unicorns are just horses with unique horns" ntfy.sh/backups
@@ -548,6 +594,7 @@ them with a comma, e.g. `tag1,tag2,tag3`.
```
=== "ntfy CLI"
+
```
ntfy publish \
--tags=warning,mailsrv13,daily-backup \
@@ -555,16 +602,18 @@ them with a comma, e.g. `tag1,tag2,tag3`.
```
=== "HTTP"
- ``` http
+
+ ```http
POST /backups HTTP/1.1
Host: ntfy.sh
Tags: warning,mailsrv13,daily-backup
-
+
Backup of mailsrv13 failed
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/backups', {
method: 'POST',
body: 'Backup of mailsrv13 failed',
@@ -573,14 +622,16 @@ them with a comma, e.g. `tag1,tag2,tag3`.
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/backups", strings.NewReader("Backup of mailsrv13 failed"))
req.Header.Set("Tags", "warning,mailsrv13,daily-backup")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/backups"
@@ -593,14 +644,16 @@ them with a comma, e.g. `tag1,tag2,tag3`.
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/backups",
data="Backup of mailsrv13 failed",
headers={ "Tags": "warning,mailsrv13,daily-backup" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/backups', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -618,32 +671,34 @@ them with a comma, e.g. `tag1,tag2,tag3`.
!!! info
- ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
- If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the tags header or individual tags
- as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `tag1,=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
- or `=?UTF-8?Q?=C3=84pfel?=,tag2` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
+ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
+If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode the tags header or individual tags
+as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `tag1,=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+or `=?UTF-8?Q?=C3=84pfel?=,tag2` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
## Scheduled delivery
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself
+You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself
reminders or even to execute commands at a later date (if your subscriber acts on messages).
-Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`,
-`X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`,
-`3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`,
-[and more](https://github.com/olebedev/when)).
+Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`,
+`X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`,
+`3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`,
+[and more](https://github.com/olebedev/when)).
As of today, the minimum delay you can set is **10 seconds** and the maximum delay is **3 days**. This can currently
-not be configured otherwise ([let me know](https://github.com/binwiederhier/ntfy/issues) if you'd like to change
+not be configured otherwise ([let me know](https://github.com/binwiederhier/ntfy/issues) if you'd like to change
these limits).
-For the purposes of [message caching](config.md#message-cache), scheduled messages are kept in the cache until 12 hours
+For the purposes of [message caching](config.md#message-cache), scheduled messages are kept in the cache until 12 hours
after they were delivered (or whatever the server-side cache duration is set to). For instance, if a message is scheduled
-to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally,
-[turning off server-side caching](#message-caching) is not possible in combination with this feature.
+to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally,
+[turning off server-side caching](#message-caching) is not possible in combination with this feature.
=== "Command line (curl)"
+
```
curl -H "At: tomorrow, 10am" -d "Good morning" ntfy.sh/hello
curl -H "In: 30min" -d "It's 30 minutes later now" ntfy.sh/reminder
@@ -651,6 +706,7 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
```
=== "ntfy CLI"
+
```
ntfy publish \
--at="tomorrow, 10am" \
@@ -658,7 +714,8 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
```
=== "HTTP"
- ``` http
+
+ ```http
POST /hello HTTP/1.1
Host: ntfy.sh
At: tomorrow, 10am
@@ -667,7 +724,8 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/hello', {
method: 'POST',
body: 'Good morning',
@@ -676,14 +734,16 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/hello", strings.NewReader("Good morning"))
req.Header.Set("At", "tomorrow, 10am")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/hello"
@@ -694,16 +754,18 @@ to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Al
}
Invoke-RestMethod @Request
```
-
+
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/hello",
data="Good morning",
headers={ "At": "tomorrow, 10am" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/backups', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -730,74 +792,85 @@ Here are a few examples (assuming today's date is **12/10/2021, 9am, Eastern Tim
-## Webhooks (publish via GET)
+## Webhooks (publish via GET)
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-In addition to using PUT/POST, you can also send to topics via simple HTTP GET requests. This makes it easy to use
+In addition to using PUT/POST, you can also send to topics via simple HTTP GET requests. This makes it easy to use
a ntfy topic as a [webhook](https://en.wikipedia.org/wiki/Webhook), or if your client has limited HTTP support (e.g.
like the [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) Android app).
-To send messages via HTTP GET, simply call the `/publish` endpoint (or its aliases `/send` and `/trigger`). Without
-any arguments, this will send the message `triggered` to the topic. However, you can provide all arguments that are
-also supported as HTTP headers as URL-encoded arguments. Be sure to check the list of all
+To send messages via HTTP GET, simply call the `/publish` endpoint (or its aliases `/send` and `/trigger`). Without
+any arguments, this will send the message `triggered` to the topic. However, you can provide all arguments that are
+also supported as HTTP headers as URL-encoded arguments. Be sure to check the list of all
[supported parameters and headers](#list-of-all-parameters) for details.
-For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhook/trigger` to send a message
+For instance, assuming your topic is `mywebhook`, you can simply call `/mywebhook/trigger` to send a message
(aka trigger the webhook):
=== "Command line (curl)"
+
```
curl ntfy.sh/mywebhook/trigger
```
=== "ntfy CLI"
+
```
ntfy trigger mywebhook
```
=== "HTTP"
- ``` http
+
+ ```http
GET /mywebhook/trigger HTTP/1.1
Host: ntfy.sh
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mywebhook/trigger')
```
=== "Go"
- ``` go
+
+ ```go
http.Get("https://ntfy.sh/mywebhook/trigger")
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
Invoke-RestMethod "ntfy.sh/mywebhook/trigger"
- ```
+ ```
=== "Python"
- ``` python
+
+ ```python
requests.get("https://ntfy.sh/mywebhook/trigger")
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mywebhook/trigger');
```
-To add a custom message, simply append the `message=` URL parameter. And of course you can set the
-[message priority](#message-priority), the [message title](#message-title), and [tags](#tags-emojis) as well.
+To add a custom message, simply append the `message=` URL parameter. And of course you can set the
+[message priority](#message-priority), the [message title](#message-title), and [tags](#tags-emojis) as well.
For a full list of possible parameters, check the list of [supported parameters and headers](#list-of-all-parameters).
Here's an example with a custom message, tags and a priority:
=== "Command line (curl)"
+
```
curl "ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull"
```
=== "ntfy CLI"
+
```
ntfy publish \
-p 5 --tags=warning,skull \
@@ -805,54 +878,62 @@ Here's an example with a custom message, tags and a priority:
```
=== "HTTP"
- ``` http
+
+ ```http
GET /mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull HTTP/1.1
Host: ntfy.sh
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull')
```
=== "Go"
- ``` go
+
+ ```go
http.Get("https://ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull")
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
Invoke-RestMethod "ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull"
```
=== "Python"
- ``` python
+
+ ```python
requests.get("https://ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull")
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mywebhook/publish?message=Webhook+triggered&priority=high&tags=warning,skull');
```
## Publish as JSON
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-For some integrations with other tools (e.g. [Jellyfin](https://jellyfin.org/), [overseerr](https://overseerr.dev/)),
-adding custom headers to HTTP requests may be tricky or impossible, so ntfy also allows publishing the entire message
+For some integrations with other tools (e.g. [Jellyfin](https://jellyfin.org/), [overseerr](https://overseerr.dev/)),
+adding custom headers to HTTP requests may be tricky or impossible, so ntfy also allows publishing the entire message
as JSON in the request body.
To publish as JSON, simple PUT/POST the JSON object directly to the ntfy root URL. The message format is described below
the example.
!!! info
- To publish as JSON, you must **PUT/POST to the ntfy root URL**, not to the topic URL. Be sure to check that you're
- POST-ing to `https://ntfy.sh/` (correct), and not to `https://ntfy.sh/mytopic` (incorrect).
+To publish as JSON, you must **PUT/POST to the ntfy root URL**, not to the topic URL. Be sure to check that you're
+POST-ing to `https://ntfy.sh/` (correct), and not to `https://ntfy.sh/mytopic` (incorrect).
-Here's an example using most supported parameters. Check the table below for a complete list. The `topic` parameter
+Here's an example using most supported parameters. Check the table below for a complete list. The `topic` parameter
is the only required one:
=== "Command line (curl)"
+
```
curl ntfy.sh \
-d '{
@@ -869,7 +950,8 @@ is the only required one:
```
=== "HTTP"
- ``` http
+
+ ```http
POST / HTTP/1.1
Host: ntfy.sh
@@ -887,7 +969,8 @@ is the only required one:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh', {
method: 'POST',
body: JSON.stringify({
@@ -905,11 +988,12 @@ is the only required one:
```
=== "Go"
- ``` go
+
+ ```go
// You should probably use json.Marshal() instead and make a proper struct,
- // or even just use req.Header.Set() like in the other examples, but for the
+ // or even just use req.Header.Set() like in the other examples, but for the
// sake of the example, this is easier.
-
+
body := `{
"topic": "mytopic",
"message": "Disk space is low at 5.1 GB",
@@ -926,7 +1010,8 @@ is the only required one:
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh"
@@ -940,7 +1025,7 @@ is the only required one:
Tags = @("warning", "cd")
Click = "https://homecamera.lan/xasds1h2xsSsa/"
Actions = ConvertTo-JSON @(
- @{
+ @{
Action = "view"
Label = "Admin panel"
URL = "https://filesrv.lan/admin"
@@ -953,7 +1038,8 @@ is the only required one:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/",
data=json.dumps({
"topic": "mytopic",
@@ -970,7 +1056,8 @@ is the only required one:
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -990,41 +1077,42 @@ is the only required one:
]));
```
-The JSON message format closely mirrors the format of the message you can consume when you [subscribe via the API](subscribe/api.md)
+The JSON message format closely mirrors the format of the message you can consume when you [subscribe via the API](subscribe/api.md)
(see [JSON message format](subscribe/api.md#json-message-format) for details), but is not exactly identical. Here's an overview of
all the supported fields:
| Field | Required | Type | Example | Description |
-|------------|----------|----------------------------------|-------------------------------------------|-----------------------------------------------------------------------|
-| `topic` | ✔️ | *string* | `topic1` | Target topic name |
-| `message` | - | *string* | `Some message` | Message body; set to `triggered` if empty or not passed |
-| `title` | - | *string* | `Some title` | Message [title](#message-title) |
-| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](#tags-emojis) that may or not map to emojis |
-| `priority` | - | *int (one of: 1, 2, 3, 4, or 5)* | `4` | Message [priority](#message-priority) with 1=min, 3=default and 5=max |
-| `actions` | - | *JSON array* | *(see [action buttons](#action-buttons))* | Custom [user action buttons](#action-buttons) for notifications |
-| `click` | - | *URL* | `https://example.com` | Website opened when notification is [clicked](#click-action) |
-| `attach` | - | *URL* | `https://example.com/file.jpg` | URL of an attachment, see [attach via URL](#attach-file-from-url) |
-| `icon` | - | *string* | `https://example.com/icon.png` | URL to use as notification [icon](#icons) |
-| `filename` | - | *string* | `file.jpg` | File name of the attachment |
-| `delay` | - | *string* | `30min`, `9am` | Timestamp or duration for delayed delivery |
-| `email` | - | *e-mail address* | `phil@example.com` | E-mail address for e-mail notifications |
-| `call` | - | *phone number or 'yes'* | `+1222334444` or `yes` | Phone number to use for [voice call](#phone-calls) |
+| ---------- | -------- | -------------------------------- | ----------------------------------------- | --------------------------------------------------------------------- |
+| `topic` | ✔️ | _string_ | `topic1` | Target topic name |
+| `message` | - | _string_ | `Some message` | Message body; set to `triggered` if empty or not passed |
+| `title` | - | _string_ | `Some title` | Message [title](#message-title) |
+| `tags` | - | _string array_ | `["tag1","tag2"]` | List of [tags](#tags-emojis) that may or not map to emojis |
+| `priority` | - | _int (one of: 1, 2, 3, 4, or 5)_ | `4` | Message [priority](#message-priority) with 1=min, 3=default and 5=max |
+| `actions` | - | _JSON array_ | _(see [action buttons](#action-buttons))_ | Custom [user action buttons](#action-buttons) for notifications |
+| `click` | - | _URL_ | `https://example.com` | Website opened when notification is [clicked](#click-action) |
+| `attach` | - | _URL_ | `https://example.com/file.jpg` | URL of an attachment, see [attach via URL](#attach-file-from-url) |
+| `icon` | - | _string_ | `https://example.com/icon.png` | URL to use as notification [icon](#icons) |
+| `filename` | - | _string_ | `file.jpg` | File name of the attachment |
+| `delay` | - | _string_ | `30min`, `9am` | Timestamp or duration for delayed delivery |
+| `email` | - | _e-mail address_ | `phil@example.com` | E-mail address for e-mail notifications |
+| `call` | - | _phone number or 'yes'_ | `+1222334444` or `yes` | Phone number to use for [voice call](#phone-calls) |
## Action buttons
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
You can add action buttons to notifications to allow yourself to react to a notification directly. This is incredibly
-useful and has countless applications.
+useful and has countless applications.
-You can control your home appliances (open/close garage door, change temperature on thermostat, ...), react to common
+You can control your home appliances (open/close garage door, change temperature on thermostat, ...), react to common
monitoring alerts (clear logs when disk is full, ...), and many other things. The sky is the limit.
As of today, the following actions are supported:
-* [`view`](#open-websiteapp): Opens a website or app when the action button is tapped
-* [`broadcast`](#send-android-broadcast): Sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent
+- [`view`](#open-websiteapp): Opens a website or app when the action button is tapped
+- [`broadcast`](#send-android-broadcast): Sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent
when the action button is tapped (only supported on Android)
-* [`http`](#send-http-request): Sends HTTP POST/GET/PUT request when the action button is tapped
+- [`http`](#send-http-request): Sends HTTP POST/GET/PUT request when the action button is tapped
Here's an example of what that a notification with actions can look like:
@@ -1034,35 +1122,40 @@ Here's an example of what that a notification with actions can look like:
### Defining actions
+
You can define **up to three user actions** in your notifications, using either of the following methods:
-* In the [`X-Actions` header](#using-a-header), using a simple comma-separated format
-* As a [JSON array](#using-a-json-array) in the `actions` key, when [publishing as JSON](#publish-as-json)
+- In the [`X-Actions` header](#using-a-header), using a simple comma-separated format
+- As a [JSON array](#using-a-json-array) in the `actions` key, when [publishing as JSON](#publish-as-json)
#### Using a header
+
To define actions using the `X-Actions` header (or any of its aliases: `Actions`, `Action`), use the following format:
=== "Header format (long)"
+
```
action=, label=, paramN=... [; action=, label=, ...]
```
=== "Header format (short)"
+
```
, , paramN=... [; , , ...]
```
-Multiple actions are separated by a semicolon (`;`), and key/value pairs are separated by commas (`,`). Values may be
-quoted with double quotes (`"`) or single quotes (`'`) if the value itself contains commas or semicolons.
+Multiple actions are separated by a semicolon (`;`), and key/value pairs are separated by commas (`,`). Values may be
+quoted with double quotes (`"`) or single quotes (`'`) if the value itself contains commas or semicolons.
-The `action=` and `label=` prefix are optional in all actions, and the `url=` prefix is optional in the `view` and
-`http` action. The only limitation of this format is that depending on your language/library, UTF-8 characters may not
+The `action=` and `label=` prefix are optional in all actions, and the `url=` prefix is optional in the `view` and
+`http` action. The only limitation of this format is that depending on your language/library, UTF-8 characters may not
work. If they don't, use the [JSON array format](#using-a-json-array) instead.
-As an example, here's how you can create the above notification using this format. Refer to the [`view` action](#open-websiteapp) and
+As an example, here's how you can create the above notification using this format. Refer to the [`view` action](#open-websiteapp) and
[`http` action](#send-http-request) section for details on the specific actions:
=== "Command line (curl)"
+
```
body='{"temperature": 65}'
curl \
@@ -1073,6 +1166,7 @@ As an example, here's how you can create the above notification using this forma
```
=== "ntfy CLI"
+
```
body='{"temperature": 65}'
ntfy publish \
@@ -1083,7 +1177,8 @@ As an example, here's how you can create the above notification using this forma
```
=== "HTTP"
- ``` http
+
+ ```http
POST /myhome HTTP/1.1
Host: ntfy.sh
Actions: view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body='{"temperature": 65}'
@@ -1092,25 +1187,28 @@ As an example, here's how you can create the above notification using this forma
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/myhome', {
method: 'POST',
body: 'You left the house. Turn down the A/C?',
- headers: {
- 'Actions': 'view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body=\'{"temperature": 65}\''
+ headers: {
+ 'Actions': 'view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body=\'{"temperature": 65}\''
}
})
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/myhome", strings.NewReader("You left the house. Turn down the A/C?"))
req.Header.Set("Actions", "view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body='{\"temperature\": 65}'")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/myhome"
@@ -1123,14 +1221,16 @@ As an example, here's how you can create the above notification using this forma
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/myhome",
data="You left the house. Turn down the A/C?",
headers={ "Actions": "view, Open portal, https://home.nest.com/, clear=true; http, Turn down, https://api.nest.com/, body='{\"temperature\": 65}'" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1143,16 +1243,18 @@ As an example, here's how you can create the above notification using this forma
```
!!! info
- ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
- If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including actions)
- as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
- or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
+ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
+If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any header (including actions)
+as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
#### Using a JSON array
-Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body
+
+Alternatively, the same actions can be defined as **JSON array**, if the notification is defined as part of the JSON body
(see [publish as JSON](#publish-as-json)):
=== "Command line (curl)"
+
```
curl ntfy.sh \
-d '{
@@ -1176,6 +1278,7 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions '[
@@ -1197,7 +1300,8 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "HTTP"
- ``` http
+
+ ```http
POST / HTTP/1.1
Host: ntfy.sh
@@ -1222,7 +1326,8 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh', {
method: 'POST',
body: JSON.stringify({
@@ -1247,10 +1352,11 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "Go"
- ``` go
+
+ ```go
// You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier.
-
+
body := `{
"topic": "myhome",
"message": "You left the house. Turn down the A/C?",
@@ -1274,7 +1380,8 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh"
@@ -1302,7 +1409,8 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/",
data=json.dumps({
"topic": "myhome",
@@ -1326,7 +1434,8 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1356,29 +1465,31 @@ Alternatively, the same actions can be defined as **JSON array**, if the notific
]));
```
-The required/optional fields for each action depend on the type of the action itself. Please refer to
-[`view` action](#open-websiteapp), [`broadcast` action](#send-android-broadcast), and [`http` action](#send-http-request)
+The required/optional fields for each action depend on the type of the action itself. Please refer to
+[`view` action](#open-websiteapp), [`broadcast` action](#send-android-broadcast), and [`http` action](#send-http-request)
for details.
### Open website/app
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
The `view` action **opens a website or app when the action button is tapped**, e.g. a browser, a Google Maps location, or
-even a deep link into Twitter or a show ntfy topic. How exactly the action is handled depends on how Android and your
-desktop browser treat the links. Normally it'll just open a link in the browser.
+even a deep link into Twitter or a show ntfy topic. How exactly the action is handled depends on how Android and your
+desktop browser treat the links. Normally it'll just open a link in the browser.
Examples:
-* `http://` or `https://` will open your browser (or an app if it registered for a URL)
-* `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
-* `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
-* `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
-* `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
-* ...
+- `http://` or `https://` will open your browser (or an app if it registered for a URL)
+- `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
+- `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
+- `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
+- `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
+- ...
Here's an example using the [`X-Actions` header](#using-a-header):
=== "Command line (curl)"
+
```
curl \
-d "Somebody retweeted your tweet." \
@@ -1387,6 +1498,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions="view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392" \
@@ -1395,7 +1507,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "HTTP"
- ``` http
+
+ ```http
POST /myhome HTTP/1.1
Host: ntfy.sh
Actions: view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392
@@ -1404,25 +1517,28 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/myhome', {
method: 'POST',
body: 'Somebody retweeted your tweet.',
- headers: {
- 'Actions': 'view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392'
+ headers: {
+ 'Actions': 'view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392'
}
})
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/myhome", strings.NewReader("Somebody retweeted your tweet."))
req.Header.Set("Actions", "view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/myhome"
@@ -1435,14 +1551,16 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/myhome",
data="Somebody retweeted your tweet.",
headers={ "Actions": "view, Open Twitter, https://twitter.com/binwiederhier/status/1467633927951163392" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1457,6 +1575,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
And the same example using [JSON publishing](#publish-as-json):
=== "Command line (curl)"
+
```
curl ntfy.sh \
-d '{
@@ -1473,6 +1592,7 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions '[
@@ -1487,7 +1607,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "HTTP"
- ``` http
+
+ ```http
POST / HTTP/1.1
Host: ntfy.sh
@@ -1505,7 +1626,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh', {
method: 'POST',
body: JSON.stringify({
@@ -1523,10 +1645,11 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Go"
- ``` go
+
+ ```go
// You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier.
-
+
body := `{
"topic": "myhome",
"message": "Somebody retweeted your tweet.",
@@ -1543,7 +1666,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh"
@@ -1564,7 +1688,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/",
data=json.dumps({
"topic": "myhome",
@@ -1581,7 +1706,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1604,13 +1730,14 @@ And the same example using [JSON publishing](#publish-as-json):
The `view` action supports the following fields:
| Field | Required | Type | Default | Example | Description |
-|----------|----------|-----------|---------|-----------------------|--------------------------------------------------|
-| `action` | ✔️ | *string* | - | `view` | Action type (**must be `view`**) |
-| `label` | ✔️ | *string* | - | `Turn on light` | Label of the action button in the notification |
-| `url` | ✔️ | *URL* | - | `https://example.com` | URL to open when action is tapped |
-| `clear` | -️ | *boolean* | `false` | `true` | Clear notification after action button is tapped |
+| -------- | -------- | --------- | ------- | --------------------- | ------------------------------------------------ |
+| `action` | ✔️ | _string_ | - | `view` | Action type (**must be `view`**) |
+| `label` | ✔️ | _string_ | - | `Turn on light` | Label of the action button in the notification |
+| `url` | ✔️ | _URL_ | - | `https://example.com` | URL to open when action is tapped |
+| `clear` | -️ | _boolean_ | `false` | `true` | Clear notification after action button is tapped |
### Send Android broadcast
+
_Supported on:_ :material-android:
The `broadcast` action **sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent
@@ -1623,13 +1750,14 @@ By default, the intent action **`io.heckel.ntfy.USER_ACTION`** is broadcast, tho
To send extras, use the `extras` parameter. Currently, **only string extras are supported**.
!!! info
- If you have no idea what this is, check out the [automation apps](subscribe/phone.md#automation-apps) section, which shows
- how to integrate Tasker and MacroDroid **with screenshots**. The action button integration is identical, except that
- you have to use **the intent action `io.heckel.ntfy.USER_ACTION`** instead.
+If you have no idea what this is, check out the [automation apps](subscribe/phone.md#automation-apps) section, which shows
+how to integrate Tasker and MacroDroid **with screenshots**. The action button integration is identical, except that
+you have to use **the intent action `io.heckel.ntfy.USER_ACTION`** instead.
Here's an example using the [`X-Actions` header](#using-a-header):
=== "Command line (curl)"
+
```
curl \
-d "Your wife requested you send a picture of yourself." \
@@ -1638,6 +1766,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions="broadcast, Take picture, extras.cmd=pic, extras.camera=front" \
@@ -1646,7 +1775,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "HTTP"
- ``` http
+
+ ```http
POST /wifey HTTP/1.1
Host: ntfy.sh
Actions: broadcast, Take picture, extras.cmd=pic, extras.camera=front
@@ -1655,25 +1785,28 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/wifey', {
method: 'POST',
body: 'Your wife requested you send a picture of yourself.',
- headers: {
- 'Actions': 'broadcast, Take picture, extras.cmd=pic, extras.camera=front'
+ headers: {
+ 'Actions': 'broadcast, Take picture, extras.cmd=pic, extras.camera=front'
}
})
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/wifey", strings.NewReader("Your wife requested you send a picture of yourself."))
req.Header.Set("Actions", "broadcast, Take picture, extras.cmd=pic, extras.camera=front")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/wifey"
@@ -1686,14 +1819,16 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/wifey",
data="Your wife requested you send a picture of yourself.",
headers={ "Actions": "broadcast, Take picture, extras.cmd=pic, extras.camera=front" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/wifey', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1708,6 +1843,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
And the same example using [JSON publishing](#publish-as-json):
=== "Command line (curl)"
+
```
curl ntfy.sh \
-d '{
@@ -1727,6 +1863,7 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions '[
@@ -1744,7 +1881,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "HTTP"
- ``` http
+
+ ```http
POST / HTTP/1.1
Host: ntfy.sh
@@ -1765,7 +1903,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh', {
method: 'POST',
body: JSON.stringify({
@@ -1786,10 +1925,11 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Go"
- ``` go
+
+ ```go
// You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier.
-
+
body := `{
"topic": "wifey",
"message": "Your wife requested you send a picture of yourself.",
@@ -1809,7 +1949,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
# Powershell requires the 'Depth' argument to equal 3 here to expand 'Extras',
# otherwise it will read System.Collections.Hashtable in the returned JSON
$Request = @{
@@ -1835,7 +1976,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/",
data=json.dumps({
"topic": "wifey",
@@ -1855,7 +1997,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1880,25 +2023,27 @@ And the same example using [JSON publishing](#publish-as-json):
The `broadcast` action supports the following fields:
| Field | Required | Type | Default | Example | Description |
-|----------|----------|------------------|------------------------------|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `action` | ✔️ | *string* | - | `broadcast` | Action type (**must be `broadcast`**) |
-| `label` | ✔️ | *string* | - | `Turn on light` | Label of the action button in the notification |
-| `intent` | -️ | *string* | `io.heckel.ntfy.USER_ACTION` | `com.example.AN_INTENT` | Android intent name, **default is `io.heckel.ntfy.USER_ACTION`** |
-| `extras` | -️ | *map of strings* | - | *see above* | Android intent extras. Currently, only string extras are supported. When publishing as JSON, extras are passed as a map. When the simple format is used, use `extras. =`. |
-| `clear` | -️ | *boolean* | `false` | `true` | Clear notification after action button is tapped |
+| -------- | -------- | ---------------- | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `action` | ✔️ | _string_ | - | `broadcast` | Action type (**must be `broadcast`**) |
+| `label` | ✔️ | _string_ | - | `Turn on light` | Label of the action button in the notification |
+| `intent` | -️ | _string_ | `io.heckel.ntfy.USER_ACTION` | `com.example.AN_INTENT` | Android intent name, **default is `io.heckel.ntfy.USER_ACTION`** |
+| `extras` | -️ | _map of strings_ | - | _see above_ | Android intent extras. Currently, only string extras are supported. When publishing as JSON, extras are passed as a map. When the simple format is used, use `extras. =`. |
+| `clear` | -️ | _boolean_ | `false` | `true` | Clear notification after action button is tapped |
### Send HTTP request
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
The `http` action **sends a HTTP request when the action button is tapped**. You can use this to trigger REST APIs
for whatever systems you have, e.g. opening the garage door, or turning on/off lights.
By default, this action sends a **POST request** (not GET!), though this can be changed with the `method` parameter.
-The only required parameter is `url`. Headers can be passed along using the `headers` parameter.
+The only required parameter is `url`. Headers can be passed along using the `headers` parameter.
Here's an example using the [`X-Actions` header](#using-a-header):
=== "Command line (curl)"
+
```
curl \
-d "Garage door has been open for 15 minutes. Close it?" \
@@ -1907,6 +2052,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions="http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}" \
@@ -1915,7 +2061,8 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "HTTP"
- ``` http
+
+ ```http
POST /myhome HTTP/1.1
Host: ntfy.sh
Actions: http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={"action": "close"}
@@ -1924,25 +2071,28 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/myhome', {
method: 'POST',
body: 'Garage door has been open for 15 minutes. Close it?',
- headers: {
- 'Actions': 'http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}'
+ headers: {
+ 'Actions': 'http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}'
}
})
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/myhome", strings.NewReader("Garage door has been open for 15 minutes. Close it?"))
req.Header.Set("Actions", "http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/myhome"
@@ -1955,14 +2105,16 @@ Here's an example using the [`X-Actions` header](#using-a-header):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/myhome",
data="Garage door has been open for 15 minutes. Close it?",
headers={ "Actions": "http, Close door, https://api.mygarage.lan/, method=PUT, headers.Authorization=Bearer zAzsx1sk.., body={\"action\": \"close\"}" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -1977,6 +2129,7 @@ Here's an example using the [`X-Actions` header](#using-a-header):
And the same example using [JSON publishing](#publish-as-json):
=== "Command line (curl)"
+
```
curl ntfy.sh \
-d '{
@@ -1998,6 +2151,7 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "ntfy CLI"
+
```
ntfy publish \
--actions '[
@@ -2017,7 +2171,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "HTTP"
- ``` http
+
+ ```http
POST / HTTP/1.1
Host: ntfy.sh
@@ -2040,7 +2195,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh', {
method: 'POST',
body: JSON.stringify({
@@ -2063,10 +2219,11 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Go"
- ``` go
+
+ ```go
// You should probably use json.Marshal() instead and make a proper struct,
// but for the sake of the example, this is easier.
-
+
body := `{
"topic": "myhome",
"message": "Garage door has been open for 15 minutes. Close it?",
@@ -2088,8 +2245,9 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PowerShell"
- ``` powershell
- # Powershell requires the 'Depth' argument to equal 3 here to expand 'headers',
+
+ ```powershell
+ # Powershell requires the 'Depth' argument to equal 3 here to expand 'headers',
# otherwise it will read System.Collections.Hashtable in the returned JSON
$Request = @{
@@ -2117,7 +2275,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/",
data=json.dumps({
"topic": "myhome",
@@ -2139,7 +2298,8 @@ And the same example using [JSON publishing](#publish-as-json):
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -2167,38 +2327,40 @@ And the same example using [JSON publishing](#publish-as-json):
The `http` action supports the following fields:
| Field | Required | Type | Default | Example | Description |
-|-----------|----------|--------------------|-----------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `action` | ✔️ | *string* | - | `http` | Action type (**must be `http`**) |
-| `label` | ✔️ | *string* | - | `Open garage door` | Label of the action button in the notification |
-| `url` | ✔️ | *string* | - | `https://ntfy.sh/mytopic` | URL to which the HTTP request will be sent |
-| `method` | -️ | *GET/POST/PUT/...* | `POST` ⚠️ | `GET` | HTTP method to use for request, **default is POST** ⚠️ |
-| `headers` | -️ | *map of strings* | - | *see above* | HTTP headers to pass in request. When publishing as JSON, headers are passed as a map. When the simple format is used, use `headers.=`. |
-| `body` | -️ | *string* | *empty* | `some body, somebody?` | HTTP body |
-| `clear` | -️ | *boolean* | `false` | `true` | Clear notification after HTTP request succeeds. If the request fails, the notification is not cleared. |
+| --------- | -------- | ------------------ | --------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `action` | ✔️ | _string_ | - | `http` | Action type (**must be `http`**) |
+| `label` | ✔️ | _string_ | - | `Open garage door` | Label of the action button in the notification |
+| `url` | ✔️ | _string_ | - | `https://ntfy.sh/mytopic` | URL to which the HTTP request will be sent |
+| `method` | -️ | _GET/POST/PUT/..._ | `POST` ⚠️ | `GET` | HTTP method to use for request, **default is POST** ⚠️ |
+| `headers` | -️ | _map of strings_ | - | _see above_ | HTTP headers to pass in request. When publishing as JSON, headers are passed as a map. When the simple format is used, use `headers.=`. |
+| `body` | -️ | _string_ | _empty_ | `some body, somebody?` | HTTP body |
+| `clear` | -️ | _boolean_ | `false` | `true` | Clear notification after HTTP request succeeds. If the request fails, the notification is not cleared. |
## Click action
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-You can define which URL to open when a notification is clicked. This may be useful if your notification is related
+You can define which URL to open when a notification is clicked. This may be useful if your notification is related
to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open
the web browser (or the app) and open the website.
To define a click action for the notification, pass a URL as the value of the `X-Click` header (or its aliase `Click`).
If you pass a website URL (`http://` or `https://`) the web browser will open. If you pass another URI that can be handled
-by another app, the responsible app may open.
+by another app, the responsible app may open.
Examples:
-* `http://` or `https://` will open your browser (or an app if it registered for a URL)
-* `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
-* `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
-* `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
-* `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
-* ...
+- `http://` or `https://` will open your browser (or an app if it registered for a URL)
+- `mailto:` links will open your mail app, e.g. `mailto:phil@example.com`
+- `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA`
+- `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats`
+- `twitter://` links will open Twitter, e.g. `twitter://user?screen_name=..`
+- ...
Here's an example that will open Reddit when the notification is clicked:
=== "Command line (curl)"
+
```
curl \
-d "New messages on Reddit" \
@@ -2207,6 +2369,7 @@ Here's an example that will open Reddit when the notification is clicked:
```
=== "ntfy CLI"
+
```
ntfy publish \
--click="https://www.reddit.com/message/messages" \
@@ -2214,16 +2377,18 @@ Here's an example that will open Reddit when the notification is clicked:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /reddit_alerts HTTP/1.1
Host: ntfy.sh
- Click: https://www.reddit.com/message/messages
+ Click: https://www.reddit.com/message/messages
New messages on Reddit
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/reddit_alerts', {
method: 'POST',
body: 'New messages on Reddit',
@@ -2232,14 +2397,16 @@ Here's an example that will open Reddit when the notification is clicked:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/reddit_alerts", strings.NewReader("New messages on Reddit"))
req.Header.Set("Click", "https://www.reddit.com/message/messages")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/reddit_alerts"
@@ -2250,14 +2417,16 @@ Here's an example that will open Reddit when the notification is clicked:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/reddit_alerts",
data="New messages on Reddit",
headers={ "Click": "https://www.reddit.com/message/messages" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -2270,30 +2439,33 @@ Here's an example that will open Reddit when the notification is clicked:
```
## Attachments
+
_Supported on:_ :material-android: :material-firefox:
You can **send images and other files to your phone** as attachments to a notification. The attachments are then downloaded
onto your phone (depending on size and setting automatically), and can be used from the Downloads folder.
-There are two different ways to send attachments:
+There are two different ways to send attachments:
-* sending [a local file](#attach-local-file) via PUT, e.g. from `~/Flowers/flower.jpg` or `ringtone.mp3`
-* or by [passing an external URL](#attach-file-from-a-url) as an attachment, e.g. `https://f-droid.org/F-Droid.apk`
+- sending [a local file](#attach-local-file) via PUT, e.g. from `~/Flowers/flower.jpg` or `ringtone.mp3`
+- or by [passing an external URL](#attach-file-from-a-url) as an attachment, e.g. `https://f-droid.org/F-Droid.apk`
### Attach local file
-To **send a file from your computer** as an attachment, you can send it as the PUT request body. If a message is greater
-than the maximum message size (4,096 bytes) or consists of non UTF-8 characters, the ntfy server will automatically
-detect the mime type and size, and send the message as an attachment file. To send smaller text-only messages or files
-as attachments, you must pass a filename by passing the `X-Filename` header or query parameter (or any of its aliases
-`Filename`, `File` or `f`).
-By default, and how ntfy.sh is configured, the **max attachment size is 15 MB** (with 100 MB total per visitor).
+To **send a file from your computer** as an attachment, you can send it as the PUT request body. If a message is greater
+than the maximum message size (4,096 bytes) or consists of non UTF-8 characters, the ntfy server will automatically
+detect the mime type and size, and send the message as an attachment file. To send smaller text-only messages or files
+as attachments, you must pass a filename by passing the `X-Filename` header or query parameter (or any of its aliases
+`Filename`, `File` or `f`).
+
+By default, and how ntfy.sh is configured, the **max attachment size is 15 MB** (with 100 MB total per visitor).
Attachments **expire after 3 hours**, which typically is plenty of time for the user to download it, or for the Android app
to auto-download it. Please also check out the [other limits below](#limitations).
Here's an example showing how to upload an image:
=== "Command line (curl)"
+
```
curl \
-T flower.jpg \
@@ -2302,6 +2474,7 @@ Here's an example showing how to upload an image:
```
=== "ntfy CLI"
+
```
ntfy publish \
--file=flower.jpg \
@@ -2309,17 +2482,19 @@ Here's an example showing how to upload an image:
```
=== "HTTP"
- ``` http
+
+ ```http
PUT /flowers HTTP/1.1
Host: ntfy.sh
Filename: flower.jpg
Content-Type: 52312
-
+
(binary JPEG data)
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/flowers', {
method: 'PUT',
body: document.getElementById("file").files[0],
@@ -2328,7 +2503,8 @@ Here's an example showing how to upload an image:
```
=== "Go"
- ``` go
+
+ ```go
file, _ := os.Open("flower.jpg")
req, _ := http.NewRequest("PUT", "https://ntfy.sh/flowers", file)
req.Header.Set("Filename", "flower.jpg")
@@ -2336,21 +2512,23 @@ Here's an example showing how to upload an image:
```
=== "Python"
- ``` python
+
+ ```python
requests.put("https://ntfy.sh/flowers",
data=open("flower.jpg", 'rb'),
headers={ "Filename": "flower.jpg" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/flowers', false, stream_context_create([
'http' => [
'method' => 'PUT',
'header' =>
"Content-Type: application/octet-stream\r\n" . // Does not matter
"Filename: flower.jpg",
- 'content' => file_get_contents('flower.jpg') // Dangerous for large files
+ 'content' => file_get_contents('flower.jpg') // Dangerous for large files
]
]));
```
@@ -2363,20 +2541,22 @@ Here's what that looks like on Android:
### Attach file from a URL
+
Instead of sending a local file to your phone, you can use **an external URL** to specify where the attachment is hosted.
-This could be a Dropbox link, a file from social media, or any other publicly available URL. Since the files are
+This could be a Dropbox link, a file from social media, or any other publicly available URL. Since the files are
externally hosted, the expiration or size limits from above do not apply here.
To attach an external file, simple pass the `X-Attach` header or query parameter (or any of its aliases `Attach` or `a`)
-to specify the attachment URL. It can be any type of file.
+to specify the attachment URL. It can be any type of file.
-ntfy will automatically try to derive the file name from the URL (e.g `https://example.com/flower.jpg` will yield a
+ntfy will automatically try to derive the file name from the URL (e.g `https://example.com/flower.jpg` will yield a
filename `flower.jpg`). To override this filename, you may send the `X-Filename` header or query parameter (or any of its
aliases `Filename`, `File` or `f`).
Here's an example showing how to attach an APK file:
=== "Command line (curl)"
+
```
curl \
-X POST \
@@ -2385,6 +2565,7 @@ Here's an example showing how to attach an APK file:
```
=== "ntfy CLI"
+
```
ntfy publish \
--attach="https://f-droid.org/F-Droid.apk" \
@@ -2392,14 +2573,16 @@ Here's an example showing how to attach an APK file:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mydownloads HTTP/1.1
Host: ntfy.sh
Attach: https://f-droid.org/F-Droid.apk
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mydownloads', {
method: 'POST',
headers: { 'Attach': 'https://f-droid.org/F-Droid.apk' }
@@ -2407,14 +2590,16 @@ Here's an example showing how to attach an APK file:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mydownloads", file)
req.Header.Set("Attach", "https://f-droid.org/F-Droid.apk")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/mydownloads"
@@ -2424,13 +2609,15 @@ Here's an example showing how to attach an APK file:
```
=== "Python"
- ``` python
+
+ ```python
requests.put("https://ntfy.sh/mydownloads",
headers={ "Attach": "https://f-droid.org/F-Droid.apk" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mydownloads', false, stream_context_create([
'http' => [
'method' => 'PUT',
@@ -2447,16 +2634,18 @@ Here's an example showing how to attach an APK file:
## Icons
+
_Supported on:_ :material-android:
You can include an icon that will appear next to the text of the notification. Simply pass the `X-Icon` header or query
parameter (or its alias `Icon`) to specify the URL that the icon is located at. The client will automatically download
-the icon (unless it is already cached locally, and less than 24 hours old), and show it in the notification. Icons are
+the icon (unless it is already cached locally, and less than 24 hours old), and show it in the notification. Icons are
cached locally in the client until the notification is deleted. **Only JPEG and PNG images are supported at this time**.
Here's an example showing how to include an icon:
=== "Command line (curl)"
+
```
curl \
-H "Icon: https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png" \
@@ -2467,6 +2656,7 @@ Here's an example showing how to include an icon:
```
=== "ntfy CLI"
+
```
ntfy publish \
--icon="https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png" \
@@ -2477,7 +2667,8 @@ Here's an example showing how to include an icon:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /tvshows HTTP/1.1
Host: ntfy.sh
Icon: https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png
@@ -2488,10 +2679,11 @@ Here's an example showing how to include an icon:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/tvshows', {
method: 'POST',
- headers: {
+ headers: {
'Icon': 'https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png',
'Title': 'Kodi: Resuming Playback',
'Tags': 'arrow_forward'
@@ -2501,7 +2693,8 @@ Here's an example showing how to include an icon:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/tvshows", strings.NewReader("The Wire, S01E01"))
req.Header.Set("Icon", "https://styles.redditmedia.com/t5_32uhe/styles/communityIcon_xnt6chtnr2j21.png")
req.Header.Set("Tags", "arrow_forward")
@@ -2510,7 +2703,8 @@ Here's an example showing how to include an icon:
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/tvshows"
@@ -2525,7 +2719,8 @@ Here's an example showing how to include an icon:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/tvshows",
data="The Wire, S01E01",
headers={
@@ -2536,7 +2731,8 @@ Here's an example showing how to include an icon:
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/tvshows', false, stream_context_create([
'http' => [
'method' => 'PUT',
@@ -2558,19 +2754,21 @@ Here's an example of how it will look on Android:
## E-mail notifications
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-You can forward messages to e-mail by specifying an address in the header. This can be useful for messages that
-you'd like to persist longer, or to blast-notify yourself on all possible channels.
+You can forward messages to e-mail by specifying an address in the header. This can be useful for messages that
+you'd like to persist longer, or to blast-notify yourself on all possible channels.
Usage is easy: Simply pass the `X-Email` header (or any of its aliases: `X-E-mail`, `Email`, `E-mail`, `Mail`, or `e`).
Only one e-mail address is supported.
-Since ntfy does not provide auth (yet), the rate limiting is pretty strict (see [limitations](#limitations)). In the
-default configuration, you get **16 e-mails per visitor** (IP address) and then after that one per hour. On top of
+Since ntfy does not provide auth (yet), the rate limiting is pretty strict (see [limitations](#limitations)). In the
+default configuration, you get **16 e-mails per visitor** (IP address) and then after that one per hour. On top of
that, your IP address appears in the e-mail body. This is to prevent abuse.
=== "Command line (curl)"
+
```
curl \
-H "Email: phil@example.com" \
@@ -2578,11 +2776,12 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
-H "Priority: high" \
-d "Unknown login from 5.31.23.83 to backups.example.com" \
ntfy.sh/alerts
- curl -H "Email: phil@example.com" -d "You've Got Mail"
+ curl -H "Email: phil@example.com" -d "You've Got Mail"
curl -d "You've Got Mail" "ntfy.sh/alerts?email=phil@example.com"
```
=== "ntfy CLI"
+
```
ntfy publish \
--email=phil@example.com \
@@ -2592,7 +2791,8 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "HTTP"
- ``` http
+
+ ```http
POST /alerts HTTP/1.1
Host: ntfy.sh
Email: phil@example.com
@@ -2603,11 +2803,12 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/alerts', {
method: 'POST',
body: "Unknown login from 5.31.23.83 to backups.example.com",
- headers: {
+ headers: {
'Email': 'phil@example.com',
'Tags': 'warning,skull,backup-host,ssh-login',
'Priority': 'high'
@@ -2616,8 +2817,9 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "Go"
- ``` go
- req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts",
+
+ ```go
+ req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts",
strings.NewReader("Unknown login from 5.31.23.83 to backups.example.com"))
req.Header.Set("Email", "phil@example.com")
req.Header.Set("Tags", "warning,skull,backup-host,ssh-login")
@@ -2626,7 +2828,8 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/alerts"
@@ -2642,10 +2845,11 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/alerts",
data="Unknown login from 5.31.23.83 to backups.example.com",
- headers={
+ headers={
"Email": "phil@example.com",
"Tags": "warning,skull,backup-host,ssh-login",
"Priority": "high"
@@ -2653,7 +2857,8 @@ that, your IP address appears in the e-mail body. This is to prevent abuse.
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -2675,14 +2880,15 @@ Here's what that looks like in Google Mail:
## E-mail publishing
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
You can publish messages to a topic via e-mail, i.e. by sending an email to a specific address. For instance, you can
-publish a message to the topic `sometopic` by sending an e-mail to `ntfy-sometopic@ntfy.sh`. This is useful for e-mail
+publish a message to the topic `sometopic` by sending an e-mail to `ntfy-sometopic@ntfy.sh`. This is useful for e-mail
based integrations such as for statuspage.io (though these days most services also support webhooks and HTTP calls).
-Depending on the [server configuration](config.md#e-mail-publishing), the e-mail address format can have a prefix to
-prevent spam on topics. For ntfy.sh, the prefix is configured to `ntfy-`, meaning that the general e-mail address
+Depending on the [server configuration](config.md#e-mail-publishing), the e-mail address format can have a prefix to
+prevent spam on topics. For ntfy.sh, the prefix is configured to `ntfy-`, meaning that the general e-mail address
format is:
```
@@ -2690,12 +2896,13 @@ ntfy-$topic@ntfy.sh
```
If [access control](config.md#access-control) is enabled, and the target topic does not support anonymous writes, e-mail publishing won't work without providing an authorized access token. That will change the format of the e-mail's recipient address to
+
```
ntfy-$topic+$token@ntfy.sh
```
As of today, e-mail publishing only supports adding a [message title](#message-title) (the e-mail subject). Tags, priority,
-delay and other features are not supported (yet). Here's an example that will publish a message with the
+delay and other features are not supported (yet). Here's an example that will publish a message with the
title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://ntfy.sh/sometopic)):
@@ -2704,16 +2911,17 @@ title `You've Got Mail` to topic `sometopic` (see [ntfy.sh/sometopic](https://nt
## Phone calls
+
_Supported on:_ :material-android: :material-apple: :material-firefox:
-You can use ntfy to call a phone and **read the message out loud using text-to-speech**.
-Similar to email notifications, this can be useful to blast-notify yourself on all possible channels, or to notify people that do not have
+You can use ntfy to call a phone and **read the message out loud using text-to-speech**.
+Similar to email notifications, this can be useful to blast-notify yourself on all possible channels, or to notify people that do not have
the ntfy app installed on their phone.
-**Phone numbers have to be previously verified** (via the [web app](https://ntfy.sh/account)), so this feature is
+**Phone numbers have to be previously verified** (via the [web app](https://ntfy.sh/account)), so this feature is
**only available to authenticated users** (no anonymous phone calls). To forward a message as a voice call, pass a phone
-number in the `X-Call` header (or its alias: `Call`), prefixed with a plus sign and the country code, e.g. `+12223334444`.
-You may also simply pass `yes` as a value to pick the first of your verified phone numbers.
+number in the `X-Call` header (or its alias: `Call`), prefixed with a plus sign and the country code, e.g. `+12223334444`.
+You may also simply pass `yes` as a value to pick the first of your verified phone numbers.
On ntfy.sh, this feature is only supported to [ntfy Pro](https://ntfy.sh/app) plans.
@@ -2725,13 +2933,14 @@ As of today, the text-to-speed voice used will only support English. If there is
be happy to add support for that. Please [open an issue on GitHub](https://github.com/binwiederhier/ntfy/issues).
!!! info
- You are responsible for the message content, and **you must abide by the [Twilio Acceptable Use Policy](https://www.twilio.com/en-us/legal/aup)**.
- This particularly means that you must not use this feature to send unsolicited messages, or messages that are illegal or
- violate the rights of others. Please read the policy for details. Failure to do so may result in your account being suspended or terminated.
+You are responsible for the message content, and **you must abide by the [Twilio Acceptable Use Policy](https://www.twilio.com/en-us/legal/aup)**.
+This particularly means that you must not use this feature to send unsolicited messages, or messages that are illegal or
+violate the rights of others. Please read the policy for details. Failure to do so may result in your account being suspended or terminated.
Here's how you use it:
=== "Command line (curl)"
+
```
curl \
-u :tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 \
@@ -2741,6 +2950,7 @@ Here's how you use it:
```
=== "ntfy CLI"
+
```
ntfy publish \
--token=tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 \
@@ -2749,7 +2959,8 @@ Here's how you use it:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /alerts HTTP/1.1
Host: ntfy.sh
Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
@@ -2759,11 +2970,12 @@ Here's how you use it:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/alerts', {
method: 'POST',
body: "Your garage seems to be on fire. You should probably check that out.",
- headers: {
+ headers: {
'Authorization': 'Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2',
'Call': '+12223334444'
}
@@ -2771,8 +2983,9 @@ Here's how you use it:
```
=== "Go"
- ``` go
- req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts",
+
+ ```go
+ req, _ := http.NewRequest("POST", "https://ntfy.sh/alerts",
strings.NewReader("Your garage seems to be on fire. You should probably check that out."))
req.Header.Set("Call", "+12223334444")
req.Header.Set("Authorization", "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2")
@@ -2780,7 +2993,8 @@ Here's how you use it:
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/alerts"
@@ -2794,17 +3008,19 @@ Here's how you use it:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/alerts",
data="Your garage seems to be on fire. You should probably check that out.",
- headers={
+ headers={
"Authorization": "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2",
"Call": "+12223334444"
})
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -2826,28 +3042,31 @@ Here's what a phone call from ntfy sounds like:
Audio transcript:
-> You have a notification from ntfy on topic alerts.
-> Message: Your garage seems to be on fire. You should probably check that out. End message.
+> You have a notification from ntfy on topic alerts.
+> Message: Your garage seems to be on fire. You should probably check that out. End message.
> This message was sent by user phil. It will be repeated up to three times.
## Authentication
+
Depending on whether the server is configured to support [access control](config.md#access-control), some topics
may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
-To publish/subscribe to protected topics, you can:
+To publish/subscribe to protected topics, you can:
-* Use [username & password](#username-password) via Basic auth, e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
-* Use [access tokens](#bearer-auth) via Bearer/Basic auth, e.g. `Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`
-* or use either with the [`auth` query parameter](#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw`
+- Use [username & password](#username-password) via Basic auth, e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
+- Use [access tokens](#bearer-auth) via Bearer/Basic auth, e.g. `Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`
+- or use either with the [`auth` query parameter](#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw`
!!! warning
- When using Basic auth, base64 only encodes username and password. It **is not encrypting it**. For your
- self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing your password.
+When using Basic auth, base64 only encodes username and password. It **is not encrypting it**. For your
+self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing your password.
### Username + password
+
The simplest way to authenticate against a ntfy server is to use [Basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication).
Here's an example with a user `testuser` and password `fakepassword`:
=== "Command line (curl)"
+
```
curl \
-u testuser:fakepassword \
@@ -2856,6 +3075,7 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "ntfy CLI"
+
```
ntfy publish \
-u testuser:fakepassword \
@@ -2864,7 +3084,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mysecrets HTTP/1.1
Host: ntfy.example.com
Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk
@@ -2873,7 +3094,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.example.com/mysecrets', {
method: 'POST', // PUT works too
body: 'Look ma, with auth',
@@ -2884,7 +3106,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
strings.NewReader("Look ma, with auth"))
req.Header.Set("Authorization", "Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk")
@@ -2892,13 +3115,14 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "PowerShell 7+"
- ``` powershell
+
+ ```powershell
# Get the credentials from the user
$Credential = Get-Credential testuser
# Alternatively, create a PSCredential object with the password from scratch
$Credential = [PSCredential]::new("testuser", (ConvertTo-SecureString "password" -AsPlainText -Force))
-
+
# Note that the Authentication parameter requires PowerShell 7 or later
$Request = @{
Method = "POST"
@@ -2911,7 +3135,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "PowerShell 5 and earlier"
- ``` powershell
+
+ ```powershell
# With PowerShell 5 or earlier, we need to create the base64 username:password string ourselves
$CredentialString = "$($Credential.Username):$($Credential.GetNetworkCredential().Password)"
$EncodedCredential = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($CredentialString))
@@ -2925,7 +3150,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.example.com/mysecrets",
data="Look ma, with auth",
headers={
@@ -2934,7 +3160,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -2946,8 +3173,8 @@ Here's an example with a user `testuser` and password `fakepassword`:
]));
```
-To generate the `Authorization` header, use **standard base64** to encode the colon-separated `:`
-and prepend the word `Basic`, i.e. `Authorization: Basic base64(:)`. Here's some pseudo-code that
+To generate the `Authorization` header, use **standard base64** to encode the colon-separated `:`
+and prepend the word `Basic`, i.e. `Authorization: Basic base64(:)`. Here's some pseudo-code that
hopefully explains it better:
```
@@ -2956,13 +3183,14 @@ password = "fakepassword"
authHeader = "Basic " + base64(username + ":" + password) // -> Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk
```
-The following command will generate the appropriate value for you on *nix systems:
+The following command will generate the appropriate value for you on \*nix systems:
```
echo "Basic $(echo -n 'testuser:fakepassword' | base64)"
```
### Access tokens
+
In addition to username/password auth, ntfy also provides authentication via access tokens. Access tokens are useful
to avoid having to configure your password across multiple publishing/subscribing applications. For instance, you may
want to use a dedicated token to publish from your backup host, and one from your home automation system.
@@ -2970,11 +3198,12 @@ want to use a dedicated token to publish from your backup host, and one from you
You can create access tokens using the `ntfy token` command, or in the web app in the "Account" section (when logged in).
See [access tokens](config.md#access-tokens) for details.
-Once an access token is created, you can use it to authenticate against the ntfy server, e.g. when you publish or
+Once an access token is created, you can use it to authenticate against the ntfy server, e.g. when you publish or
subscribe to topics. Here's an example using [Bearer auth](https://swagger.io/docs/specification/authentication/bearer-authentication/),
with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
=== "Command line (curl)"
+
```
curl \
-H "Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2" \
@@ -2983,6 +3212,7 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "ntfy CLI"
+
```
ntfy publish \
--token tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 \
@@ -2991,7 +3221,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mysecrets HTTP/1.1
Host: ntfy.example.com
Authorization: Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
@@ -3000,7 +3231,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.example.com/mysecrets', {
method: 'POST', // PUT works too
body: 'Look ma, with auth',
@@ -3011,7 +3243,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
strings.NewReader("Look ma, with auth"))
req.Header.Set("Authorization", "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2")
@@ -3019,7 +3252,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "PowerShell 7+"
- ``` powershell
+
+ ```powershell
# With PowerShell 7 or greater, we can use the Authentication and Token parameters
$Request = @{
Method = "POST"
@@ -3032,7 +3266,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "PowerShell 5 and earlier"
- ``` powershell
+
+ ```powershell
# In PowerShell 5 and below, we can only send the Bearer token as a string in the Headers
$Request = @{
Method = "POST"
@@ -3044,7 +3279,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.example.com/mysecrets",
data="Look ma, with auth",
headers={
@@ -3053,7 +3289,8 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -3065,11 +3302,12 @@ with the token `tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2`:
]));
```
-Alternatively, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) to send the
-access token. When sending an empty username, the basic auth password is treated by the ntfy server as an
+Alternatively, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication) to send the
+access token. When sending an empty username, the basic auth password is treated by the ntfy server as an
access token. This is primarily useful to make `curl` calls easier, e.g. `curl -u:tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 ...`:
=== "Command line (curl)"
+
```
curl \
-u :tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 \
@@ -3078,6 +3316,7 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "ntfy CLI"
+
```
ntfy publish \
--token tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 \
@@ -3086,7 +3325,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mysecrets HTTP/1.1
Host: ntfy.example.com
Authorization: Basic OnRrX0FnUWRxN21WQm9GRDM3elFWTjI5Umh1TXpOSXoy
@@ -3095,7 +3335,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.example.com/mysecrets', {
method: 'POST', // PUT works too
body: 'Look ma, with auth',
@@ -3106,7 +3347,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
strings.NewReader("Look ma, with auth"))
req.Header.Set("Authorization", "Basic OnRrX0FnUWRxN21WQm9GRDM3elFWTjI5Umh1TXpOSXoy")
@@ -3114,7 +3356,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
# Note that PSCredentials *must* have a username, so we fall back to placing the authorization in the Headers as with PowerShell 5
$Request = @{
Method = "POST"
@@ -3128,7 +3371,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.example.com/mysecrets",
data="Look ma, with auth",
headers={
@@ -3137,7 +3381,8 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -3149,11 +3394,12 @@ access token. This is primarily useful to make `curl` calls easier, e.g. `curl -
]));
```
-
### Query param
+
Here's an example using the `auth` query parameter:
=== "Command line (curl)"
+
```
curl \
-d "Look ma, with auth" \
@@ -3161,6 +3407,7 @@ Here's an example using the `auth` query parameter:
```
=== "ntfy CLI"
+
```
ntfy publish \
-u testuser:fakepassword \
@@ -3169,7 +3416,8 @@ Here's an example using the `auth` query parameter:
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw HTTP/1.1
Host: ntfy.example.com
@@ -3177,7 +3425,8 @@ Here's an example using the `auth` query parameter:
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.example.com/mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw', {
method: 'POST', // PUT works too
body: 'Look ma, with auth'
@@ -3185,14 +3434,16 @@ Here's an example using the `auth` query parameter:
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw",
strings.NewReader("Look ma, with auth"))
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.example.com/mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw"
@@ -3202,13 +3453,15 @@ Here's an example using the `auth` query parameter:
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.example.com/mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw",
data="Look ma, with auth"
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.example.com/mysecrets?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
@@ -3218,8 +3471,8 @@ Here's an example using the `auth` query parameter:
]));
```
-To generate the value of the `auth` parameter, encode the value of the `Authorization` header (see above) using
-**raw base64 encoding** (like base64, but strip any trailing `=`). Here's some pseudo-code that hopefully
+To generate the value of the `auth` parameter, encode the value of the `Authorization` header (see above) using
+**raw base64 encoding** (like base64, but strip any trailing `=`). Here's some pseudo-code that hopefully
explains it better:
```
@@ -3229,10 +3482,10 @@ authHeader = "Basic " + base64(username + ":" + password) // -> Basic dGVzdHVzZX
authParam = base64_raw(authHeader) // -> QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw (no trailing =)
// If your language does not have a function to encode raw base64, simply use normal base64
-// and REMOVE TRAILING "=" characters.
+// and REMOVE TRAILING "=" characters.
```
-The following command will generate the appropriate value for you on *nix systems:
+The following command will generate the appropriate value for you on \*nix systems:
```
echo -n "Basic `echo -n 'testuser:fakepassword' | base64`" | base64 | tr -d '='
@@ -3247,27 +3500,30 @@ echo -n "Bearer faketoken" | base64 | tr -d '='
## Advanced features
### Message caching
+
!!! info
- If `Cache: no` is used, messages will only be delivered to connected subscribers, and won't be re-delivered if a
- client re-connects. If a subscriber has (temporary) network issues or is reconnecting momentarily,
- **messages might be missed**.
+If `Cache: no` is used, messages will only be delivered to connected subscribers, and won't be re-delivered if a
+client re-connects. If a subscriber has (temporary) network issues or is reconnecting momentarily,
+**messages might be missed**.
By default, the ntfy server caches messages on disk for 12 hours (see [message caching](config.md#message-cache)), so
-all messages you publish are stored server-side for a little while. The reason for this is to overcome temporary
+all messages you publish are stored server-side for a little while. The reason for this is to overcome temporary
client-side network disruptions, but arguably this feature also may raise privacy concerns.
-To avoid messages being cached server-side entirely, you can set `X-Cache` header (or its alias: `Cache`) to `no`.
+To avoid messages being cached server-side entirely, you can set `X-Cache` header (or its alias: `Cache`) to `no`.
This will make sure that your message is not cached on the server, even if server-side caching is enabled. Messages
-are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fetch-cached-messages) and
+are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fetch-cached-messages) and
[`poll=1`](subscribe/api.md#poll-for-messages) won't return the message anymore.
=== "Command line (curl)"
+
```
curl -H "X-Cache: no" -d "This message won't be stored server-side" ntfy.sh/mytopic
curl -H "Cache: no" -d "This message won't be stored server-side" ntfy.sh/mytopic
```
=== "ntfy CLI"
+
```
ntfy publish \
--no-cache \
@@ -3275,7 +3531,8 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Cache: no
@@ -3284,7 +3541,8 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST',
body: 'This message won't be stored server-side',
@@ -3293,14 +3551,16 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mytopic", strings.NewReader("This message won't be stored server-side"))
req.Header.Set("Cache", "no")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/mytopic"
@@ -3311,14 +3571,16 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/mytopic",
data="This message won't be stored server-side",
headers={ "Cache": "no" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -3331,13 +3593,14 @@ are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fe
```
### Disable Firebase
+
!!! info
- If `Firebase: no` is used and [instant delivery](subscribe/phone.md#instant-delivery) isn't enabled in the Android
- app (Google Play variant only), **message delivery will be significantly delayed (up to 15 minutes)**. To overcome
- this delay, simply enable instant delivery.
+If `Firebase: no` is used and [instant delivery](subscribe/phone.md#instant-delivery) isn't enabled in the Android
+app (Google Play variant only), **message delivery will be significantly delayed (up to 15 minutes)**. To overcome
+this delay, simply enable instant delivery.
The ntfy server can be configured to use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging)
-(see [Firebase config](config.md#firebase-fcm)) for message delivery on Android (to minimize the app's battery footprint).
+(see [Firebase config](config.md#firebase-fcm)) for message delivery on Android (to minimize the app's battery footprint).
The ntfy.sh server is configured this way, meaning that all messages published to ntfy.sh are also published to corresponding
FCM topics.
@@ -3345,12 +3608,14 @@ If you'd like to avoid forwarding messages to Firebase, you can set the `X-Fireb
to `no`. This will instruct the server not to forward messages to Firebase.
=== "Command line (curl)"
+
```
curl -H "X-Firebase: no" -d "This message won't be forwarded to FCM" ntfy.sh/mytopic
curl -H "Firebase: no" -d "This message won't be forwarded to FCM" ntfy.sh/mytopic
```
=== "ntfy CLI"
+
```
ntfy publish \
--no-firebase \
@@ -3358,7 +3623,8 @@ to `no`. This will instruct the server not to forward messages to Firebase.
```
=== "HTTP"
- ``` http
+
+ ```http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Firebase: no
@@ -3367,7 +3633,8 @@ to `no`. This will instruct the server not to forward messages to Firebase.
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST',
body: 'This message won't be forwarded to FCM',
@@ -3376,14 +3643,16 @@ to `no`. This will instruct the server not to forward messages to Firebase.
```
=== "Go"
- ``` go
+
+ ```go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mytopic", strings.NewReader("This message won't be forwarded to FCM"))
req.Header.Set("Firebase", "no")
http.DefaultClient.Do(req)
```
=== "PowerShell"
- ``` powershell
+
+ ```powershell
$Request = @{
Method = "POST"
URI = "https://ntfy.sh/mytopic"
@@ -3394,14 +3663,16 @@ to `no`. This will instruct the server not to forward messages to Firebase.
```
=== "Python"
- ``` python
+
+ ```python
requests.post("https://ntfy.sh/mytopic",
data="This message won't be forwarded to FCM",
headers={ "Firebase": "no" })
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST',
@@ -3414,8 +3685,9 @@ to `no`. This will instruct the server not to forward messages to Firebase.
```
### UnifiedPush
+
!!! info
- This setting is not relevant to users, only to app developers and people interested in [UnifiedPush](https://unifiedpush.org).
+This setting is not relevant to users, only to app developers and people interested in [UnifiedPush](https://unifiedpush.org).
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications
@@ -3423,16 +3695,17 @@ in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwa
When publishing messages to a topic, apps using ntfy as a UnifiedPush distributor can set the `X-UnifiedPush` header or query
parameter (or any of its aliases `unifiedpush` or `up`) to `1` to [disable Firebase](#disable-firebase). As of today, this
-option is mostly equivalent to `Firebase: no`, but was introduced to allow future flexibility. The flag additionally
+option is mostly equivalent to `Firebase: no`, but was introduced to allow future flexibility. The flag additionally
enables auto-detection of the message encoding. If the message is binary, it'll be encoded as base64.
### Matrix Gateway
+
The ntfy server implements a [Matrix Push Gateway](https://spec.matrix.org/v1.2/push-gateway-api/) (in combination with
[UnifiedPush](https://unifiedpush.org) as the [Provider Push Protocol](https://unifiedpush.org/developers/gateway/)). This makes it easier to integrate
-with self-hosted [Matrix](https://matrix.org/) servers (such as [synapse](https://github.com/matrix-org/synapse)), since
+with self-hosted [Matrix](https://matrix.org/) servers (such as [synapse](https://github.com/matrix-org/synapse)), since
you don't have to set up a separate push proxy (such as [common-proxies](https://github.com/UnifiedPush/common-proxies)).
-In short, ntfy accepts Matrix messages on the `/_matrix/push/v1/notify` endpoint (see [Push Gateway API](https://spec.matrix.org/v1.2/push-gateway-api/)),
+In short, ntfy accepts Matrix messages on the `/_matrix/push/v1/notify` endpoint (see [Push Gateway API](https://spec.matrix.org/v1.2/push-gateway-api/)),
and forwards them to the ntfy topic defined in the `pushkey` of the message. The message will then be forwarded to the
ntfy Android app, and passed on to the Matrix client there.
@@ -3440,24 +3713,26 @@ There is a nice diagram in the [Push Gateway docs](https://spec.matrix.org/v1.2/
ntfy server plays the role of the Push Gateway, as well as the Push Provider. UnifiedPush is the Provider Push Protocol.
!!! info
- This is not a generic Matrix Push Gateway. It only works in combination with UnifiedPush and ntfy.
+This is not a generic Matrix Push Gateway. It only works in combination with UnifiedPush and ntfy.
## Public topics
+
Obviously all topics on ntfy.sh are public, but there are a few designated topics that are used in examples, and topics
that you can use to try out what [authentication and access control](#authentication) looks like.
-| Topic | User | Permissions | Description |
-|------------------------------------------------|-----------------------------------|------------------------------------------------------|--------------------------------------|
-| [announcements](https://ntfy.sh/announcements) | `*` (unauthenticated) | Read-only for everyone | Release announcements and such |
-| [stats](https://ntfy.sh/stats) | `*` (unauthenticated) | Read-only for everyone | Daily statistics about ntfy.sh usage |
+| Topic | User | Permissions | Description |
+| ---------------------------------------------- | --------------------- | ---------------------- | ------------------------------------ |
+| [announcements](https://ntfy.sh/announcements) | `*` (unauthenticated) | Read-only for everyone | Release announcements and such |
+| [stats](https://ntfy.sh/stats) | `*` (unauthenticated) | Read-only for everyone | Daily statistics about ntfy.sh usage |
## Limitations
-There are a few limitations to the API to prevent abuse and to keep the server healthy. Almost all of these settings
+
+There are a few limitations to the API to prevent abuse and to keep the server healthy. Almost all of these settings
are configurable via the server side [rate limiting settings](config.md#rate-limiting). Most of these limits you won't run into,
but just in case, let's list them all:
| Limit | Description |
-|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Message length** | Each message can be up to 4,096 bytes long. Longer messages are treated as [attachments](#attachments). |
| **Requests** | By default, the server is configured to allow 60 requests per visitor at once, and then refills the your allowed requests bucket at a rate of one request per 5 seconds. |
| **Daily messages** | By default, the number of messages is governed by the request limits. This can be overridden. On ntfy.sh, the daily message limit is 250. |
@@ -3470,21 +3745,22 @@ but just in case, let's list them all:
| **Total number of topics** | By default, the server is configured to allow 15,000 topics. The ntfy.sh server has higher limits though. |
These limits can be changed on a per-user basis using [tiers](config.md#tiers). If [payments](config.md#payments) are enabled, a user tier can be changed by purchasing
-a higher tier. ntfy.sh offers multiple paid tiers, which allows for much hier limits than the ones listed above.
+a higher tier. ntfy.sh offers multiple paid tiers, which allows for much hier limits than the ones listed above.
## List of all parameters
+
The following is a list of all parameters that can be passed when publishing a message. Parameter names are **case-insensitive**
-when used in **HTTP headers**, and must be **lowercase** when used as **query parameters in the URL**. They are listed in the
+when used in **HTTP headers**, and must be **lowercase** when used as **query parameters in the URL**. They are listed in the
table in their canonical form.
!!! info
- ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
- If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any
- header as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
- or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
+ntfy supports UTF-8 in HTTP headers, but [not every library or programming language does](https://www.jmix.io/blog/utf-8-in-http-headers/).
+If non-ASCII characters are causing issues for you in the title (i.e. you're seeing `?` symbols), you may also encode any
+header as [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2), e.g. `=?UTF-8?B?8J+HqfCfh6o=?=` ([base64](https://en.wikipedia.org/wiki/Base64)),
+or `=?UTF-8?Q?=C3=84pfel?=` ([quoted-printable](https://en.wikipedia.org/wiki/Quoted-printable)).
| Parameter | Aliases | Description |
-|-----------------|--------------------------------------------|-----------------------------------------------------------------------------------------------|
+| --------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
| `X-Message` | `Message`, `m` | Main body of the message as shown in the notification |
| `X-Title` | `Title`, `t` | [Message title](#message-title) |
| `X-Priority` | `Priority`, `prio`, `p` | [Message priority](#message-priority) |
diff --git a/docs/releases.md b/docs/releases.md
index 71fceb1e..49da73a6 100644
--- a/docs/releases.md
+++ b/docs/releases.md
@@ -1,12 +1,14 @@
# Release notes
+
Binaries for all releases can be found on the GitHub releases pages for the [ntfy server](https://github.com/binwiederhier/ntfy/releases)
and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases).
## ntfy server v2.5.0
+
Released May 18, 2023
-This release brings a number of new features, including support for text-to-speech style [phone calls](publish.md#phone-calls),
-an admin API to manage users and ACL (currently in beta, and hence undocumented), and support for authorized access to
+This release brings a number of new features, including support for text-to-speech style [phone calls](publish.md#phone-calls),
+an admin API to manage users and ACL (currently in beta, and hence undocumented), and support for authorized access to
upstream servers via the `upstream-access-token` config option.
❤️ If you like ntfy, **please consider sponsoring me** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
@@ -15,20 +17,21 @@ if you use promo code `MYTOPIC`). ntfy will always remain open source.
**Features:**
-* Support for text-to-speech style [phone calls](publish.md#phone-calls) using the `X-Call` header (no ticket)
-* Admin API to manage users and ACL, `v1/users` + `v1/users/access` (intentionally undocumented as of now, [#722](https://github.com/binwiederhier/ntfy/issues/722), thanks to [@CreativeWarlock](https://github.com/CreativeWarlock) for sponsoring this ticket)
-* Added `upstream-access-token` config option to allow authorized access to upstream servers (no ticket)
+- Support for text-to-speech style [phone calls](publish.md#phone-calls) using the `X-Call` header (no ticket)
+- Admin API to manage users and ACL, `v1/users` + `v1/users/access` (intentionally undocumented as of now, [#722](https://github.com/binwiederhier/ntfy/issues/722), thanks to [@CreativeWarlock](https://github.com/CreativeWarlock) for sponsoring this ticket)
+- Added `upstream-access-token` config option to allow authorized access to upstream servers (no ticket)
**Bug fixes + maintenance:**
-* Removed old ntfy website from ntfy entirely (no ticket)
-* Make emoji lookup for emails more efficient ([#725](https://github.com/binwiederhier/ntfy/pull/725), thanks to [@adamantike](https://github.com/adamantike))
-* Fix potential subscriber ID clash ([#712](https://github.com/binwiederhier/ntfy/issues/712), thanks to [@peterbourgon](https://github.com/peterbourgon) for reporting, and [@dropdevrahul](https://github.com/dropdevrahul) for fixing)
-* Support for `quoted-printable` in incoming emails ([#719](https://github.com/binwiederhier/ntfy/pull/719), thanks to [@Aerion](https://github.com/Aerion))
-* Attachments with filenames that are downloaded using a browser will now download with the proper filename ([#726](https://github.com/binwiederhier/ntfy/issues/726), thanks to [@un99known99](https://github.com/un99known99) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
-* Fix web app i18n issue in account preferences ([#730](https://github.com/binwiederhier/ntfy/issues/730), thanks to [@codebude](https://github.com/codebude) for reporting)
+- Removed old ntfy website from ntfy entirely (no ticket)
+- Make emoji lookup for emails more efficient ([#725](https://github.com/binwiederhier/ntfy/pull/725), thanks to [@adamantike](https://github.com/adamantike))
+- Fix potential subscriber ID clash ([#712](https://github.com/binwiederhier/ntfy/issues/712), thanks to [@peterbourgon](https://github.com/peterbourgon) for reporting, and [@dropdevrahul](https://github.com/dropdevrahul) for fixing)
+- Support for `quoted-printable` in incoming emails ([#719](https://github.com/binwiederhier/ntfy/pull/719), thanks to [@Aerion](https://github.com/Aerion))
+- Attachments with filenames that are downloaded using a browser will now download with the proper filename ([#726](https://github.com/binwiederhier/ntfy/issues/726), thanks to [@un99known99](https://github.com/un99known99) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
+- Fix web app i18n issue in account preferences ([#730](https://github.com/binwiederhier/ntfy/issues/730), thanks to [@codebude](https://github.com/codebude) for reporting)
## ntfy server v2.4.0
+
Released Apr 26, 2023
This release adds a tiny `v1/stats` endpoint to expose how many messages have been published, and adds suport to encode the `X-Title`,
@@ -40,24 +43,25 @@ will always remain open source.
**Features:**
-* [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) can now be installed via Homebrew (thanks to [@Moulick](https://github.com/Moulick))
-* Added `v1/stats` endpoint to expose messages stats (no ticket)
-* Support [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2) encoded headers (no ticket, honorable mention to [mqttwarn](https://github.com/jpmens/mqttwarn/pull/638) and [@amotl](https://github.com/amotl))
+- [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) can now be installed via Homebrew (thanks to [@Moulick](https://github.com/Moulick))
+- Added `v1/stats` endpoint to expose messages stats (no ticket)
+- Support [RFC 2047](https://datatracker.ietf.org/doc/html/rfc2047#section-2) encoded headers (no ticket, honorable mention to [mqttwarn](https://github.com/jpmens/mqttwarn/pull/638) and [@amotl](https://github.com/amotl))
**Bug fixes + maintenance:**
-* Hide country flags on Windows ([#606](https://github.com/binwiederhier/ntfy/issues/606), thanks to [@cmeis](https://github.com/cmeis) for reporting, and to [@pokej6](https://github.com/pokej6) for fixing it)
-* `ntfy sub` now uses default auth credentials as defined in `client.yml` ([#698](https://github.com/binwiederhier/ntfy/issues/698), thanks to [@CrimsonFez](https://github.com/CrimsonFez) for reporting, and to [@wunter8](https://github.com/wunter8) for fixing it)
+- Hide country flags on Windows ([#606](https://github.com/binwiederhier/ntfy/issues/606), thanks to [@cmeis](https://github.com/cmeis) for reporting, and to [@pokej6](https://github.com/pokej6) for fixing it)
+- `ntfy sub` now uses default auth credentials as defined in `client.yml` ([#698](https://github.com/binwiederhier/ntfy/issues/698), thanks to [@CrimsonFez](https://github.com/CrimsonFez) for reporting, and to [@wunter8](https://github.com/wunter8) for fixing it)
**Documentation:**
-* Updated PowerShell examples ([#697](https://github.com/binwiederhier/ntfy/pull/697), thanks to [@Natfan](https://github.com/Natfan))
+- Updated PowerShell examples ([#697](https://github.com/binwiederhier/ntfy/pull/697), thanks to [@Natfan](https://github.com/Natfan))
**Additional languages:**
-* Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/Shjosan/))
+- Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/Shjosan/))
+
+## ntfy server v2.3.1
-## ntfy server v2.3.1
Released March 30, 2023
This release disables server-initiated polling of iOS devices entirely, thereby eliminating the thundering herd problem
@@ -67,9 +71,10 @@ or Matrix if there are issues.
**Bug fixes + maintenance:**
-* Disable iOS polling entirely ([#677](https://github.com/binwiederhier/ntfy/issues/677)/[#509](https://github.com/binwiederhier/ntfy/issues/509))
+- Disable iOS polling entirely ([#677](https://github.com/binwiederhier/ntfy/issues/677)/[#509](https://github.com/binwiederhier/ntfy/issues/509))
## ntfy server v2.3.0
+
Released March 29, 2023
This release primarily fixes an issue with delayed messages, and it adds support for Go's profiler (if enabled), which
@@ -78,24 +83,25 @@ actual spikes [caused by iOS devices](https://github.com/binwiederhier/ntfy/issu
**Features:**
-* ntfy now supports Go's `pprof` profiler, if enabled (relates to [#677](https://github.com/binwiederhier/ntfy/issues/677))
+- ntfy now supports Go's `pprof` profiler, if enabled (relates to [#677](https://github.com/binwiederhier/ntfy/issues/677))
**Bug fixes + maintenance:**
-* Fix delayed message sending from authenticated users ([#679](https://github.com/binwiederhier/ntfy/issues/679))
-* Fixed plural for Polish and other translations ([#678](https://github.com/binwiederhier/ntfy/pull/678), thanks to [@bmoczulski](https://github.com/bmoczulski))
+- Fix delayed message sending from authenticated users ([#679](https://github.com/binwiederhier/ntfy/issues/679))
+- Fixed plural for Polish and other translations ([#678](https://github.com/binwiederhier/ntfy/pull/678), thanks to [@bmoczulski](https://github.com/bmoczulski))
## ntfy server v2.2.0
+
Released March 17, 2023
With this release, ntfy is now able to expose metrics via a `/metrics` endpoint for [Prometheus](https://prometheus.io/), if enabled.
The endpoint exposes about 20 different counters and gauges, from the number of published messages and emails, to active subscribers,
-visitors and topics. If you'd like more metrics, pop in the Discord/Matrix or file an issue on GitHub.
+visitors and topics. If you'd like more metrics, pop in the Discord/Matrix or file an issue on GitHub.
On top of this, you can now use access tokens in the ntfy CLI (defined in the `client.yml` file), fixed a bug in `ntfy subscribe`,
removed the dependency on Google Fonts, and more.
-🔥 Reminder: Purchase one of three **ntfy Pro plans** for **50% off** for a limited time (if you use promo code `MYTOPIC`).
+🔥 Reminder: Purchase one of three **ntfy Pro plans** for **50% off** for a limited time (if you use promo code `MYTOPIC`).
ntfy Pro gives you higher rate limits and lets you reserve topic names. [Buy through web app](https://ntfy.sh/app).
❤️ If you don't need ntfy Pro, please consider sponsoring ntfy via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
@@ -103,25 +109,26 @@ and [Liberapay](https://en.liberapay.com/ntfy/). ntfy will stay open source fore
**Features:**
-* Monitoring: ntfy now exposes a `/metrics` endpoint for [Prometheus](https://prometheus.io/) if [configured](config.md#monitoring) ([#210](https://github.com/binwiederhier/ntfy/issues/210), thanks to [@rogeliodh](https://github.com/rogeliodh) for reporting)
-* You can now use tokens in `client.yml` for publishing and subscribing ([#653](https://github.com/binwiederhier/ntfy/issues/653), thanks to [@wunter8](https://github.com/wunter8))
+- Monitoring: ntfy now exposes a `/metrics` endpoint for [Prometheus](https://prometheus.io/) if [configured](config.md#monitoring) ([#210](https://github.com/binwiederhier/ntfy/issues/210), thanks to [@rogeliodh](https://github.com/rogeliodh) for reporting)
+- You can now use tokens in `client.yml` for publishing and subscribing ([#653](https://github.com/binwiederhier/ntfy/issues/653), thanks to [@wunter8](https://github.com/wunter8))
**Bug fixes + maintenance:**
-* `ntfy sub --poll --from-config` will now include authentication headers from client.yml (if applicable) ([#658](https://github.com/binwiederhier/ntfy/issues/658), thanks to [@wunter8](https://github.com/wunter8))
-* Docs: Removed dependency on Google Fonts in docs ([#554](https://github.com/binwiederhier/ntfy/issues/554), thanks to [@bt90](https://github.com/bt90) for reporting, and [@ozskywalker](https://github.com/ozskywalker) for implementing)
-* Increase allowed auth failure attempts per IP address to 30 (no ticket)
-* Web app: Increase maximum incremental backoff retry interval to 2 minutes (no ticket)
+- `ntfy sub --poll --from-config` will now include authentication headers from client.yml (if applicable) ([#658](https://github.com/binwiederhier/ntfy/issues/658), thanks to [@wunter8](https://github.com/wunter8))
+- Docs: Removed dependency on Google Fonts in docs ([#554](https://github.com/binwiederhier/ntfy/issues/554), thanks to [@bt90](https://github.com/bt90) for reporting, and [@ozskywalker](https://github.com/ozskywalker) for implementing)
+- Increase allowed auth failure attempts per IP address to 30 (no ticket)
+- Web app: Increase maximum incremental backoff retry interval to 2 minutes (no ticket)
**Documentation:**
-* Make query parameter description more clear ([#630](https://github.com/binwiederhier/ntfy/issues/630), thanks to [@bbaa-bbaa](https://github.com/bbaa-bbaa) for reporting, and to [@wunter8](https://github.com/wunter8) for a fix)
+- Make query parameter description more clear ([#630](https://github.com/binwiederhier/ntfy/issues/630), thanks to [@bbaa-bbaa](https://github.com/bbaa-bbaa) for reporting, and to [@wunter8](https://github.com/wunter8) for a fix)
## ntfy server v2.1.2
+
Released March 4, 2023
This is a hotfix release, mostly to combat the ridiculous amount of Matrix requests with invalid/dead pushkeys, and the
-corresponding HTTP 507 responses the ntfy.sh server is sending out. We're up to >600k HTTP 507 responses per day 🤦. This
+corresponding HTTP 507 responses the ntfy.sh server is sending out. We're up to >600k HTTP 507 responses per day 🤦. This
release solves this issue by rejecting Matrix pushkeys, if nobody has subscribed to the corresponding topic for 12 hours.
The release furthermore reverts the default rate limiting behavior for UnifiedPush to be publisher-based, and introduces
@@ -129,25 +136,26 @@ a flag to enable [subscriber-based rate limiting](config.md#subscriber-based-rat
**Features:**
-* Support SMTP servers without auth ([#645](https://github.com/binwiederhier/ntfy/issues/645), thanks to [@Sharknoon](https://github.com/Sharknoon) for reporting)
+- Support SMTP servers without auth ([#645](https://github.com/binwiederhier/ntfy/issues/645), thanks to [@Sharknoon](https://github.com/Sharknoon) for reporting)
**Bug fixes + maintenance:**
-* Token auth doesn't work if default user credentials are defined in `client.yml` ([#650](https://github.com/binwiederhier/ntfy/issues/650), thanks to [@Xinayder](https://github.com/Xinayder))
-* Add `visitor-subscriber-rate-limiting` flag to allow enabling [subscriber-based rate limiting](config.md#subscriber-based-rate-limiting) (off by default now, [#649](https://github.com/binwiederhier/ntfy/issues/649)/[#655](https://github.com/binwiederhier/ntfy/pull/655), thanks to [@barathrm](https://github.com/barathrm) for reporting, and to [@karmanyaahm](https://github.com/karmanyaahm) and [@p1gp1g](https://github.com/p1gp1g) for help with the design)
-* Reject Matrix pushkey after 12 hours of inactivity on a topic, if `visitor-subscriber-rate-limiting` is enabled ([#643](https://github.com/binwiederhier/ntfy/pull/643), thanks to [@karmanyaahm](https://github.com/karmanyaahm) and [@p1gp1g](https://github.com/p1gp1g) for help with the design)
+- Token auth doesn't work if default user credentials are defined in `client.yml` ([#650](https://github.com/binwiederhier/ntfy/issues/650), thanks to [@Xinayder](https://github.com/Xinayder))
+- Add `visitor-subscriber-rate-limiting` flag to allow enabling [subscriber-based rate limiting](config.md#subscriber-based-rate-limiting) (off by default now, [#649](https://github.com/binwiederhier/ntfy/issues/649)/[#655](https://github.com/binwiederhier/ntfy/pull/655), thanks to [@barathrm](https://github.com/barathrm) for reporting, and to [@karmanyaahm](https://github.com/karmanyaahm) and [@p1gp1g](https://github.com/p1gp1g) for help with the design)
+- Reject Matrix pushkey after 12 hours of inactivity on a topic, if `visitor-subscriber-rate-limiting` is enabled ([#643](https://github.com/binwiederhier/ntfy/pull/643), thanks to [@karmanyaahm](https://github.com/karmanyaahm) and [@p1gp1g](https://github.com/p1gp1g) for help with the design)
**Additional languages:**
-* Danish (thanks to [@Andersbiha](https://hosted.weblate.org/user/Andersbiha/))
+- Danish (thanks to [@Andersbiha](https://hosted.weblate.org/user/Andersbiha/))
## ntfy server v2.1.1
+
Released March 1, 2023
-This is a tiny release with a few bug fixes, but it's big for me personally. After almost three months of work,
-**today I am finally launching the paid plans on ntfy.sh** 🥳 🎉.
+This is a tiny release with a few bug fixes, but it's big for me personally. After almost three months of work,
+**today I am finally launching the paid plans on ntfy.sh** 🥳 🎉.
-You are now able to purchase one of three plans that'll give you **higher rate limits** (messages, emails, attachment sizes, ...),
+You are now able to purchase one of three plans that'll give you **higher rate limits** (messages, emails, attachment sizes, ...),
as well as the ability to **reserve topic names** for your personal use, while at the same time supporting me and the
ntfy open source project ❤️. You can check out the pricing, and [purchase plans through the web app](https://ntfy.sh/app) (use
promo code `MYTOPIC` for a **50% discount**, limited time only).
@@ -157,14 +165,15 @@ are no closed-source features. So if you'd like to run your own server, you can!
**Bug fixes + maintenance:**
-* Fix panic when using Firebase without users ([#641](https://github.com/binwiederhier/ntfy/issues/641), thanks to [u/heavybell](https://www.reddit.com/user/heavybell/) for reporting)
-* Remove health check from `Dockerfile` and [document it](config.md#health-checks) ([#635](https://github.com/binwiederhier/ntfy/issues/635), thanks to [@Andersbiha](https://github.com/Andersbiha))
-* Upgrade dialog: Disable submit button for free tier (no ticket)
-* Allow multiple `log-level-overrides` on the same field (no ticket)
-* Actually remove `ntfy publish --env-topic` flag (as per [deprecations](deprecations.md), no ticket)
-* Added `billing-contact` config option (no ticket)
+- Fix panic when using Firebase without users ([#641](https://github.com/binwiederhier/ntfy/issues/641), thanks to [u/heavybell](https://www.reddit.com/user/heavybell/) for reporting)
+- Remove health check from `Dockerfile` and [document it](config.md#health-checks) ([#635](https://github.com/binwiederhier/ntfy/issues/635), thanks to [@Andersbiha](https://github.com/Andersbiha))
+- Upgrade dialog: Disable submit button for free tier (no ticket)
+- Allow multiple `log-level-overrides` on the same field (no ticket)
+- Actually remove `ntfy publish --env-topic` flag (as per [deprecations](deprecations.md), no ticket)
+- Added `billing-contact` config option (no ticket)
## ntfy server v2.1.0
+
Released February 25, 2023
This release changes the way UnifiedPush (UP) topics are rate limited from publisher-based rate limiting to subscriber-based
@@ -172,75 +181,77 @@ rate limiting. This allows UP application servers to send higher volumes, since
However, it also means that UP clients have to subscribe to a topic first before they are allowed to publish. If they do
no, clients will receive an HTTP 507 response from the server.
-We also fixed another issue with UnifiedPush: Some Mastodon servers were sending unsupported `Authorization` headers,
-which ntfy rejected with an HTTP 401. We now ignore unsupported header values.
+We also fixed another issue with UnifiedPush: Some Mastodon servers were sending unsupported `Authorization` headers,
+which ntfy rejected with an HTTP 401. We now ignore unsupported header values.
As of this release, ntfy also supports sending emails to protected topics, and it ships code to support annual billing
cycles (not live yet).
-As part of this release, I also enabled sign-up and login (free accounts only), and I also started reducing the rate
+As part of this release, I also enabled sign-up and login (free accounts only), and I also started reducing the rate
limits for anonymous & free users a bit. With the next release and the launch of the paid plan, I'll reduce the limits
a bit more. For 90% of users, you should not feel the difference.
**Features:**
-* UnifiedPush: Subscriber-based rate limiting for `up*` topics ([#584](https://github.com/binwiederhier/ntfy/pull/584)/[#609](https://github.com/binwiederhier/ntfy/pull/609)/[#633](https://github.com/binwiederhier/ntfy/pull/633), thanks to [@karmanyaahm](https://github.com/karmanyaahm))
-* Support for publishing to protected topics via email with access tokens ([#612](https://github.com/binwiederhier/ntfy/pull/621), thanks to [@tamcore](https://github.com/tamcore))
-* Support for base64-encoded and nested multipart emails ([#610](https://github.com/binwiederhier/ntfy/issues/610), thanks to [@Robert-litts](https://github.com/Robert-litts))
-* Payments: Add support for annual billing intervals (no ticket)
+- UnifiedPush: Subscriber-based rate limiting for `up*` topics ([#584](https://github.com/binwiederhier/ntfy/pull/584)/[#609](https://github.com/binwiederhier/ntfy/pull/609)/[#633](https://github.com/binwiederhier/ntfy/pull/633), thanks to [@karmanyaahm](https://github.com/karmanyaahm))
+- Support for publishing to protected topics via email with access tokens ([#612](https://github.com/binwiederhier/ntfy/pull/621), thanks to [@tamcore](https://github.com/tamcore))
+- Support for base64-encoded and nested multipart emails ([#610](https://github.com/binwiederhier/ntfy/issues/610), thanks to [@Robert-litts](https://github.com/Robert-litts))
+- Payments: Add support for annual billing intervals (no ticket)
**Bug fixes + maintenance:**
-* Web: Do not disable "Reserve topic" checkbox for admins (no ticket, thanks to @xenrox for reporting)
-* UnifiedPush: Treat non-Basic/Bearer `Authorization` header like header was not sent ([#629](https://github.com/binwiederhier/ntfy/issues/629), thanks to [@Boebbele](https://github.com/Boebbele) and [@S1m](https://github.com/S1m) for reporting)
+- Web: Do not disable "Reserve topic" checkbox for admins (no ticket, thanks to @xenrox for reporting)
+- UnifiedPush: Treat non-Basic/Bearer `Authorization` header like header was not sent ([#629](https://github.com/binwiederhier/ntfy/issues/629), thanks to [@Boebbele](https://github.com/Boebbele) and [@S1m](https://github.com/S1m) for reporting)
**Documentation:**
-* Added example for [Traccar](https://ntfy.sh/docs/examples/#traccar) ([#631](https://github.com/binwiederhier/ntfy/pull/631), thanks to [tamcore](https://github.com/tamcore))
+- Added example for [Traccar](https://ntfy.sh/docs/examples/#traccar) ([#631](https://github.com/binwiederhier/ntfy/pull/631), thanks to [tamcore](https://github.com/tamcore))
**Additional languages:**
-* Arabic (thanks to [@ButterflyOfFire](https://hosted.weblate.org/user/ButterflyOfFire/))
+- Arabic (thanks to [@ButterflyOfFire](https://hosted.weblate.org/user/ButterflyOfFire/))
## ntfy server v2.0.1
+
Released February 17, 2023
This is a quick bugfix release to address a panic that happens when `attachment-cache-dir` is not set.
**Bug fixes + maintenance:**
-* Avoid panic in manager when `attachment-cache-dir` is not set ([#617](https://github.com/binwiederhier/ntfy/issues/617), thanks to [@ksurl](https://github.com/ksurl))
-* Ensure that calls to standard logger `log.Println` also output JSON (no ticket)
+- Avoid panic in manager when `attachment-cache-dir` is not set ([#617](https://github.com/binwiederhier/ntfy/issues/617), thanks to [@ksurl](https://github.com/ksurl))
+- Ensure that calls to standard logger `log.Println` also output JSON (no ticket)
## ntfy server v2.0.0
+
Released February 16, 2023
-This is the biggest ntfy server release I've ever done 🥳 . Lots of new and exciting features.
+This is the biggest ntfy server release I've ever done 🥳 . Lots of new and exciting features.
**Brand-new features:**
-* **User signup/login & account sync**: If enabled, users can now register to create a user account, and then login to
- the web app. Once logged in, topic subscriptions and user settings are stored server-side in the user account (as
+- **User signup/login & account sync**: If enabled, users can now register to create a user account, and then login to
+ the web app. Once logged in, topic subscriptions and user settings are stored server-side in the user account (as
opposed to only in the browser storage). So far, this is implemented only in the web app only. Once it's in the Android/iOS
- app, you can easily keep your account in sync. Relevant [config options](config.md#config-options) are `enable-signup` and
+ app, you can easily keep your account in sync. Relevant [config options](config.md#config-options) are `enable-signup` and
`enable-login`.
-* **Topic reservations** 🎉: If enabled, users can now **reserve topics and restrict access to other users**.
+- **Topic reservations** 🎉: If enabled, users can now **reserve topics and restrict access to other users**.
Once this is fully rolled out, you may reserve `ntfy.sh/philbackups` and define access so that only you can publish/subscribe
to the topic. Reservations let you claim ownership of a topic, and you can define access permissions for others as
- `deny-all` (only you have full access), `read-only` (you can publish/subscribe, others can subscribe), `write-only` (you
+ `deny-all` (only you have full access), `read-only` (you can publish/subscribe, others can subscribe), `write-only` (you
can publish/subscribe, others can publish), `read-write` (everyone can publish/subscribe, but you remain the owner).
- Topic reservations can be [configured](config.md#config-options) in the web app if `enable-reservations` is enabled, and
+ Topic reservations can be [configured](config.md#config-options) in the web app if `enable-reservations` is enabled, and
only if the user has a [tier](config.md#tiers) that supports reservations.
-* **Access tokens:** It is now possible to create user access tokens for a user account. Access tokens are useful
- to avoid having to paste your password to various applications or scripts. For instance, you may want to use a
+- **Access tokens:** It is now possible to create user access tokens for a user account. Access tokens are useful
+ to avoid having to paste your password to various applications or scripts. For instance, you may want to use a
dedicated token to publish from your backup host, and one from your home automation system. Tokens can be configured
in the web app, or via the `ntfy token` command. See [creating tokens](config.md#access-tokens),
and [publishing using tokens](publish.md#access-tokens).
@@ -248,31 +259,31 @@ This is the biggest ntfy server release I've ever done 🥳 . Lots of new and ex
-* **Structured logging:** I've redone a lot of the logging to make it more structured, and to make it easier to debug and
+- **Structured logging:** I've redone a lot of the logging to make it more structured, and to make it easier to debug and
troubleshoot. Logs can now be written to a file, and as JSON (if configured). Each log event carries context fields
that you can filter and search on using tools like `jq`. On top of that, you can override the log level if certain fields
match. For instance, you can say `user_name=phil -> debug` to log everything related to a certain user with debug level.
See [logging & debugging](config.md#logging-debugging).
-* **Tiers:** You can now define and associate usage tiers to users. Tiers can be used to grant users higher limits, such as
+- **Tiers:** You can now define and associate usage tiers to users. Tiers can be used to grant users higher limits, such as
daily message limits, attachment size, or make it possible for users to reserve topics. You could, for instance, have
a tier `Standard` that allows 500 messages/day, 15 MB attachments and 5 allowed topic reservations, and another
tier `Friends & Family` with much higher limits. For ntfy.sh, I'll mostly use these tiers to facilitate paid plans (see below).
Tiers can be configured via the `ntfy tier ...` command. See [tiers](config.md#tiers).
-* **Paid tiers:** Starting very soon, I will be offering paid tiers for ntfy.sh on top of the free service. You'll be
+- **Paid tiers:** Starting very soon, I will be offering paid tiers for ntfy.sh on top of the free service. You'll be
able to subscribe to tiers with higher rate limits (more daily messages, bigger attachments) and topic reservations.
Paid tiers are facilitated by integrating [Stripe](https://stripe.com) as a payment provider. See [payments](config.md#payments)
for details.
-**ntfy is forever open source!**
-Yes, I will be offering some paid plans. But you don't need to panic! I won't be taking any features away, and everything
+**ntfy is forever open source!**
+Yes, I will be offering some paid plans. But you don't need to panic! I won't be taking any features away, and everything
will remain forever open source, so you can self-host if you like. Similar to the donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), paid plans will help pay for the service and keep me motivated to keep
going. It'll only make ntfy better.
**Other tickets:**
-* User account signup, login, topic reservations, access tokens, tiers etc. ([#522](https://github.com/binwiederhier/ntfy/issues/522))
-* `OPTIONS` method calls are not serviced when the UI is disabled ([#598](https://github.com/binwiederhier/ntfy/issues/598), thanks to [@enticedwanderer](https://github.com/enticedwanderer) for reporting)
+- User account signup, login, topic reservations, access tokens, tiers etc. ([#522](https://github.com/binwiederhier/ntfy/issues/522))
+- `OPTIONS` method calls are not serviced when the UI is disabled ([#598](https://github.com/binwiederhier/ntfy/issues/598), thanks to [@enticedwanderer](https://github.com/enticedwanderer) for reporting)
**Special thanks:**
@@ -280,37 +291,39 @@ A big Thank-you goes to everyone who tested the user account and payments work.
suggestions, and bug reports. Thank you, @nwithan8, @deadcade, @xenrox, @cmeis, @wunter8 and the others who I forgot.
## ntfy server v1.31.0
+
Released February 14, 2023
-This is a tiny release before the really big release, and also the last before the big v2.0.0. The most interesting
+This is a tiny release before the really big release, and also the last before the big v2.0.0. The most interesting
things in this release are the new preliminary health endpoint to allow monitoring in K8s (and others), and the removal
-of `upx` binary packing (which was causing erroneous virus flagging). Aside from that, the `go-smtp` library did a
+of `upx` binary packing (which was causing erroneous virus flagging). Aside from that, the `go-smtp` library did a
breaking-change upgrade, which required some work to get working again.
**Features:**
-* Preliminary `/v1/health` API endpoint for service monitoring (no ticket)
-* Add basic health check to `Dockerfile` ([#555](https://github.com/binwiederhier/ntfy/pull/555), thanks to [@bt90](https://github.com/bt90))
+- Preliminary `/v1/health` API endpoint for service monitoring (no ticket)
+- Add basic health check to `Dockerfile` ([#555](https://github.com/binwiederhier/ntfy/pull/555), thanks to [@bt90](https://github.com/bt90))
**Bug fixes + maintenance:**
-* Fix `chown` issues with RHEL-like based systems ([#566](https://github.com/binwiederhier/ntfy/issues/566)/[#565](https://github.com/binwiederhier/ntfy/pull/565), thanks to [@danieldemus](https://github.com/danieldemus))
-* Removed `upx` (binary packing) for all builds due to false virus warnings ([#576](https://github.com/binwiederhier/ntfy/issues/576), thanks to [@shawnhwei](https://github.com/shawnhwei) for reporting)
-* Upgraded `go-smtp` library and tests to v0.16.0 ([#569](https://github.com/binwiederhier/ntfy/issues/569))
+- Fix `chown` issues with RHEL-like based systems ([#566](https://github.com/binwiederhier/ntfy/issues/566)/[#565](https://github.com/binwiederhier/ntfy/pull/565), thanks to [@danieldemus](https://github.com/danieldemus))
+- Removed `upx` (binary packing) for all builds due to false virus warnings ([#576](https://github.com/binwiederhier/ntfy/issues/576), thanks to [@shawnhwei](https://github.com/shawnhwei) for reporting)
+- Upgraded `go-smtp` library and tests to v0.16.0 ([#569](https://github.com/binwiederhier/ntfy/issues/569))
**Documentation:**
-* Add HTTP/2 and TLSv1.3 support to nginx docs ([#553](https://github.com/binwiederhier/ntfy/issues/553), thanks to [@bt90](https://github.com/bt90))
-* Small wording change for `client.yml` ([#562](https://github.com/binwiederhier/ntfy/pull/562), thanks to [@fleopaulD](https://github.com/fleopaulD))
-* Fix K8s install docs ([#582](https://github.com/binwiederhier/ntfy/pull/582), thanks to [@Remedan](https://github.com/Remedan))
-* Updated Jellyseer docs ([#604](https://github.com/binwiederhier/ntfy/pull/604), thanks to [@Y0ngg4n](https://github.com/Y0ngg4n))
-* Updated iOS developer docs ([#605](https://github.com/binwiederhier/ntfy/pull/605), thanks to [@SticksDev](https://github.com/SticksDev))
+- Add HTTP/2 and TLSv1.3 support to nginx docs ([#553](https://github.com/binwiederhier/ntfy/issues/553), thanks to [@bt90](https://github.com/bt90))
+- Small wording change for `client.yml` ([#562](https://github.com/binwiederhier/ntfy/pull/562), thanks to [@fleopaulD](https://github.com/fleopaulD))
+- Fix K8s install docs ([#582](https://github.com/binwiederhier/ntfy/pull/582), thanks to [@Remedan](https://github.com/Remedan))
+- Updated Jellyseer docs ([#604](https://github.com/binwiederhier/ntfy/pull/604), thanks to [@Y0ngg4n](https://github.com/Y0ngg4n))
+- Updated iOS developer docs ([#605](https://github.com/binwiederhier/ntfy/pull/605), thanks to [@SticksDev](https://github.com/SticksDev))
**Additional languages:**
-* Portuguese (thanks to [@ssantos](https://hosted.weblate.org/user/ssantos/))
+- Portuguese (thanks to [@ssantos](https://hosted.weblate.org/user/ssantos/))
## ntfy server v1.30.1
+
Released December 23, 2022 🎅
This is a special holiday edition version of ntfy, with all sorts of holiday fun and games, and hidden quests.
@@ -319,17 +332,18 @@ roll out the TLSv1.3, HTTP/2 and Unix mode changes on ntfy.sh (see [#552](https:
**Features:**
-* Web: Generate random topic name button ([#453](https://github.com/binwiederhier/ntfy/issues/453), thanks to [@yardenshoham](https://github.com/yardenshoham))
-* Add [Gitpod config](https://github.com/binwiederhier/ntfy/blob/main/.gitpod.yml) ([#540](https://github.com/binwiederhier/ntfy/pull/540), thanks to [@yardenshoham](https://github.com/yardenshoham))
+- Web: Generate random topic name button ([#453](https://github.com/binwiederhier/ntfy/issues/453), thanks to [@yardenshoham](https://github.com/yardenshoham))
+- Add [Gitpod config](https://github.com/binwiederhier/ntfy/blob/main/.gitpod.yml) ([#540](https://github.com/binwiederhier/ntfy/pull/540), thanks to [@yardenshoham](https://github.com/yardenshoham))
**Bug fixes + maintenance:**
-* Remove `--env-topic` option from `ntfy publish` as per [deprecation](deprecations.md) (no ticket)
-* Prepared statements for message cache writes ([#542](https://github.com/binwiederhier/ntfy/pull/542), thanks to [@nicois](https://github.com/nicois))
-* Do not warn about invalid IP address when behind proxy in unix socket mode (relates to [#552](https://github.com/binwiederhier/ntfy/issues/552))
-* Upgrade nginx/ntfy config on ntfy.sh to work with TLSv1.3, HTTP/2 ([#552](https://github.com/binwiederhier/ntfy/issues/552), thanks to [@bt90](https://github.com/bt90))
+- Remove `--env-topic` option from `ntfy publish` as per [deprecation](deprecations.md) (no ticket)
+- Prepared statements for message cache writes ([#542](https://github.com/binwiederhier/ntfy/pull/542), thanks to [@nicois](https://github.com/nicois))
+- Do not warn about invalid IP address when behind proxy in unix socket mode (relates to [#552](https://github.com/binwiederhier/ntfy/issues/552))
+- Upgrade nginx/ntfy config on ntfy.sh to work with TLSv1.3, HTTP/2 ([#552](https://github.com/binwiederhier/ntfy/issues/552), thanks to [@bt90](https://github.com/bt90))
## ntfy Android app v1.16.0
+
Released December 11, 2022
This is a feature and platform/dependency upgrade release. You can now have per-subscription notification settings
@@ -341,33 +355,34 @@ opening the wrong subscription, and we also fixed the icon color issue.
**Features:**
-* Custom per-subscription notification settings incl. sounds, DND, etc. ([#6](https://github.com/binwiederhier/ntfy/issues/6), thanks to [@doits](https://github.com/doits))
-* Insistent notifications that ring until dismissed ([#417](https://github.com/binwiederhier/ntfy/issues/417), thanks to [@danmed](https://github.com/danmed) for reporting)
-* Add thematic/adaptive launcher icon ([#513](https://github.com/binwiederhier/ntfy/issues/513), thanks to [@daedric7](https://github.com/daedric7) for reporting)
+- Custom per-subscription notification settings incl. sounds, DND, etc. ([#6](https://github.com/binwiederhier/ntfy/issues/6), thanks to [@doits](https://github.com/doits))
+- Insistent notifications that ring until dismissed ([#417](https://github.com/binwiederhier/ntfy/issues/417), thanks to [@danmed](https://github.com/danmed) for reporting)
+- Add thematic/adaptive launcher icon ([#513](https://github.com/binwiederhier/ntfy/issues/513), thanks to [@daedric7](https://github.com/daedric7) for reporting)
**Bug fixes + maintenance:**
-* Upgrade Android dependencies and build toolchain to SDK 33 (no ticket)
-* Simplify F-Droid build: Disable tasks for Google Services ([#516](https://github.com/binwiederhier/ntfy/issues/516), thanks to [@markosopcic](https://github.com/markosopcic))
-* Android 13: Ask for permission to post notifications ([#508](https://github.com/binwiederhier/ntfy/issues/508))
-* Android 13: Do not allow swiping away the foreground notification ([#521](https://github.com/binwiederhier/ntfy/issues/521), thanks to [@alexhorner](https://github.com/alexhorner) for reporting)
-* Android 5 (SDK 21): Fix crash on unsubscribing ([#528](https://github.com/binwiederhier/ntfy/issues/528), thanks to Roger M.)
-* Remove timestamp when copying message text ([#471](https://github.com/binwiederhier/ntfy/issues/471), thanks to [@wunter8](https://github.com/wunter8))
-* Fix auto-delete if some icons do not exist anymore ([#506](https://github.com/binwiederhier/ntfy/issues/506))
-* Fix notification icon color ([#480](https://github.com/binwiederhier/ntfy/issues/480), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d) for reporting)
-* Fix topics do not re-subscribe to Firebase after restoring from backup ([#511](https://github.com/binwiederhier/ntfy/issues/511))
-* Fix crashes from large images ([#474](https://github.com/binwiederhier/ntfy/issues/474), thanks to [@daedric7](https://github.com/daedric7) for reporting)
-* Fix notification click opens wrong subscription ([#261](https://github.com/binwiederhier/ntfy/issues/261), thanks to [@SMAW](https://github.com/SMAW) for reporting)
-* Fix Firebase-only "link expired" issue ([#529](https://github.com/binwiederhier/ntfy/issues/529))
-* Remove "Install .apk" feature in Google Play variant due to policy change ([#531](https://github.com/binwiederhier/ntfy/issues/531))
-* Add donate button (no ticket)
+- Upgrade Android dependencies and build toolchain to SDK 33 (no ticket)
+- Simplify F-Droid build: Disable tasks for Google Services ([#516](https://github.com/binwiederhier/ntfy/issues/516), thanks to [@markosopcic](https://github.com/markosopcic))
+- Android 13: Ask for permission to post notifications ([#508](https://github.com/binwiederhier/ntfy/issues/508))
+- Android 13: Do not allow swiping away the foreground notification ([#521](https://github.com/binwiederhier/ntfy/issues/521), thanks to [@alexhorner](https://github.com/alexhorner) for reporting)
+- Android 5 (SDK 21): Fix crash on unsubscribing ([#528](https://github.com/binwiederhier/ntfy/issues/528), thanks to Roger M.)
+- Remove timestamp when copying message text ([#471](https://github.com/binwiederhier/ntfy/issues/471), thanks to [@wunter8](https://github.com/wunter8))
+- Fix auto-delete if some icons do not exist anymore ([#506](https://github.com/binwiederhier/ntfy/issues/506))
+- Fix notification icon color ([#480](https://github.com/binwiederhier/ntfy/issues/480), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d) for reporting)
+- Fix topics do not re-subscribe to Firebase after restoring from backup ([#511](https://github.com/binwiederhier/ntfy/issues/511))
+- Fix crashes from large images ([#474](https://github.com/binwiederhier/ntfy/issues/474), thanks to [@daedric7](https://github.com/daedric7) for reporting)
+- Fix notification click opens wrong subscription ([#261](https://github.com/binwiederhier/ntfy/issues/261), thanks to [@SMAW](https://github.com/SMAW) for reporting)
+- Fix Firebase-only "link expired" issue ([#529](https://github.com/binwiederhier/ntfy/issues/529))
+- Remove "Install .apk" feature in Google Play variant due to policy change ([#531](https://github.com/binwiederhier/ntfy/issues/531))
+- Add donate button (no ticket)
**Additional translations:**
-* Korean (thanks to [@YJSofta0f97461d82447ac](https://hosted.weblate.org/user/YJSofta0f97461d82447ac/))
-* Portuguese (thanks to [@victormagalhaess](https://hosted.weblate.org/user/victormagalhaess/))
+- Korean (thanks to [@YJSofta0f97461d82447ac](https://hosted.weblate.org/user/YJSofta0f97461d82447ac/))
+- Portuguese (thanks to [@victormagalhaess](https://hosted.weblate.org/user/victormagalhaess/))
## ntfy server v1.29.1
+
Released November 17, 2022
This is mostly a bugfix release to address the high load on ntfy.sh. There are now two new options that allow
@@ -376,72 +391,74 @@ requests.
**Bug fixes:**
-* High-load servers: Allow asynchronous batch-writing of messages to cache via `cache-batch-*` options ([#498](https://github.com/binwiederhier/ntfy/issues/498)/[#502](https://github.com/binwiederhier/ntfy/pull/502))
-* Sender column in cache.db shows invalid IP ([#503](https://github.com/binwiederhier/ntfy/issues/503))
+- High-load servers: Allow asynchronous batch-writing of messages to cache via `cache-batch-*` options ([#498](https://github.com/binwiederhier/ntfy/issues/498)/[#502](https://github.com/binwiederhier/ntfy/pull/502))
+- Sender column in cache.db shows invalid IP ([#503](https://github.com/binwiederhier/ntfy/issues/503))
**Documentation:**
-* GitHub Actions example ([#492](https://github.com/binwiederhier/ntfy/pull/492), thanks to [@ksurl](https://github.com/ksurl))
-* UnifiedPush ACL clarification ([#497](https://github.com/binwiederhier/ntfy/issues/497), thanks to [@bt90](https://github.com/bt90))
-* Install instructions for Kustomize ([#463](https://github.com/binwiederhier/ntfy/pull/463), thanks to [@l-maciej](https://github.com/l-maciej))
+- GitHub Actions example ([#492](https://github.com/binwiederhier/ntfy/pull/492), thanks to [@ksurl](https://github.com/ksurl))
+- UnifiedPush ACL clarification ([#497](https://github.com/binwiederhier/ntfy/issues/497), thanks to [@bt90](https://github.com/bt90))
+- Install instructions for Kustomize ([#463](https://github.com/binwiederhier/ntfy/pull/463), thanks to [@l-maciej](https://github.com/l-maciej))
**Other things:**
-* Put ntfy.sh docs on GitHub pages to reduce AWS outbound traffic cost ([#491](https://github.com/binwiederhier/ntfy/issues/491))
-* The ntfy.sh server hardware was upgraded to a bigger box. If you'd like to help out carrying the server cost, **[sponsorships and donations](https://github.com/sponsors/binwiederhier)** 💸 would be very much appreciated
+- Put ntfy.sh docs on GitHub pages to reduce AWS outbound traffic cost ([#491](https://github.com/binwiederhier/ntfy/issues/491))
+- The ntfy.sh server hardware was upgraded to a bigger box. If you'd like to help out carrying the server cost, **[sponsorships and donations](https://github.com/sponsors/binwiederhier)** 💸 would be very much appreciated
## ntfy server v1.29.0
+
Released November 12, 2022
-This release adds the ability to add rate limit exemptions for IP ranges instead of just specific IP addresses. It also fixes
+This release adds the ability to add rate limit exemptions for IP ranges instead of just specific IP addresses. It also fixes
a few bugs in the web app and the CLI and adds lots of new examples and install instructions.
Thanks to [some love on HN](https://news.ycombinator.com/item?id=33517944), we got so many new ntfy users trying out ntfy
-and joining the [chat rooms](https://github.com/binwiederhier/ntfy#chat--forum). **Welcome to the ntfy community to all of you!**
+and joining the [chat rooms](https://github.com/binwiederhier/ntfy#chat--forum). **Welcome to the ntfy community to all of you!**
We also got a ton of new **[sponsors and donations](https://github.com/sponsors/binwiederhier)** 💸, which is amazing. I'd like to thank
all of you for believing in the project, and for helping me pay the server cost. The HN spike increased the AWS cost quite a bit.
**Features:**
-* Allow IP CIDRs in `visitor-request-limit-exempt-hosts` ([#423](https://github.com/binwiederhier/ntfy/issues/423), thanks to [@karmanyaahm](https://github.com/karmanyaahm))
+- Allow IP CIDRs in `visitor-request-limit-exempt-hosts` ([#423](https://github.com/binwiederhier/ntfy/issues/423), thanks to [@karmanyaahm](https://github.com/karmanyaahm))
**Bug fixes + maintenance:**
-* Subscriptions can now have a display name ([#370](https://github.com/binwiederhier/ntfy/issues/370), thanks to [@tfheen](https://github.com/tfheen) for reporting)
-* Bump Go version to Go 18.x ([#422](https://github.com/binwiederhier/ntfy/issues/422))
-* Web: Strip trailing slash when subscribing ([#428](https://github.com/binwiederhier/ntfy/issues/428), thanks to [@raining1123](https://github.com/raining1123) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
-* Web: Strip trailing slash after server URL in publish dialog ([#441](https://github.com/binwiederhier/ntfy/issues/441), thanks to [@wunter8](https://github.com/wunter8))
-* Allow empty passwords in `client.yml` ([#374](https://github.com/binwiederhier/ntfy/issues/374), thanks to [@cyqsimon](https://github.com/cyqsimon) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
-* `ntfy pub` will now use default username and password from `client.yml` ([#431](https://github.com/binwiederhier/ntfy/issues/431), thanks to [@wunter8](https://github.com/wunter8) for fixing)
-* Make `ntfy sub` work with `NTFY_USER` env variable ([#447](https://github.com/binwiederhier/ntfy/pull/447), thanks to [SuperSandro2000](https://github.com/SuperSandro2000))
-* Web: Disallow GET/HEAD requests with body in actions ([#468](https://github.com/binwiederhier/ntfy/issues/468), thanks to [@ollien](https://github.com/ollien))
+- Subscriptions can now have a display name ([#370](https://github.com/binwiederhier/ntfy/issues/370), thanks to [@tfheen](https://github.com/tfheen) for reporting)
+- Bump Go version to Go 18.x ([#422](https://github.com/binwiederhier/ntfy/issues/422))
+- Web: Strip trailing slash when subscribing ([#428](https://github.com/binwiederhier/ntfy/issues/428), thanks to [@raining1123](https://github.com/raining1123) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
+- Web: Strip trailing slash after server URL in publish dialog ([#441](https://github.com/binwiederhier/ntfy/issues/441), thanks to [@wunter8](https://github.com/wunter8))
+- Allow empty passwords in `client.yml` ([#374](https://github.com/binwiederhier/ntfy/issues/374), thanks to [@cyqsimon](https://github.com/cyqsimon) for reporting, and [@wunter8](https://github.com/wunter8) for fixing)
+- `ntfy pub` will now use default username and password from `client.yml` ([#431](https://github.com/binwiederhier/ntfy/issues/431), thanks to [@wunter8](https://github.com/wunter8) for fixing)
+- Make `ntfy sub` work with `NTFY_USER` env variable ([#447](https://github.com/binwiederhier/ntfy/pull/447), thanks to [SuperSandro2000](https://github.com/SuperSandro2000))
+- Web: Disallow GET/HEAD requests with body in actions ([#468](https://github.com/binwiederhier/ntfy/issues/468), thanks to [@ollien](https://github.com/ollien))
**Documentation:**
-* Updated developer docs, bump nodejs and go version ([#414](https://github.com/binwiederhier/ntfy/issues/414), thanks to [@YJSoft](https://github.com/YJSoft) for reporting)
-* Officially document `?auth=..` query parameter ([#433](https://github.com/binwiederhier/ntfy/pull/433), thanks to [@wunter8](https://github.com/wunter8))
-* Added Rundeck example ([#427](https://github.com/binwiederhier/ntfy/pull/427), thanks to [@demogorgonz](https://github.com/demogorgonz))
-* Fix Debian installation instructions ([#237](https://github.com/binwiederhier/ntfy/issues/237), thanks to [@Joeharrison94](https://github.com/Joeharrison94) for reporting)
-* Updated [example](https://ntfy.sh/docs/examples/#gatus) with official [Gatus](https://github.com/TwiN/gatus) integration (thanks to [@TwiN](https://github.com/TwiN))
-* Added [Kubernetes install instructions](https://ntfy.sh/docs/install/#kubernetes) ([#452](https://github.com/binwiederhier/ntfy/pull/452), thanks to [@gmemstr](https://github.com/gmemstr))
-* Added [additional NixOS links for self-hosting](https://ntfy.sh/docs/install/#nixos-nix) ([#462](https://github.com/binwiederhier/ntfy/pull/462), thanks to [@wamserma](https://github.com/wamserma))
-* Added additional [more secure nginx config example](https://ntfy.sh/docs/config/#nginxapache2caddy) ([#451](https://github.com/binwiederhier/ntfy/pull/451), thanks to [SuperSandro2000](https://github.com/SuperSandro2000))
-* Minor fixes in the config table ([#470](https://github.com/binwiederhier/ntfy/pull/470), thanks to [snh](https://github.com/snh))
-* Fix broken link ([#476](https://github.com/binwiederhier/ntfy/pull/476), thanks to [@shuuji3](https://github.com/shuuji3))
+- Updated developer docs, bump nodejs and go version ([#414](https://github.com/binwiederhier/ntfy/issues/414), thanks to [@YJSoft](https://github.com/YJSoft) for reporting)
+- Officially document `?auth=..` query parameter ([#433](https://github.com/binwiederhier/ntfy/pull/433), thanks to [@wunter8](https://github.com/wunter8))
+- Added Rundeck example ([#427](https://github.com/binwiederhier/ntfy/pull/427), thanks to [@demogorgonz](https://github.com/demogorgonz))
+- Fix Debian installation instructions ([#237](https://github.com/binwiederhier/ntfy/issues/237), thanks to [@Joeharrison94](https://github.com/Joeharrison94) for reporting)
+- Updated [example](https://ntfy.sh/docs/examples/#gatus) with official [Gatus](https://github.com/TwiN/gatus) integration (thanks to [@TwiN](https://github.com/TwiN))
+- Added [Kubernetes install instructions](https://ntfy.sh/docs/install/#kubernetes) ([#452](https://github.com/binwiederhier/ntfy/pull/452), thanks to [@gmemstr](https://github.com/gmemstr))
+- Added [additional NixOS links for self-hosting](https://ntfy.sh/docs/install/#nixos-nix) ([#462](https://github.com/binwiederhier/ntfy/pull/462), thanks to [@wamserma](https://github.com/wamserma))
+- Added additional [more secure nginx config example](https://ntfy.sh/docs/config/#nginxapache2caddy) ([#451](https://github.com/binwiederhier/ntfy/pull/451), thanks to [SuperSandro2000](https://github.com/SuperSandro2000))
+- Minor fixes in the config table ([#470](https://github.com/binwiederhier/ntfy/pull/470), thanks to [snh](https://github.com/snh))
+- Fix broken link ([#476](https://github.com/binwiederhier/ntfy/pull/476), thanks to [@shuuji3](https://github.com/shuuji3))
**Additional translations:**
-* Korean (thanks to [@YJSofta0f97461d82447ac](https://hosted.weblate.org/user/YJSofta0f97461d82447ac/))
+- Korean (thanks to [@YJSofta0f97461d82447ac](https://hosted.weblate.org/user/YJSofta0f97461d82447ac/))
**Sponsorships:**:
-Thank you to the amazing folks who decided to [sponsor ntfy](https://github.com/sponsors/binwiederhier). Thank you for
-helping carry the cost of the public server and developer licenses, and more importantly: Thank you for believing in ntfy!
-You guys rock!
+Thank you to the amazing folks who decided to [sponsor ntfy](https://github.com/sponsors/binwiederhier). Thank you for
+helping carry the cost of the public server and developer licenses, and more importantly: Thank you for believing in ntfy!
+You guys rock!
A list of all the sponsors can be found in the [README](https://github.com/binwiederhier/ntfy/blob/main/README.md).
-## ntfy Android app v1.14.0
+## ntfy Android app v1.14.0
+
Released September 27, 2022
This release adds the ability to set a custom icon to each notification, as well as a display name to subscriptions. We
@@ -450,119 +467,123 @@ languages. Hurray!
**Features:**
-* Subscriptions can now have a display name ([#313](https://github.com/binwiederhier/ntfy/issues/313), thanks to [@wunter8](https://github.com/wunter8))
-* Display name for UnifiedPush subscriptions ([#355](https://github.com/binwiederhier/ntfy/issues/355), thanks to [@wunter8](https://github.com/wunter8))
-* Polling is now done with `since=` API, which makes deduping easier ([#165](https://github.com/binwiederhier/ntfy/issues/165))
-* Turned JSON stream deprecation banner into "Use WebSockets" banner (no ticket)
-* Move action buttons in notification cards ([#236](https://github.com/binwiederhier/ntfy/issues/236), thanks to [@wunter8](https://github.com/wunter8))
-* Icons can be set for each individual notification ([#126](https://github.com/binwiederhier/ntfy/issues/126), thanks to [@wunter8](https://github.com/wunter8))
+- Subscriptions can now have a display name ([#313](https://github.com/binwiederhier/ntfy/issues/313), thanks to [@wunter8](https://github.com/wunter8))
+- Display name for UnifiedPush subscriptions ([#355](https://github.com/binwiederhier/ntfy/issues/355), thanks to [@wunter8](https://github.com/wunter8))
+- Polling is now done with `since=` API, which makes deduping easier ([#165](https://github.com/binwiederhier/ntfy/issues/165))
+- Turned JSON stream deprecation banner into "Use WebSockets" banner (no ticket)
+- Move action buttons in notification cards ([#236](https://github.com/binwiederhier/ntfy/issues/236), thanks to [@wunter8](https://github.com/wunter8))
+- Icons can be set for each individual notification ([#126](https://github.com/binwiederhier/ntfy/issues/126), thanks to [@wunter8](https://github.com/wunter8))
**Bug fixes:**
-* Long-click selecting of notifications doesn't scroll to the top anymore ([#235](https://github.com/binwiederhier/ntfy/issues/235), thanks to [@wunter8](https://github.com/wunter8))
-* Add attachment and click URL extras to MESSAGE_RECEIVED broadcast ([#329](https://github.com/binwiederhier/ntfy/issues/329), thanks to [@wunter8](https://github.com/wunter8))
-* Accessibility: Clear/choose service URL button in base URL dropdown now has a label ([#292](https://github.com/binwiederhier/ntfy/issues/292), thanks to [@mhameed](https://github.com/mhameed) for reporting)
+- Long-click selecting of notifications doesn't scroll to the top anymore ([#235](https://github.com/binwiederhier/ntfy/issues/235), thanks to [@wunter8](https://github.com/wunter8))
+- Add attachment and click URL extras to MESSAGE_RECEIVED broadcast ([#329](https://github.com/binwiederhier/ntfy/issues/329), thanks to [@wunter8](https://github.com/wunter8))
+- Accessibility: Clear/choose service URL button in base URL dropdown now has a label ([#292](https://github.com/binwiederhier/ntfy/issues/292), thanks to [@mhameed](https://github.com/mhameed) for reporting)
**Additional translations:**
-* Italian (thanks to [@Genio2003](https://hosted.weblate.org/user/Genio2003/))
-* Dutch (thanks to [@SchoNie](https://hosted.weblate.org/user/SchoNie/))
-* Ukranian (thanks to [@v.kopitsa](https://hosted.weblate.org/user/v.kopitsa/))
-* Polish (thanks to [@Namax0r](https://hosted.weblate.org/user/Namax0r/))
+- Italian (thanks to [@Genio2003](https://hosted.weblate.org/user/Genio2003/))
+- Dutch (thanks to [@SchoNie](https://hosted.weblate.org/user/SchoNie/))
+- Ukranian (thanks to [@v.kopitsa](https://hosted.weblate.org/user/v.kopitsa/))
+- Polish (thanks to [@Namax0r](https://hosted.weblate.org/user/Namax0r/))
Thank you to [@wunter8](https://github.com/wunter8) for proactively picking up some Android tickets, and fixing them! You rock!
## ntfy server v1.28.0
+
Released September 27, 2022
This release primarily adds icon support for the Android app, and adds a display name to subscriptions in the web app.
Aside from that, we fixed a few random bugs, most importantly the `Priority` header bug that allows the use behind
Cloudflare. We also added a ton of documentation. Most prominently, an [integrations + projects page](https://ntfy.sh/docs/integrations/).
-As of now, I also have started accepting **[donations and sponsorships](https://github.com/sponsors/binwiederhier)** 💸.
+As of now, I also have started accepting **[donations and sponsorships](https://github.com/sponsors/binwiederhier)** 💸.
I would be very humbled if you consider donating.
**Features:**
-* Subscription display name for the web app ([#348](https://github.com/binwiederhier/ntfy/pull/348))
-* Allow setting socket permissions via `--listen-unix-mode` ([#356](https://github.com/binwiederhier/ntfy/pull/356), thanks to [@koro666](https://github.com/koro666))
-* Icons can be set for each individual notification ([#126](https://github.com/binwiederhier/ntfy/issues/126), thanks to [@wunter8](https://github.com/wunter8))
-* CLI: Allow default username/password in `client.yml` ([#372](https://github.com/binwiederhier/ntfy/pull/372), thanks to [@wunter8](https://github.com/wunter8))
-* Build support for other Unix systems ([#393](https://github.com/binwiederhier/ntfy/pull/393), thanks to [@la-ninpre](https://github.com/la-ninpre))
+- Subscription display name for the web app ([#348](https://github.com/binwiederhier/ntfy/pull/348))
+- Allow setting socket permissions via `--listen-unix-mode` ([#356](https://github.com/binwiederhier/ntfy/pull/356), thanks to [@koro666](https://github.com/koro666))
+- Icons can be set for each individual notification ([#126](https://github.com/binwiederhier/ntfy/issues/126), thanks to [@wunter8](https://github.com/wunter8))
+- CLI: Allow default username/password in `client.yml` ([#372](https://github.com/binwiederhier/ntfy/pull/372), thanks to [@wunter8](https://github.com/wunter8))
+- Build support for other Unix systems ([#393](https://github.com/binwiederhier/ntfy/pull/393), thanks to [@la-ninpre](https://github.com/la-ninpre))
**Bug fixes:**
-* `ntfy user` commands don't work with `auth_file` but works with `auth-file` ([#344](https://github.com/binwiederhier/ntfy/issues/344), thanks to [@Histalek](https://github.com/Histalek) for reporting)
-* Ignore new draft HTTP `Priority` header ([#351](https://github.com/binwiederhier/ntfy/issues/351), thanks to [@ksurl](https://github.com/ksurl) for reporting)
-* Delete expired attachments based on mod time instead of DB entry to avoid races (no ticket)
-* Better logging for Matrix push key errors ([#384](https://github.com/binwiederhier/ntfy/pull/384), thanks to [@christophehenry](https://github.com/christophehenry))
-* Web: Switched "Pop" and "Pop Swoosh" sounds ([#352](https://github.com/binwiederhier/ntfy/issues/352), thanks to [@coma-toast](https://github.com/coma-toast) for reporting)
+- `ntfy user` commands don't work with `auth_file` but works with `auth-file` ([#344](https://github.com/binwiederhier/ntfy/issues/344), thanks to [@Histalek](https://github.com/Histalek) for reporting)
+- Ignore new draft HTTP `Priority` header ([#351](https://github.com/binwiederhier/ntfy/issues/351), thanks to [@ksurl](https://github.com/ksurl) for reporting)
+- Delete expired attachments based on mod time instead of DB entry to avoid races (no ticket)
+- Better logging for Matrix push key errors ([#384](https://github.com/binwiederhier/ntfy/pull/384), thanks to [@christophehenry](https://github.com/christophehenry))
+- Web: Switched "Pop" and "Pop Swoosh" sounds ([#352](https://github.com/binwiederhier/ntfy/issues/352), thanks to [@coma-toast](https://github.com/coma-toast) for reporting)
**Documentation:**
-* Added [integrations + projects page](https://ntfy.sh/docs/integrations/) (**so many integrations, whoa!**)
-* Added example for [UptimeRobot](https://ntfy.sh/docs/examples/#uptimerobot)
-* Fix some PowerShell publish docs ([#345](https://github.com/binwiederhier/ntfy/pull/345), thanks to [@noahpeltier](https://github.com/noahpeltier))
-* Clarified Docker install instructions ([#361](https://github.com/binwiederhier/ntfy/issues/361), thanks to [@barart](https://github.com/barart) for reporting)
-* Mismatched quotation marks ([#392](https://github.com/binwiederhier/ntfy/pull/392)], thanks to [@connorlanigan](https://github.com/connorlanigan))
+- Added [integrations + projects page](https://ntfy.sh/docs/integrations/) (**so many integrations, whoa!**)
+- Added example for [UptimeRobot](https://ntfy.sh/docs/examples/#uptimerobot)
+- Fix some PowerShell publish docs ([#345](https://github.com/binwiederhier/ntfy/pull/345), thanks to [@noahpeltier](https://github.com/noahpeltier))
+- Clarified Docker install instructions ([#361](https://github.com/binwiederhier/ntfy/issues/361), thanks to [@barart](https://github.com/barart) for reporting)
+- Mismatched quotation marks ([#392](https://github.com/binwiederhier/ntfy/pull/392)], thanks to [@connorlanigan](https://github.com/connorlanigan))
**Additional translations:**
-* Ukranian (thanks to [@v.kopitsa](https://hosted.weblate.org/user/v.kopitsa/))
-* Polish (thanks to [@Namax0r](https://hosted.weblate.org/user/Namax0r/))
+- Ukranian (thanks to [@v.kopitsa](https://hosted.weblate.org/user/v.kopitsa/))
+- Polish (thanks to [@Namax0r](https://hosted.weblate.org/user/Namax0r/))
## ntfy server v1.27.2
+
Released June 23, 2022
This release brings two new CLI options to wait for a command to finish, or for a PID to exit. It also adds more detail
-to trace debug output. Aside from other bugs, it fixes a performance issue that occurred in large installations every
-minute or so, due to competing stats gathering (personal installations will likely be unaffected by this).
+to trace debug output. Aside from other bugs, it fixes a performance issue that occurred in large installations every
+minute or so, due to competing stats gathering (personal installations will likely be unaffected by this).
**Features:**
-* Add `cache-startup-queries` option to allow custom [SQLite performance tuning](config.md#wal-for-message-cache) (no ticket)
-* ntfy CLI can now [wait for a command or PID](subscribe/cli.md#wait-for-pidcommand) before publishing ([#263](https://github.com/binwiederhier/ntfy/issues/263), thanks to the [original ntfy](https://github.com/dschep/ntfy) for the idea)
-* Trace: Log entire HTTP request to simplify debugging (no ticket)
-* Allow setting user password via `NTFY_PASSWORD` env variable ([#327](https://github.com/binwiederhier/ntfy/pull/327), thanks to [@Kenix3](https://github.com/Kenix3))
+- Add `cache-startup-queries` option to allow custom [SQLite performance tuning](config.md#wal-for-message-cache) (no ticket)
+- ntfy CLI can now [wait for a command or PID](subscribe/cli.md#wait-for-pidcommand) before publishing ([#263](https://github.com/binwiederhier/ntfy/issues/263), thanks to the [original ntfy](https://github.com/dschep/ntfy) for the idea)
+- Trace: Log entire HTTP request to simplify debugging (no ticket)
+- Allow setting user password via `NTFY_PASSWORD` env variable ([#327](https://github.com/binwiederhier/ntfy/pull/327), thanks to [@Kenix3](https://github.com/Kenix3))
**Bug fixes:**
-* Fix slow requests due to excessive locking ([#338](https://github.com/binwiederhier/ntfy/issues/338))
-* Return HTTP 500 for `GET /_matrix/push/v1/notify` when `base-url` is not configured (no ticket)
-* Disallow setting `upstream-base-url` to the same value as `base-url` ([#334](https://github.com/binwiederhier/ntfy/issues/334), thanks to [@oester](https://github.com/oester) for reporting)
-* Fix `since=` implementation for multiple topics ([#336](https://github.com/binwiederhier/ntfy/issues/336), thanks to [@karmanyaahm](https://github.com/karmanyaahm) for reporting)
-* Simple parsing in `Actions` header now supports settings Android `intent=` key ([#341](https://github.com/binwiederhier/ntfy/pull/341), thanks to [@wunter8](https://github.com/wunter8))
+- Fix slow requests due to excessive locking ([#338](https://github.com/binwiederhier/ntfy/issues/338))
+- Return HTTP 500 for `GET /_matrix/push/v1/notify` when `base-url` is not configured (no ticket)
+- Disallow setting `upstream-base-url` to the same value as `base-url` ([#334](https://github.com/binwiederhier/ntfy/issues/334), thanks to [@oester](https://github.com/oester) for reporting)
+- Fix `since=` implementation for multiple topics ([#336](https://github.com/binwiederhier/ntfy/issues/336), thanks to [@karmanyaahm](https://github.com/karmanyaahm) for reporting)
+- Simple parsing in `Actions` header now supports settings Android `intent=` key ([#341](https://github.com/binwiederhier/ntfy/pull/341), thanks to [@wunter8](https://github.com/wunter8))
**Deprecations:**
-* The `ntfy publish --env-topic` option is deprecated as of now (see [deprecations](deprecations.md) for details)
+- The `ntfy publish --env-topic` option is deprecated as of now (see [deprecations](deprecations.md) for details)
## ntfy server v1.26.0
+
Released June 16, 2022
This release adds a Matrix Push Gateway directly into ntfy, to make self-hosting a Matrix server easier. The Windows
-CLI is now available via Scoop, and ntfy is now natively supported in Uptime Kuma.
+CLI is now available via Scoop, and ntfy is now natively supported in Uptime Kuma.
**Features:**
-* ntfy now is a [Matrix Push Gateway](https://spec.matrix.org/v1.2/push-gateway-api/) (in combination with [UnifiedPush](https://unifiedpush.org) as the [Provider Push Protocol](https://unifiedpush.org/developers/gateway/), [#319](https://github.com/binwiederhier/ntfy/issues/319)/[#326](https://github.com/binwiederhier/ntfy/pull/326), thanks to [@MayeulC](https://github.com/MayeulC) for reporting)
-* Windows CLI is now available via [Scoop](https://scoop.sh) ([ScoopInstaller#3594](https://github.com/ScoopInstaller/Main/pull/3594), [#311](https://github.com/binwiederhier/ntfy/pull/311), [#269](https://github.com/binwiederhier/ntfy/issues/269), thanks to [@kzshantonu](https://github.com/kzshantonu))
-* [Uptime Kuma](https://github.com/louislam/uptime-kuma) now allows publishing to ntfy ([uptime-kuma#1674](https://github.com/louislam/uptime-kuma/pull/1674), thanks to [@philippdormann](https://github.com/philippdormann))
-* Display ntfy version in `ntfy serve` command ([#314](https://github.com/binwiederhier/ntfy/issues/314), thanks to [@poblabs](https://github.com/poblabs))
+- ntfy now is a [Matrix Push Gateway](https://spec.matrix.org/v1.2/push-gateway-api/) (in combination with [UnifiedPush](https://unifiedpush.org) as the [Provider Push Protocol](https://unifiedpush.org/developers/gateway/), [#319](https://github.com/binwiederhier/ntfy/issues/319)/[#326](https://github.com/binwiederhier/ntfy/pull/326), thanks to [@MayeulC](https://github.com/MayeulC) for reporting)
+- Windows CLI is now available via [Scoop](https://scoop.sh) ([ScoopInstaller#3594](https://github.com/ScoopInstaller/Main/pull/3594), [#311](https://github.com/binwiederhier/ntfy/pull/311), [#269](https://github.com/binwiederhier/ntfy/issues/269), thanks to [@kzshantonu](https://github.com/kzshantonu))
+- [Uptime Kuma](https://github.com/louislam/uptime-kuma) now allows publishing to ntfy ([uptime-kuma#1674](https://github.com/louislam/uptime-kuma/pull/1674), thanks to [@philippdormann](https://github.com/philippdormann))
+- Display ntfy version in `ntfy serve` command ([#314](https://github.com/binwiederhier/ntfy/issues/314), thanks to [@poblabs](https://github.com/poblabs))
**Bug fixes:**
-* Web app: Show "notifications not supported" alert on HTTP ([#323](https://github.com/binwiederhier/ntfy/issues/323), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
-* Use last address in `X-Forwarded-For` header as visitor address ([#328](https://github.com/binwiederhier/ntfy/issues/328))
+- Web app: Show "notifications not supported" alert on HTTP ([#323](https://github.com/binwiederhier/ntfy/issues/323), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
+- Use last address in `X-Forwarded-For` header as visitor address ([#328](https://github.com/binwiederhier/ntfy/issues/328))
**Documentation**
-* Added [example](examples.md) for [Uptime Kuma](https://github.com/louislam/uptime-kuma) integration ([#315](https://github.com/binwiederhier/ntfy/pull/315), thanks to [@philippdormann](https://github.com/philippdormann))
-* Fix Docker install instructions ([#320](https://github.com/binwiederhier/ntfy/issues/320), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
-* Add clarifying comments to base-url ([#322](https://github.com/binwiederhier/ntfy/issues/322), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
-* Update FAQ for iOS app ([#321](https://github.com/binwiederhier/ntfy/issues/321), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
+- Added [example](examples.md) for [Uptime Kuma](https://github.com/louislam/uptime-kuma) integration ([#315](https://github.com/binwiederhier/ntfy/pull/315), thanks to [@philippdormann](https://github.com/philippdormann))
+- Fix Docker install instructions ([#320](https://github.com/binwiederhier/ntfy/issues/320), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
+- Add clarifying comments to base-url ([#322](https://github.com/binwiederhier/ntfy/issues/322), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
+- Update FAQ for iOS app ([#321](https://github.com/binwiederhier/ntfy/issues/321), thanks to [@milksteakjellybeans](https://github.com/milksteakjellybeans) for reporting)
## ntfy iOS app v1.2
+
Released June 16, 2022
This release adds support for authentication/authorization for self-hosted servers. It also allows you to
@@ -570,18 +591,19 @@ set your server as the default server for new topics.
**Features:**
-* Support for auth and user management ([#277](https://github.com/binwiederhier/ntfy/issues/277))
-* Ability to add default server ([#295](https://github.com/binwiederhier/ntfy/issues/295))
+- Support for auth and user management ([#277](https://github.com/binwiederhier/ntfy/issues/277))
+- Ability to add default server ([#295](https://github.com/binwiederhier/ntfy/issues/295))
**Bug fixes:**
-* Add validation for selfhosted server URL ([#290](https://github.com/binwiederhier/ntfy/issues/290))
+- Add validation for selfhosted server URL ([#290](https://github.com/binwiederhier/ntfy/issues/290))
## ntfy server v1.25.2
+
Released June 2, 2022
-This release adds the ability to set a log level to facilitate easier debugging of live systems. It also solves a
-production problem with a few over-users that resulted in Firebase quota problems (only applying to the over-users).
+This release adds the ability to set a log level to facilitate easier debugging of live systems. It also solves a
+production problem with a few over-users that resulted in Firebase quota problems (only applying to the over-users).
We now block visitors from using Firebase if they trigger a quota exceeded response.
On top of that, we updated the Firebase SDK and are now building the release in GitHub Actions. We've also got two
@@ -589,32 +611,33 @@ more translations: Chinese/Simplified and Dutch.
**Features:**
-* Advanced logging, with different log levels and hot reloading of the log level ([#284](https://github.com/binwiederhier/ntfy/pull/284))
+- Advanced logging, with different log levels and hot reloading of the log level ([#284](https://github.com/binwiederhier/ntfy/pull/284))
**Bugs**:
-* Respect Firebase "quota exceeded" response for topics, block Firebase publishing for user for 10min ([#289](https://github.com/binwiederhier/ntfy/issues/289))
-* Fix documentation header blue header due to mkdocs-material theme update (no ticket)
+- Respect Firebase "quota exceeded" response for topics, block Firebase publishing for user for 10min ([#289](https://github.com/binwiederhier/ntfy/issues/289))
+- Fix documentation header blue header due to mkdocs-material theme update (no ticket)
**Maintenance:**
-* Upgrade Firebase Admin SDK to 4.x ([#274](https://github.com/binwiederhier/ntfy/issues/274))
-* CI: Build from pipeline instead of locally ([#36](https://github.com/binwiederhier/ntfy/issues/36))
+- Upgrade Firebase Admin SDK to 4.x ([#274](https://github.com/binwiederhier/ntfy/issues/274))
+- CI: Build from pipeline instead of locally ([#36](https://github.com/binwiederhier/ntfy/issues/36))
**Documentation**:
-* ⚠️ [Privacy policy](privacy.md) updated to reflect additional debug/tracing feature (no ticket)
-* [Examples](examples.md) for [Home Assistant](https://www.home-assistant.io/) ([#282](https://github.com/binwiederhier/ntfy/pull/282), thanks to [@poblabs](https://github.com/poblabs))
-* Install instructions for [NixOS/Nix](https://ntfy.sh/docs/install/#nixos-nix) ([#282](https://github.com/binwiederhier/ntfy/pull/282), thanks to [@arjan-s](https://github.com/arjan-s))
-* Clarify `poll_request` wording for [iOS push notifications](https://ntfy.sh/docs/config/#ios-instant-notifications) ([#300](https://github.com/binwiederhier/ntfy/issues/300), thanks to [@prabirshrestha](https://github.com/prabirshrestha) for reporting)
-* Example for using ntfy with docker-compose.yml without root privileges ([#304](https://github.com/binwiederhier/ntfy/pull/304), thanks to [@ksurl](https://github.com/ksurl))
+- ⚠️ [Privacy policy](privacy.md) updated to reflect additional debug/tracing feature (no ticket)
+- [Examples](examples.md) for [Home Assistant](https://www.home-assistant.io/) ([#282](https://github.com/binwiederhier/ntfy/pull/282), thanks to [@poblabs](https://github.com/poblabs))
+- Install instructions for [NixOS/Nix](https://ntfy.sh/docs/install/#nixos-nix) ([#282](https://github.com/binwiederhier/ntfy/pull/282), thanks to [@arjan-s](https://github.com/arjan-s))
+- Clarify `poll_request` wording for [iOS push notifications](https://ntfy.sh/docs/config/#ios-instant-notifications) ([#300](https://github.com/binwiederhier/ntfy/issues/300), thanks to [@prabirshrestha](https://github.com/prabirshrestha) for reporting)
+- Example for using ntfy with docker-compose.yml without root privileges ([#304](https://github.com/binwiederhier/ntfy/pull/304), thanks to [@ksurl](https://github.com/ksurl))
**Additional translations:**
-* Chinese/Simplified (thanks to [@yufei.im](https://hosted.weblate.org/user/yufei.im/))
-* Dutch (thanks to [@SchoNie](https://hosted.weblate.org/user/SchoNie/))
+- Chinese/Simplified (thanks to [@yufei.im](https://hosted.weblate.org/user/yufei.im/))
+- Dutch (thanks to [@SchoNie](https://hosted.weblate.org/user/SchoNie/))
## ntfy iOS app v1.1
+
Released May 31, 2022
In this release of the iOS app, we add message priorities (mapped to iOS interruption levels), tags and emojis,
@@ -627,20 +650,21 @@ for details).
**Features:**
-* [Message priority](https://ntfy.sh/docs/publish/#message-priority) support (no ticket)
-* [Tags/emojis](https://ntfy.sh/docs/publish/#tags-emojis) support (no ticket)
-* [Action buttons](https://ntfy.sh/docs/publish/#action-buttons) support (no ticket)
-* [Click action](https://ntfy.sh/docs/publish/#click-action) support (no ticket)
-* Open topic when notification clicked (no ticket)
-* Notification now makes a sound and vibrates (no ticket)
-* Cancel notifications when navigating to topic (no ticket)
-* iOS 14.0 support (no ticket, [PR#1](https://github.com/binwiederhier/ntfy-ios/pull/1), thanks to [@callum-99](https://github.com/callum-99))
+- [Message priority](https://ntfy.sh/docs/publish/#message-priority) support (no ticket)
+- [Tags/emojis](https://ntfy.sh/docs/publish/#tags-emojis) support (no ticket)
+- [Action buttons](https://ntfy.sh/docs/publish/#action-buttons) support (no ticket)
+- [Click action](https://ntfy.sh/docs/publish/#click-action) support (no ticket)
+- Open topic when notification clicked (no ticket)
+- Notification now makes a sound and vibrates (no ticket)
+- Cancel notifications when navigating to topic (no ticket)
+- iOS 14.0 support (no ticket, [PR#1](https://github.com/binwiederhier/ntfy-ios/pull/1), thanks to [@callum-99](https://github.com/callum-99))
**Bug fixes:**
-* iOS UI not always updating properly ([#267](https://github.com/binwiederhier/ntfy/issues/267))
+- iOS UI not always updating properly ([#267](https://github.com/binwiederhier/ntfy/issues/267))
## ntfy server v1.24.0
+
Released May 28, 2022
This release of the ntfy server brings supporting features for the ntfy iOS app. Most importantly, it
@@ -649,19 +673,20 @@ Apple development environment.
**Features:**
-* Regularly send Firebase keepalive messages to ~poll topic to support self-hosted servers (no ticket)
-* Add subscribe filter to query exact messages by ID (no ticket)
-* Support for `poll_request` messages to support [iOS push notifications](https://ntfy.sh/docs/config/#ios-instant-notifications) for self-hosted servers (no ticket)
+- Regularly send Firebase keepalive messages to ~poll topic to support self-hosted servers (no ticket)
+- Add subscribe filter to query exact messages by ID (no ticket)
+- Support for `poll_request` messages to support [iOS push notifications](https://ntfy.sh/docs/config/#ios-instant-notifications) for self-hosted servers (no ticket)
**Bug fixes:**
-* Support emails without `Content-Type` ([#265](https://github.com/binwiederhier/ntfy/issues/265), thanks to [@dmbonsall](https://github.com/dmbonsall))
+- Support emails without `Content-Type` ([#265](https://github.com/binwiederhier/ntfy/issues/265), thanks to [@dmbonsall](https://github.com/dmbonsall))
**Additional translations:**
-* Italian (thanks to [@Genio2003](https://hosted.weblate.org/user/Genio2003/))
+- Italian (thanks to [@Genio2003](https://hosted.weblate.org/user/Genio2003/))
## ntfy iOS app v1.0
+
Released May 25, 2022
This is the first version of the ntfy iOS app. It supports only ntfy.sh (no selfhosted servers) and only messages + title
@@ -672,43 +697,45 @@ The app is now available in the [App Store](https://apps.apple.com/us/app/ntfy/i
**Tickets:**
-* iOS app ([#4](https://github.com/binwiederhier/ntfy/issues/4), see also: [TestFlight summary](https://github.com/binwiederhier/ntfy/issues/4#issuecomment-1133767150))
+- iOS app ([#4](https://github.com/binwiederhier/ntfy/issues/4), see also: [TestFlight summary](https://github.com/binwiederhier/ntfy/issues/4#issuecomment-1133767150))
**Thanks:**
-* Thank you to all the testers who tried out the app. You guys gave me the confidence that it's ready to release (albeit with
+- Thank you to all the testers who tried out the app. You guys gave me the confidence that it's ready to release (albeit with
some known issues which will be addressed in follow-up releases).
## ntfy server v1.23.0
+
Released May 21, 2022
-This release ships a CLI for Windows and macOS, as well as the ability to disable the web app entirely. On top of that,
+This release ships a CLI for Windows and macOS, as well as the ability to disable the web app entirely. On top of that,
it adds support for APNs, the iOS messaging service. This is needed for the (soon to be released) iOS app.
**Features:**
-* [Windows](https://ntfy.sh/docs/install/#windows) and [macOS](https://ntfy.sh/docs/install/#macos) builds for the [ntfy CLI](https://ntfy.sh/docs/subscribe/cli/) ([#112](https://github.com/binwiederhier/ntfy/issues/112))
-* Ability to disable the web app entirely ([#238](https://github.com/binwiederhier/ntfy/issues/238)/[#249](https://github.com/binwiederhier/ntfy/pull/249), thanks to [@Curid](https://github.com/Curid))
-* Add APNs config to Firebase messages to support [iOS app](https://github.com/binwiederhier/ntfy/issues/4) ([#247](https://github.com/binwiederhier/ntfy/pull/247), thanks to [@Copephobia](https://github.com/Copephobia))
+- [Windows](https://ntfy.sh/docs/install/#windows) and [macOS](https://ntfy.sh/docs/install/#macos) builds for the [ntfy CLI](https://ntfy.sh/docs/subscribe/cli/) ([#112](https://github.com/binwiederhier/ntfy/issues/112))
+- Ability to disable the web app entirely ([#238](https://github.com/binwiederhier/ntfy/issues/238)/[#249](https://github.com/binwiederhier/ntfy/pull/249), thanks to [@Curid](https://github.com/Curid))
+- Add APNs config to Firebase messages to support [iOS app](https://github.com/binwiederhier/ntfy/issues/4) ([#247](https://github.com/binwiederhier/ntfy/pull/247), thanks to [@Copephobia](https://github.com/Copephobia))
**Bug fixes:**
-* Support underscores in server.yml config options ([#255](https://github.com/binwiederhier/ntfy/issues/255), thanks to [@ajdelgado](https://github.com/ajdelgado))
-* Force MAKEFLAGS to --jobs=1 in `Makefile` ([#257](https://github.com/binwiederhier/ntfy/pull/257), thanks to [@oddlama](https://github.com/oddlama))
+- Support underscores in server.yml config options ([#255](https://github.com/binwiederhier/ntfy/issues/255), thanks to [@ajdelgado](https://github.com/ajdelgado))
+- Force MAKEFLAGS to --jobs=1 in `Makefile` ([#257](https://github.com/binwiederhier/ntfy/pull/257), thanks to [@oddlama](https://github.com/oddlama))
**Documentation:**
-* Typo in install instructions ([#252](https://github.com/binwiederhier/ntfy/pull/252)/[#251](https://github.com/binwiederhier/ntfy/issues/251), thanks to [@oddlama](https://github.com/oddlama))
-* Fix typo in private server example ([#262](https://github.com/binwiederhier/ntfy/pull/262), thanks to [@MayeulC](https://github.com/MayeulC))
-* [Examples](examples.md) for [jellyseerr](https://github.com/Fallenbagel/jellyseerr)/[overseerr](https://overseerr.dev/) ([#264](https://github.com/binwiederhier/ntfy/pull/264), thanks to [@Fallenbagel](https://github.com/Fallenbagel))
+- Typo in install instructions ([#252](https://github.com/binwiederhier/ntfy/pull/252)/[#251](https://github.com/binwiederhier/ntfy/issues/251), thanks to [@oddlama](https://github.com/oddlama))
+- Fix typo in private server example ([#262](https://github.com/binwiederhier/ntfy/pull/262), thanks to [@MayeulC](https://github.com/MayeulC))
+- [Examples](examples.md) for [jellyseerr](https://github.com/Fallenbagel/jellyseerr)/[overseerr](https://overseerr.dev/) ([#264](https://github.com/binwiederhier/ntfy/pull/264), thanks to [@Fallenbagel](https://github.com/Fallenbagel))
**Additional translations:**
-* Portuguese/Brazil (thanks to [@tiagotriques](https://hosted.weblate.org/user/tiagotriques/) and [@pireshenrique22](https://hosted.weblate.org/user/pireshenrique22/))
+- Portuguese/Brazil (thanks to [@tiagotriques](https://hosted.weblate.org/user/tiagotriques/) and [@pireshenrique22](https://hosted.weblate.org/user/pireshenrique22/))
-Thank you to the many translators, who helped translate the new strings so quickly. I am humbled and amazed by your help.
+Thank you to the many translators, who helped translate the new strings so quickly. I am humbled and amazed by your help.
## ntfy Android app v1.13.0
+
Released May 11, 2022
This release brings a slightly altered design for the detail view, featuring a card layout to make notifications more easily
@@ -717,22 +744,22 @@ and custom icons. Aside from that, we've got tons of bug fixes as usual.
**Features:**
-* Per-subscription settings, custom subscription icons ([#155](https://github.com/binwiederhier/ntfy/issues/155), thanks to [@mztiq](https://github.com/mztiq) for reporting)
-* Cards in notification detail view ([#175](https://github.com/binwiederhier/ntfy/issues/175), thanks to [@cmeis](https://github.com/cmeis) for reporting)
+- Per-subscription settings, custom subscription icons ([#155](https://github.com/binwiederhier/ntfy/issues/155), thanks to [@mztiq](https://github.com/mztiq) for reporting)
+- Cards in notification detail view ([#175](https://github.com/binwiederhier/ntfy/issues/175), thanks to [@cmeis](https://github.com/cmeis) for reporting)
**Bug fixes:**
-* Accurate naming of "mute notifications" from "pause notifications" ([#224](https://github.com/binwiederhier/ntfy/issues/224), thanks to [@shadow00](https://github.com/shadow00) for reporting)
-* Make messages with links selectable ([#226](https://github.com/binwiederhier/ntfy/issues/226), thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov) for reporting)
-* Restoring topics or settings from backup doesn't work ([#223](https://github.com/binwiederhier/ntfy/issues/223), thanks to [@shadow00](https://github.com/shadow00) for reporting)
-* Fix app icon on old Android versions ([#128](https://github.com/binwiederhier/ntfy/issues/128), thanks to [@shadow00](https://github.com/shadow00) for reporting)
-* Fix races in UnifiedPush registration ([#230](https://github.com/binwiederhier/ntfy/issues/230), thanks to @Jakob for reporting)
-* Prevent view action from crashing the app ([#233](https://github.com/binwiederhier/ntfy/issues/233))
-* Prevent long topic names and icons from overlapping ([#240](https://github.com/binwiederhier/ntfy/issues/240), thanks to [@cmeis](https://github.com/cmeis) for reporting)
+- Accurate naming of "mute notifications" from "pause notifications" ([#224](https://github.com/binwiederhier/ntfy/issues/224), thanks to [@shadow00](https://github.com/shadow00) for reporting)
+- Make messages with links selectable ([#226](https://github.com/binwiederhier/ntfy/issues/226), thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov) for reporting)
+- Restoring topics or settings from backup doesn't work ([#223](https://github.com/binwiederhier/ntfy/issues/223), thanks to [@shadow00](https://github.com/shadow00) for reporting)
+- Fix app icon on old Android versions ([#128](https://github.com/binwiederhier/ntfy/issues/128), thanks to [@shadow00](https://github.com/shadow00) for reporting)
+- Fix races in UnifiedPush registration ([#230](https://github.com/binwiederhier/ntfy/issues/230), thanks to @Jakob for reporting)
+- Prevent view action from crashing the app ([#233](https://github.com/binwiederhier/ntfy/issues/233))
+- Prevent long topic names and icons from overlapping ([#240](https://github.com/binwiederhier/ntfy/issues/240), thanks to [@cmeis](https://github.com/cmeis) for reporting)
**Additional translations:**
-* Dutch (*incomplete*, thanks to [@diony](https://hosted.weblate.org/user/diony/))
+- Dutch (_incomplete_, thanks to [@diony](https://hosted.weblate.org/user/diony/))
**Thank you:**
@@ -740,6 +767,7 @@ Thanks to [@cmeis](https://github.com/cmeis), [@StoyanDimitrov](https://github.c
to [@Joeharrison94](https://github.com/Joeharrison94) for the input. And thank you very much to all the translators for catching up so quickly.
## ntfy server v1.22.0
+
Released May 7, 2022
This release makes the web app more accessible to people with disabilities, and introduces a "mark as read" icon in the web app.
@@ -749,72 +777,73 @@ We've also improved the documentation a little and added translations for three
**Features:**
-* Make web app more accessible ([#217](https://github.com/binwiederhier/ntfy/issues/217))
-* Better parsing of the user actions, allowing quotes (no ticket)
-* Add "mark as read" icon button to notification ([#243](https://github.com/binwiederhier/ntfy/pull/243), thanks to [@wunter8](https://github.com/wunter8))
+- Make web app more accessible ([#217](https://github.com/binwiederhier/ntfy/issues/217))
+- Better parsing of the user actions, allowing quotes (no ticket)
+- Add "mark as read" icon button to notification ([#243](https://github.com/binwiederhier/ntfy/pull/243), thanks to [@wunter8](https://github.com/wunter8))
**Bug fixes:**
-* `Upgrade` header check is now case in-sensitive ([#228](https://github.com/binwiederhier/ntfy/issues/228), thanks to [@wunter8](https://github.com/wunter8) for finding it)
-* Made web app sounds quieter ([#222](https://github.com/binwiederhier/ntfy/issues/222))
-* Add "private browsing"-specific error message for Firefox/Safari ([#208](https://github.com/binwiederhier/ntfy/issues/208), thanks to [@julianfoad](https://github.com/julianfoad) for reporting)
+- `Upgrade` header check is now case in-sensitive ([#228](https://github.com/binwiederhier/ntfy/issues/228), thanks to [@wunter8](https://github.com/wunter8) for finding it)
+- Made web app sounds quieter ([#222](https://github.com/binwiederhier/ntfy/issues/222))
+- Add "private browsing"-specific error message for Firefox/Safari ([#208](https://github.com/binwiederhier/ntfy/issues/208), thanks to [@julianfoad](https://github.com/julianfoad) for reporting)
**Documentation:**
-* Improved caddy configuration (no ticket, thanks to @Stnby)
-* Additional multi-line examples on the [publish page](https://ntfy.sh/docs/publish/) ([#234](https://github.com/binwiederhier/ntfy/pull/234), thanks to [@aTable](https://github.com/aTable))
-* Fixed PowerShell auth example to use UTF-8 ([#242](https://github.com/binwiederhier/ntfy/pull/242), thanks to [@SMAW](https://github.com/SMAW))
+- Improved caddy configuration (no ticket, thanks to @Stnby)
+- Additional multi-line examples on the [publish page](https://ntfy.sh/docs/publish/) ([#234](https://github.com/binwiederhier/ntfy/pull/234), thanks to [@aTable](https://github.com/aTable))
+- Fixed PowerShell auth example to use UTF-8 ([#242](https://github.com/binwiederhier/ntfy/pull/242), thanks to [@SMAW](https://github.com/SMAW))
**Additional translations:**
-* Czech (thanks to [@waclaw66](https://hosted.weblate.org/user/waclaw66/))
-* French (thanks to [@nathanaelhoun](https://hosted.weblate.org/user/nathanaelhoun/))
-* Hungarian (thanks to [@agocsdaniel](https://hosted.weblate.org/user/agocsdaniel/))
+- Czech (thanks to [@waclaw66](https://hosted.weblate.org/user/waclaw66/))
+- French (thanks to [@nathanaelhoun](https://hosted.weblate.org/user/nathanaelhoun/))
+- Hungarian (thanks to [@agocsdaniel](https://hosted.weblate.org/user/agocsdaniel/))
**Thanks for testing:**
Thanks to [@wunter8](https://github.com/wunter8) for testing.
## ntfy Android app v1.12.0
+
Released Apr 25, 2022
The main feature in this Android release is [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons), a feature
that allows users to add actions to the notifications. Actions can be to view a website or app, send a broadcast, or
-send a HTTP request.
+send a HTTP request.
-We also added support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links), added three more
-languages and fixed a ton of bugs.
+We also added support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links), added three more
+languages and fixed a ton of bugs.
**Features:**
-* Custom notification [action buttons](https://ntfy.sh/docs/publish/#action-buttons) ([#134](https://github.com/binwiederhier/ntfy/issues/134),
+- Custom notification [action buttons](https://ntfy.sh/docs/publish/#action-buttons) ([#134](https://github.com/binwiederhier/ntfy/issues/134),
thanks to [@mrherman](https://github.com/mrherman) for reporting)
-* Support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links) ([#20](https://github.com/binwiederhier/ntfy/issues/20), thanks
+- Support for [ntfy:// deep links](https://ntfy.sh/docs/subscribe/phone/#ntfy-links) ([#20](https://github.com/binwiederhier/ntfy/issues/20), thanks
to [@Copephobia](https://github.com/Copephobia) for reporting)
-* [Fastlane metadata](https://hosted.weblate.org/projects/ntfy/android-fastlane/) can now be translated too ([#198](https://github.com/binwiederhier/ntfy/issues/198),
+- [Fastlane metadata](https://hosted.weblate.org/projects/ntfy/android-fastlane/) can now be translated too ([#198](https://github.com/binwiederhier/ntfy/issues/198),
thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov) for reporting)
-* Channel settings option to configure DND override, sounds, etc. ([#91](https://github.com/binwiederhier/ntfy/issues/91))
+- Channel settings option to configure DND override, sounds, etc. ([#91](https://github.com/binwiederhier/ntfy/issues/91))
**Bug fixes:**
-* Validate URLs when changing default server and server in user management ([#193](https://github.com/binwiederhier/ntfy/issues/193),
+- Validate URLs when changing default server and server in user management ([#193](https://github.com/binwiederhier/ntfy/issues/193),
thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov) for reporting)
-* Error in sending test notification in different languages ([#209](https://github.com/binwiederhier/ntfy/issues/209),
+- Error in sending test notification in different languages ([#209](https://github.com/binwiederhier/ntfy/issues/209),
thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov) for reporting)
-* "[x] Instant delivery in doze mode" checkbox does not work properly ([#211](https://github.com/binwiederhier/ntfy/issues/211))
-* Disallow "http" GET/HEAD actions with body ([#221](https://github.com/binwiederhier/ntfy/issues/221), thanks to
+- "[x] Instant delivery in doze mode" checkbox does not work properly ([#211](https://github.com/binwiederhier/ntfy/issues/211))
+- Disallow "http" GET/HEAD actions with body ([#221](https://github.com/binwiederhier/ntfy/issues/221), thanks to
[@cmeis](https://github.com/cmeis) for reporting)
-* Action "view" with "clear=true" does not work on some phones ([#220](https://github.com/binwiederhier/ntfy/issues/220), thanks to
+- Action "view" with "clear=true" does not work on some phones ([#220](https://github.com/binwiederhier/ntfy/issues/220), thanks to
[@cmeis](https://github.com/cmeis) for reporting)
-* Do not group foreground service notification with others ([#219](https://github.com/binwiederhier/ntfy/issues/219), thanks to
+- Do not group foreground service notification with others ([#219](https://github.com/binwiederhier/ntfy/issues/219), thanks to
[@s-h-a-r-d](https://github.com/s-h-a-r-d) for reporting)
**Additional translations:**
-* Czech (thanks to [@waclaw66](https://hosted.weblate.org/user/waclaw66/))
-* French (thanks to [@nathanaelhoun](https://hosted.weblate.org/user/nathanaelhoun/))
-* Japanese (thanks to [@shak](https://hosted.weblate.org/user/shak/))
-* Russian (thanks to [@flamey](https://hosted.weblate.org/user/flamey/) and [@ilya.mikheev.coder](https://hosted.weblate.org/user/ilya.mikheev.coder/))
+- Czech (thanks to [@waclaw66](https://hosted.weblate.org/user/waclaw66/))
+- French (thanks to [@nathanaelhoun](https://hosted.weblate.org/user/nathanaelhoun/))
+- Japanese (thanks to [@shak](https://hosted.weblate.org/user/shak/))
+- Russian (thanks to [@flamey](https://hosted.weblate.org/user/flamey/) and [@ilya.mikheev.coder](https://hosted.weblate.org/user/ilya.mikheev.coder/))
**Thanks for testing:**
@@ -822,43 +851,44 @@ Thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d) (aka @Shard), [@cmeis](http
@poblabs, and everyone I forgot for testing.
## ntfy server v1.21.2
+
Released Apr 24, 2022
-In this release, the web app got translation support and was translated into 9 languages already 🇧🇬 🇩🇪 🇺🇸 🌎.
+In this release, the web app got translation support and was translated into 9 languages already 🇧🇬 🇩🇪 🇺🇸 🌎.
It also re-adds support for ARMv6, and adds server-side support for Action Buttons. [Action Buttons](https://ntfy.sh/docs/publish/#action-buttons)
-is a feature that will be released in the Android app soon. It allows users to add actions to the notifications.
+is a feature that will be released in the Android app soon. It allows users to add actions to the notifications.
Limited support is available in the web app.
**Features:**
-* Custom notification [action buttons](https://ntfy.sh/docs/publish/#action-buttons) ([#134](https://github.com/binwiederhier/ntfy/issues/134),
+- Custom notification [action buttons](https://ntfy.sh/docs/publish/#action-buttons) ([#134](https://github.com/binwiederhier/ntfy/issues/134),
thanks to [@mrherman](https://github.com/mrherman) for reporting)
-* Added ARMv6 build ([#200](https://github.com/binwiederhier/ntfy/issues/200), thanks to [@jcrubioa](https://github.com/jcrubioa) for reporting)
-* Web app internationalization support 🇧🇬 🇩🇪 🇺🇸 🌎 ([#189](https://github.com/binwiederhier/ntfy/issues/189))
+- Added ARMv6 build ([#200](https://github.com/binwiederhier/ntfy/issues/200), thanks to [@jcrubioa](https://github.com/jcrubioa) for reporting)
+- Web app internationalization support 🇧🇬 🇩🇪 🇺🇸 🌎 ([#189](https://github.com/binwiederhier/ntfy/issues/189))
**Bug fixes:**
-* Web app: English language strings fixes, additional descriptions for settings ([#203](https://github.com/binwiederhier/ntfy/issues/203), thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
-* Web app: Show error message snackbar when sending test notification fails ([#205](https://github.com/binwiederhier/ntfy/issues/205), thanks to [@cmeis](https://github.com/cmeis))
-* Web app: basic URL validation in user management ([#204](https://github.com/binwiederhier/ntfy/issues/204), thanks to [@cmeis](https://github.com/cmeis))
-* Disallow "http" GET/HEAD actions with body ([#221](https://github.com/binwiederhier/ntfy/issues/221), thanks to
+- Web app: English language strings fixes, additional descriptions for settings ([#203](https://github.com/binwiederhier/ntfy/issues/203), thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
+- Web app: Show error message snackbar when sending test notification fails ([#205](https://github.com/binwiederhier/ntfy/issues/205), thanks to [@cmeis](https://github.com/cmeis))
+- Web app: basic URL validation in user management ([#204](https://github.com/binwiederhier/ntfy/issues/204), thanks to [@cmeis](https://github.com/cmeis))
+- Disallow "http" GET/HEAD actions with body ([#221](https://github.com/binwiederhier/ntfy/issues/221), thanks to
[@cmeis](https://github.com/cmeis) for reporting)
**Translations (web app):**
-* Bulgarian (thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
-* German (thanks to [@cmeis](https://github.com/cmeis))
-* Indonesian (thanks to [@linerly](https://hosted.weblate.org/user/linerly/))
-* Japanese (thanks to [@shak](https://hosted.weblate.org/user/shak/))
-* Norwegian Bokmål (thanks to [@comradekingu](https://github.com/comradekingu))
-* Russian (thanks to [@flamey](https://hosted.weblate.org/user/flamey/) and [@ilya.mikheev.coder](https://hosted.weblate.org/user/ilya.mikheev.coder/))
-* Spanish (thanks to [@rogeliodh](https://github.com/rogeliodh))
-* Turkish (thanks to [@ersen](https://ersen.moe/))
+- Bulgarian (thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
+- German (thanks to [@cmeis](https://github.com/cmeis))
+- Indonesian (thanks to [@linerly](https://hosted.weblate.org/user/linerly/))
+- Japanese (thanks to [@shak](https://hosted.weblate.org/user/shak/))
+- Norwegian Bokmål (thanks to [@comradekingu](https://github.com/comradekingu))
+- Russian (thanks to [@flamey](https://hosted.weblate.org/user/flamey/) and [@ilya.mikheev.coder](https://hosted.weblate.org/user/ilya.mikheev.coder/))
+- Spanish (thanks to [@rogeliodh](https://github.com/rogeliodh))
+- Turkish (thanks to [@ersen](https://ersen.moe/))
**Integrations:**
[Apprise](https://github.com/caronc/apprise) support was fully released in [v0.9.8.2](https://github.com/caronc/apprise/releases/tag/v0.9.8.2)
-of Apprise. Thanks to [@particledecay](https://github.com/particledecay) and [@caronc](https://github.com/caronc) for their fantastic work.
+of Apprise. Thanks to [@particledecay](https://github.com/particledecay) and [@caronc](https://github.com/caronc) for their fantastic work.
You can try it yourself like this (detailed usage in the [Apprise wiki](https://github.com/caronc/apprise/wiki/Notify_ntfy)):
```
@@ -867,338 +897,361 @@ apprise -b "Hi there" ntfys://mytopic
```
## ntfy Android app v1.11.0
+
Released Apr 7, 2022
**Features:**
-* Download attachments to cache folder ([#181](https://github.com/binwiederhier/ntfy/issues/181))
-* Regularly delete attachments for deleted notifications ([#142](https://github.com/binwiederhier/ntfy/issues/142))
-* Translations to different languages ([#188](https://github.com/binwiederhier/ntfy/issues/188), thanks to
+- Download attachments to cache folder ([#181](https://github.com/binwiederhier/ntfy/issues/181))
+- Regularly delete attachments for deleted notifications ([#142](https://github.com/binwiederhier/ntfy/issues/142))
+- Translations to different languages ([#188](https://github.com/binwiederhier/ntfy/issues/188), thanks to
[@StoyanDimitrov](https://github.com/StoyanDimitrov) for initiating things)
**Bug fixes:**
-* IllegalStateException: Failed to build unique file ([#177](https://github.com/binwiederhier/ntfy/issues/177), thanks to [@Fallenbagel](https://github.com/Fallenbagel) for reporting)
-* SQLiteConstraintException: Crash during UP registration ([#185](https://github.com/binwiederhier/ntfy/issues/185))
-* Refresh preferences screen after settings import (#183, thanks to [@cmeis](https://github.com/cmeis) for reporting)
-* Add priority strings to strings.xml to make it translatable (#192, thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
+- IllegalStateException: Failed to build unique file ([#177](https://github.com/binwiederhier/ntfy/issues/177), thanks to [@Fallenbagel](https://github.com/Fallenbagel) for reporting)
+- SQLiteConstraintException: Crash during UP registration ([#185](https://github.com/binwiederhier/ntfy/issues/185))
+- Refresh preferences screen after settings import (#183, thanks to [@cmeis](https://github.com/cmeis) for reporting)
+- Add priority strings to strings.xml to make it translatable (#192, thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
**Translations:**
-* English language improvements (thanks to [@comradekingu](https://github.com/comradekingu))
-* Bulgarian (thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
-* Chinese/Simplified (thanks to [@poi](https://hosted.weblate.org/user/poi) and [@PeterCxy](https://hosted.weblate.org/user/PeterCxy))
-* Dutch (*incomplete*, thanks to [@diony](https://hosted.weblate.org/user/diony))
-* French (thanks to [@Kusoneko](https://kusoneko.moe/) and [@mlcsthor](https://hosted.weblate.org/user/mlcsthor/))
-* German (thanks to [@cmeis](https://github.com/cmeis))
-* Italian (thanks to [@theTranslator](https://hosted.weblate.org/user/theTranslator/))
-* Indonesian (thanks to [@linerly](https://hosted.weblate.org/user/linerly/))
-* Norwegian Bokmål (*incomplete*, thanks to [@comradekingu](https://github.com/comradekingu))
-* Portuguese/Brazil (thanks to [@LW](https://hosted.weblate.org/user/LW/))
-* Spanish (thanks to [@rogeliodh](https://github.com/rogeliodh))
-* Turkish (thanks to [@ersen](https://ersen.moe/))
+- English language improvements (thanks to [@comradekingu](https://github.com/comradekingu))
+- Bulgarian (thanks to [@StoyanDimitrov](https://github.com/StoyanDimitrov))
+- Chinese/Simplified (thanks to [@poi](https://hosted.weblate.org/user/poi) and [@PeterCxy](https://hosted.weblate.org/user/PeterCxy))
+- Dutch (_incomplete_, thanks to [@diony](https://hosted.weblate.org/user/diony))
+- French (thanks to [@Kusoneko](https://kusoneko.moe/) and [@mlcsthor](https://hosted.weblate.org/user/mlcsthor/))
+- German (thanks to [@cmeis](https://github.com/cmeis))
+- Italian (thanks to [@theTranslator](https://hosted.weblate.org/user/theTranslator/))
+- Indonesian (thanks to [@linerly](https://hosted.weblate.org/user/linerly/))
+- Norwegian Bokmål (_incomplete_, thanks to [@comradekingu](https://github.com/comradekingu))
+- Portuguese/Brazil (thanks to [@LW](https://hosted.weblate.org/user/LW/))
+- Spanish (thanks to [@rogeliodh](https://github.com/rogeliodh))
+- Turkish (thanks to [@ersen](https://ersen.moe/))
**Thanks:**
-* Many thanks to [@cmeis](https://github.com/cmeis), [@Fallenbagel](https://github.com/Fallenbagel), [@Joeharrison94](https://github.com/Joeharrison94),
+- Many thanks to [@cmeis](https://github.com/cmeis), [@Fallenbagel](https://github.com/Fallenbagel), [@Joeharrison94](https://github.com/Joeharrison94),
and [@rogeliodh](https://github.com/rogeliodh) for input on the new attachment logic, and for testing the release
## ntfy server v1.20.0
+
Released Apr 6, 2022
**Features:**:
-* Added message bar and publish dialog ([#196](https://github.com/binwiederhier/ntfy/issues/196))
+- Added message bar and publish dialog ([#196](https://github.com/binwiederhier/ntfy/issues/196))
**Bug fixes:**
-* Added `EXPOSE 80/tcp` to Dockerfile to support auto-discovery in [Traefik](https://traefik.io/) ([#195](https://github.com/binwiederhier/ntfy/issues/195), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d))
+- Added `EXPOSE 80/tcp` to Dockerfile to support auto-discovery in [Traefik](https://traefik.io/) ([#195](https://github.com/binwiederhier/ntfy/issues/195), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d))
**Documentation:**
-* Added docker-compose example to [install instructions](install.md#docker) ([#194](https://github.com/binwiederhier/ntfy/pull/194), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d))
+- Added docker-compose example to [install instructions](install.md#docker) ([#194](https://github.com/binwiederhier/ntfy/pull/194), thanks to [@s-h-a-r-d](https://github.com/s-h-a-r-d))
**Integrations:**
-* [Apprise](https://github.com/caronc/apprise) has added integration into ntfy ([#99](https://github.com/binwiederhier/ntfy/issues/99), [apprise#524](https://github.com/caronc/apprise/pull/524),
+- [Apprise](https://github.com/caronc/apprise) has added integration into ntfy ([#99](https://github.com/binwiederhier/ntfy/issues/99), [apprise#524](https://github.com/caronc/apprise/pull/524),
thanks to [@particledecay](https://github.com/particledecay) and [@caronc](https://github.com/caronc) for their fantastic work)
## ntfy server v1.19.0
+
Released Mar 30, 2022
**Bug fixes:**
-* Do not pack binary with `upx` for armv7/arm64 due to `illegal instruction` errors ([#191](https://github.com/binwiederhier/ntfy/issues/191), thanks to [@iexos](https://github.com/iexos))
-* Do not allow comma in topic name in publish via GET endpoint (no ticket)
-* Add "Access-Control-Allow-Origin: *" for attachments (no ticket, thanks to @FrameXX)
-* Make pruning run again in web app ([#186](https://github.com/binwiederhier/ntfy/issues/186))
-* Added missing params `delay` and `email` to publish as JSON body (no ticket)
+- Do not pack binary with `upx` for armv7/arm64 due to `illegal instruction` errors ([#191](https://github.com/binwiederhier/ntfy/issues/191), thanks to [@iexos](https://github.com/iexos))
+- Do not allow comma in topic name in publish via GET endpoint (no ticket)
+- Add "Access-Control-Allow-Origin: \*" for attachments (no ticket, thanks to @FrameXX)
+- Make pruning run again in web app ([#186](https://github.com/binwiederhier/ntfy/issues/186))
+- Added missing params `delay` and `email` to publish as JSON body (no ticket)
**Documentation:**
-* Improved [e-mail publishing](config.md#e-mail-publishing) documentation
+- Improved [e-mail publishing](config.md#e-mail-publishing) documentation
## ntfy server v1.18.1
-Released Mar 21, 2022
+
+Released Mar 21, 2022
_This release ships no features or bug fixes. It's merely a documentation update._
**Documentation:**
-* Overhaul of [developer documentation](https://ntfy.sh/docs/develop/)
-* PowerShell examples for [publish documentation](https://ntfy.sh/docs/publish/) ([#138](https://github.com/binwiederhier/ntfy/issues/138), thanks to [@Joeharrison94](https://github.com/Joeharrison94))
-* Additional examples for [NodeRED, Gatus, Sonarr, Radarr, ...](https://ntfy.sh/docs/examples/) (thanks to [@nickexyz](https://github.com/nickexyz))
-* Fixes in developer instructions (thanks to [@Fallenbagel](https://github.com/Fallenbagel) for reporting)
+- Overhaul of [developer documentation](https://ntfy.sh/docs/develop/)
+- PowerShell examples for [publish documentation](https://ntfy.sh/docs/publish/) ([#138](https://github.com/binwiederhier/ntfy/issues/138), thanks to [@Joeharrison94](https://github.com/Joeharrison94))
+- Additional examples for [NodeRED, Gatus, Sonarr, Radarr, ...](https://ntfy.sh/docs/examples/) (thanks to [@nickexyz](https://github.com/nickexyz))
+- Fixes in developer instructions (thanks to [@Fallenbagel](https://github.com/Fallenbagel) for reporting)
## ntfy Android app v1.10.0
+
Released Mar 21, 2022
**Features:**
-* Support for UnifiedPush 2.0 specification (bytes messages, [#130](https://github.com/binwiederhier/ntfy/issues/130))
-* Export/import settings and subscriptions ([#115](https://github.com/binwiederhier/ntfy/issues/115), thanks [@cmeis](https://github.com/cmeis) for reporting)
-* Open "Click" link when tapping notification ([#110](https://github.com/binwiederhier/ntfy/issues/110), thanks [@cmeis](https://github.com/cmeis) for reporting)
-* JSON stream deprecation banner ([#164](https://github.com/binwiederhier/ntfy/issues/164))
+- Support for UnifiedPush 2.0 specification (bytes messages, [#130](https://github.com/binwiederhier/ntfy/issues/130))
+- Export/import settings and subscriptions ([#115](https://github.com/binwiederhier/ntfy/issues/115), thanks [@cmeis](https://github.com/cmeis) for reporting)
+- Open "Click" link when tapping notification ([#110](https://github.com/binwiederhier/ntfy/issues/110), thanks [@cmeis](https://github.com/cmeis) for reporting)
+- JSON stream deprecation banner ([#164](https://github.com/binwiederhier/ntfy/issues/164))
**Bug fixes:**
-* Display locale-specific times, with AM/PM or 24h format ([#140](https://github.com/binwiederhier/ntfy/issues/140), thanks [@hl2guide](https://github.com/hl2guide) for reporting)
+- Display locale-specific times, with AM/PM or 24h format ([#140](https://github.com/binwiederhier/ntfy/issues/140), thanks [@hl2guide](https://github.com/hl2guide) for reporting)
## ntfy server v1.18.0
+
Released Mar 16, 2022
**Features:**
-* [Publish messages as JSON](https://ntfy.sh/docs/publish/#publish-as-json) ([#133](https://github.com/binwiederhier/ntfy/issues/133),
- thanks [@cmeis](https://github.com/cmeis) for reporting, thanks to [@Joeharrison94](https://github.com/Joeharrison94) and
+- [Publish messages as JSON](https://ntfy.sh/docs/publish/#publish-as-json) ([#133](https://github.com/binwiederhier/ntfy/issues/133),
+ thanks [@cmeis](https://github.com/cmeis) for reporting, thanks to [@Joeharrison94](https://github.com/Joeharrison94) and
[@Fallenbagel](https://github.com/Fallenbagel) for testing)
**Bug fixes:**
-* rpm: do not overwrite server.yaml on package upgrade ([#166](https://github.com/binwiederhier/ntfy/issues/166), thanks [@waclaw66](https://github.com/waclaw66) for reporting)
-* Typo in [ntfy.sh/announcements](https://ntfy.sh/announcements) topic ([#170](https://github.com/binwiederhier/ntfy/pull/170), thanks to [@sandebert](https://github.com/sandebert))
-* Readme image URL fixes ([#156](https://github.com/binwiederhier/ntfy/pull/156), thanks to [@ChaseCares](https://github.com/ChaseCares))
+- rpm: do not overwrite server.yaml on package upgrade ([#166](https://github.com/binwiederhier/ntfy/issues/166), thanks [@waclaw66](https://github.com/waclaw66) for reporting)
+- Typo in [ntfy.sh/announcements](https://ntfy.sh/announcements) topic ([#170](https://github.com/binwiederhier/ntfy/pull/170), thanks to [@sandebert](https://github.com/sandebert))
+- Readme image URL fixes ([#156](https://github.com/binwiederhier/ntfy/pull/156), thanks to [@ChaseCares](https://github.com/ChaseCares))
**Deprecations:**
-* Removed the ability to run server as `ntfy` (as opposed to `ntfy serve`) as per [deprecation](deprecations.md)
+- Removed the ability to run server as `ntfy` (as opposed to `ntfy serve`) as per [deprecation](deprecations.md)
## ntfy server v1.17.1
+
Released Mar 12, 2022
**Bug fixes:**
-* Replace `crypto.subtle` with `hashCode` to errors with Brave/FF-Windows (#157, thanks for reporting @arminus)
+- Replace `crypto.subtle` with `hashCode` to errors with Brave/FF-Windows (#157, thanks for reporting @arminus)
## ntfy server v1.17.0
+
Released Mar 11, 2022
**Features & bug fixes:**
-* Replace [web app](https://ntfy.sh/app) with a React/MUI-based web app from the 21st century (#111)
-* Web UI broken with auth (#132, thanks for reporting @arminus)
-* Send static web resources as `Content-Encoding: gzip`, i.e. docs and web app (no ticket)
-* Add support for auth via `?auth=...` query param, used by WebSocket in web app (no ticket)
+- Replace [web app](https://ntfy.sh/app) with a React/MUI-based web app from the 21st century (#111)
+- Web UI broken with auth (#132, thanks for reporting @arminus)
+- Send static web resources as `Content-Encoding: gzip`, i.e. docs and web app (no ticket)
+- Add support for auth via `?auth=...` query param, used by WebSocket in web app (no ticket)
## ntfy server v1.16.0
+
Released Feb 27, 2022
**Features & Bug fixes:**
-* Add [auth support](https://ntfy.sh/docs/subscribe/cli/#authentication) for subscribing with CLI (#147/#148, thanks @lrabane)
-* Add support for [?since=](https://ntfy.sh/docs/subscribe/api/#fetch-cached-messages) (#151, thanks for reporting @nachotp)
+- Add [auth support](https://ntfy.sh/docs/subscribe/cli/#authentication) for subscribing with CLI (#147/#148, thanks @lrabane)
+- Add support for [?since=](https://ntfy.sh/docs/subscribe/api/#fetch-cached-messages) (#151, thanks for reporting @nachotp)
**Documentation:**
-* Add [watchtower/shoutrr examples](https://ntfy.sh/docs/examples/#watchtower-notifications-shoutrrr) (#150, thanks @rogeliodh)
-* Add [release notes](https://ntfy.sh/docs/releases/)
+- Add [watchtower/shoutrr examples](https://ntfy.sh/docs/examples/#watchtower-notifications-shoutrrr) (#150, thanks @rogeliodh)
+- Add [release notes](https://ntfy.sh/docs/releases/)
**Technical notes:**
-* As of this release, message IDs will be 12 characters long (as opposed to 10 characters). This is to be able to
+- As of this release, message IDs will be 12 characters long (as opposed to 10 characters). This is to be able to
distinguish them from Unix timestamps for #151.
## ntfy Android app v1.9.1
+
Released Feb 16, 2022
**Features:**
-* Share to topic feature (#131, thanks u/emptymatrix for reporting)
-* Ability to pick a default server (#127, thanks to @poblabs for reporting and testing)
-* Automatically delete notifications (#71, thanks @arjan-s for reporting)
-* Dark theme: Improvements around style and contrast (#119, thanks @kzshantonu for reporting)
+- Share to topic feature (#131, thanks u/emptymatrix for reporting)
+- Ability to pick a default server (#127, thanks to @poblabs for reporting and testing)
+- Automatically delete notifications (#71, thanks @arjan-s for reporting)
+- Dark theme: Improvements around style and contrast (#119, thanks @kzshantonu for reporting)
**Bug fixes:**
-* Do not attempt to download attachments if they are already expired (#135)
-* Fixed crash in AddFragment as seen per stack trace in Play Console (no ticket)
+- Do not attempt to download attachments if they are already expired (#135)
+- Fixed crash in AddFragment as seen per stack trace in Play Console (no ticket)
**Other thanks:**
-* Thanks to @rogeliodh, @cmeis and @poblabs for testing
+- Thanks to @rogeliodh, @cmeis and @poblabs for testing
## ntfy server v1.15.0
+
Released Feb 14, 2022
**Features & bug fixes:**
-* Compress binaries with `upx` (#137)
-* Add `visitor-request-limit-exempt-hosts` to exempt friendly hosts from rate limits (#144)
-* Double default requests per second limit from 1 per 10s to 1 per 5s (no ticket)
-* Convert `\n` to new line for `X-Message` header as prep for sharing feature (see #136)
-* Reduce bcrypt cost to 10 to make auth timing more reasonable on slow servers (no ticket)
-* Docs update to include [public test topics](https://ntfy.sh/docs/publish/#public-topics) (no ticket)
+- Compress binaries with `upx` (#137)
+- Add `visitor-request-limit-exempt-hosts` to exempt friendly hosts from rate limits (#144)
+- Double default requests per second limit from 1 per 10s to 1 per 5s (no ticket)
+- Convert `\n` to new line for `X-Message` header as prep for sharing feature (see #136)
+- Reduce bcrypt cost to 10 to make auth timing more reasonable on slow servers (no ticket)
+- Docs update to include [public test topics](https://ntfy.sh/docs/publish/#public-topics) (no ticket)
## ntfy server v1.14.1
+
Released Feb 9, 2022
**Bug fixes:**
-* Fix ARMv8 Docker build (#113, thanks to @djmaze)
-* No other significant changes
+- Fix ARMv8 Docker build (#113, thanks to @djmaze)
+- No other significant changes
## ntfy Android app v1.8.1
+
Released Feb 6, 2022
**Features:**
-* Support [auth / access control](https://ntfy.sh/docs/config/#access-control) (#19, thanks to @cmeis, @drsprite/@poblabs,
+- Support [auth / access control](https://ntfy.sh/docs/config/#access-control) (#19, thanks to @cmeis, @drsprite/@poblabs,
@gedw99, @karmanyaahm, @Mek101, @gc-ss, @julianfoad, @nmoseman, Jakob, PeterCxy, Techlosopher)
-* Export/upload log now allows censored/uncensored logs (no ticket)
-* Removed wake lock (except for notification dispatching, no ticket)
-* Swipe to remove notifications (#117)
+- Export/upload log now allows censored/uncensored logs (no ticket)
+- Removed wake lock (except for notification dispatching, no ticket)
+- Swipe to remove notifications (#117)
**Bug fixes:**
-* Fix download issues on SDK 29 "Movement not allowed" (#116, thanks Jakob)
-* Fix for Android 12 crashes (#124, thanks @eskilop)
-* Fix WebSocket retry logic bug with multiple servers (no ticket)
-* Fix race in refresh logic leading to duplicate connections (no ticket)
-* Fix scrolling issue in subscribe to topic dialog (#131, thanks @arminus)
-* Fix base URL text field color in dark mode, and size with large fonts (no ticket)
-* Fix action bar color in dark mode (make black, no ticket)
+- Fix download issues on SDK 29 "Movement not allowed" (#116, thanks Jakob)
+- Fix for Android 12 crashes (#124, thanks @eskilop)
+- Fix WebSocket retry logic bug with multiple servers (no ticket)
+- Fix race in refresh logic leading to duplicate connections (no ticket)
+- Fix scrolling issue in subscribe to topic dialog (#131, thanks @arminus)
+- Fix base URL text field color in dark mode, and size with large fonts (no ticket)
+- Fix action bar color in dark mode (make black, no ticket)
**Notes:**
-* Foundational work for per-subscription settings
+- Foundational work for per-subscription settings
## ntfy server v1.14.0
+
Released Feb 3, 2022
**Features**:
-* Server-side for [authentication & authorization](https://ntfy.sh/docs/config/#access-control) (#19, thanks for testing @cmeis, and for input from @gedw99, @karmanyaahm, @Mek101, @gc-ss, @julianfoad, @nmoseman, Jakob, PeterCxy, Techlosopher)
-* Support `NTFY_TOPIC` env variable in `ntfy publish` (#103)
+- Server-side for [authentication & authorization](https://ntfy.sh/docs/config/#access-control) (#19, thanks for testing @cmeis, and for input from @gedw99, @karmanyaahm, @Mek101, @gc-ss, @julianfoad, @nmoseman, Jakob, PeterCxy, Techlosopher)
+- Support `NTFY_TOPIC` env variable in `ntfy publish` (#103)
**Bug fixes**:
-* Binary UnifiedPush messages should not be converted to attachments (part 1, #101)
+- Binary UnifiedPush messages should not be converted to attachments (part 1, #101)
**Docs**:
-* Clarification regarding attachments (#118, thanks @xnumad)
+- Clarification regarding attachments (#118, thanks @xnumad)
## ntfy Android app v1.7.1
+
Released Jan 21, 2022
**New features:**
-* Battery improvements: wakelock disabled by default (#76)
-* Dark mode: Allow changing app appearance (#102)
-* Report logs: Copy/export logs to help troubleshooting (#94)
-* WebSockets (experimental): Use WebSockets to subscribe to topics (#96, #100, #97)
-* Show battery optimization banner (#105)
+- Battery improvements: wakelock disabled by default (#76)
+- Dark mode: Allow changing app appearance (#102)
+- Report logs: Copy/export logs to help troubleshooting (#94)
+- WebSockets (experimental): Use WebSockets to subscribe to topics (#96, #100, #97)
+- Show battery optimization banner (#105)
**Bug fixes:**
-* (Partial) support for binary UnifiedPush messages (#101)
+- (Partial) support for binary UnifiedPush messages (#101)
**Notes:**
-* The foreground wakelock is now disabled by default
-* The service restarter is now scheduled every 3h instead of every 6h
+- The foreground wakelock is now disabled by default
+- The service restarter is now scheduled every 3h instead of every 6h
## ntfy server v1.13.0
+
Released Jan 16, 2022
**Features:**
-* [Websockets](https://ntfy.sh/docs/subscribe/api/#websockets) endpoint
-* Listen on Unix socket, see [config option](https://ntfy.sh/docs/config/#config-options) `listen-unix`
+- [Websockets](https://ntfy.sh/docs/subscribe/api/#websockets) endpoint
+- Listen on Unix socket, see [config option](https://ntfy.sh/docs/config/#config-options) `listen-unix`
## ntfy Android app v1.6.0
+
Released Jan 14, 2022
**New features:**
-* Attachments: Send files to the phone (#25, #15)
-* Click action: Add a click action URL to notifications (#85)
-* Battery optimization: Allow disabling persistent wake-lock (#76, thanks @MatMaul)
-* Recognize imported user CA certificate for self-hosted servers (#87, thanks @keith24)
-* Remove mentions of "instant delivery" from F-Droid to make it less confusing (no ticket)
+- Attachments: Send files to the phone (#25, #15)
+- Click action: Add a click action URL to notifications (#85)
+- Battery optimization: Allow disabling persistent wake-lock (#76, thanks @MatMaul)
+- Recognize imported user CA certificate for self-hosted servers (#87, thanks @keith24)
+- Remove mentions of "instant delivery" from F-Droid to make it less confusing (no ticket)
**Bug fixes:**
-* Subscription "muted until" was not always respected (#90)
-* Fix two stack traces reported by Play console vitals (no ticket)
-* Truncate FCM messages >4,000 bytes, prefer instant messages (#84)
+- Subscription "muted until" was not always respected (#90)
+- Fix two stack traces reported by Play console vitals (no ticket)
+- Truncate FCM messages >4,000 bytes, prefer instant messages (#84)
## ntfy server v1.12.1
+
Released Jan 14, 2022
**Bug fixes:**
-* Fix security issue with attachment peaking (#93)
+- Fix security issue with attachment peaking (#93)
## ntfy server v1.12.0
+
Released Jan 13, 2022
**Features:**
-* [Attachments](https://ntfy.sh/docs/publish/#attachments) (#25, #15)
-* [Click action](https://ntfy.sh/docs/publish/#click-action) (#85)
-* Increase FCM priority for high/max priority messages (#70)
+- [Attachments](https://ntfy.sh/docs/publish/#attachments) (#25, #15)
+- [Click action](https://ntfy.sh/docs/publish/#click-action) (#85)
+- Increase FCM priority for high/max priority messages (#70)
**Bug fixes:**
-* Make postinst script work properly for rpm-based systems (#83, thanks @cmeis)
-* Truncate FCM messages longer than 4000 bytes (#84)
-* Fix `listen-https` port (no ticket)
+- Make postinst script work properly for rpm-based systems (#83, thanks @cmeis)
+- Truncate FCM messages longer than 4000 bytes (#84)
+- Fix `listen-https` port (no ticket)
## ntfy Android app v1.5.2
+
Released Jan 3, 2022
**New features:**
-* Allow using ntfy as UnifiedPush distributor (#9)
-* Support for longer message up to 4096 bytes (#77)
-* Minimum priority: show notifications only if priority X or higher (#79)
-* Allowing disabling broadcasts in global settings (#80)
+- Allow using ntfy as UnifiedPush distributor (#9)
+- Support for longer message up to 4096 bytes (#77)
+- Minimum priority: show notifications only if priority X or higher (#79)
+- Allowing disabling broadcasts in global settings (#80)
**Bug fixes:**
-* Allow int/long extras for SEND_MESSAGE intent (#57)
-* Various battery improvement fixes (#76)
+- Allow int/long extras for SEND_MESSAGE intent (#57)
+- Various battery improvement fixes (#76)
## ntfy server v1.11.2
+
Released Jan 1, 2022
**Features & bug fixes:**
-* Increase message limit to 4096 bytes (4k) #77
-* Docs for [UnifiedPush](https://unifiedpush.org) #9
-* Increase keepalive interval to 55s #76
-* Increase Firebase keepalive to 3 hours #76
+- Increase message limit to 4096 bytes (4k) #77
+- Docs for [UnifiedPush](https://unifiedpush.org) #9
+- Increase keepalive interval to 55s #76
+- Increase Firebase keepalive to 3 hours #76
## ntfy server v1.10.0
+
Released Dec 28, 2021
**Features & bug fixes:**
-* [Publish messages via e-mail](ntfy.sh/docs/publish/#e-mail-publishing) #66
-* Server-side work to support [unifiedpush.org](https://unifiedpush.org) #64
-* Fixing the Santa bug #65
+- [Publish messages via e-mail](ntfy.sh/docs/publish/#e-mail-publishing) #66
+- Server-side work to support [unifiedpush.org](https://unifiedpush.org) #64
+- Fixing the Santa bug #65
## Older releases
+
For older releases, check out the GitHub releases pages for the [ntfy server](https://github.com/binwiederhier/ntfy/releases)
and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases).
@@ -1208,27 +1261,27 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
**Features:**
-* You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
+- You can now disable UnifiedPush so ntfy does not act as a UnifiedPush distributor ([#646](https://github.com/binwiederhier/ntfy/issues/646), thanks to [@ollien](https://github.com/ollien) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
**Bug fixes + maintenance:**
-* UnifiedPush subscriptions now include the `Rate-Topics` header to facilitate subscriber-based billing ([#652](https://github.com/binwiederhier/ntfy/issues/652), thanks to [@wunter8](https://github.com/wunter8))
-* Subscriptions without icons no longer appear to use another subscription's icon ([#634](https://github.com/binwiederhier/ntfy/issues/634), thanks to [@topcaser](https://github.com/topcaser) for reporting and to [@wunter8](https://github.com/wunter8) for fixing)
-* Bumped all dependencies to the latest versions (no ticket)
+- UnifiedPush subscriptions now include the `Rate-Topics` header to facilitate subscriber-based billing ([#652](https://github.com/binwiederhier/ntfy/issues/652), thanks to [@wunter8](https://github.com/wunter8))
+- Subscriptions without icons no longer appear to use another subscription's icon ([#634](https://github.com/binwiederhier/ntfy/issues/634), thanks to [@topcaser](https://github.com/topcaser) for reporting and to [@wunter8](https://github.com/wunter8) for fixing)
+- Bumped all dependencies to the latest versions (no ticket)
**Additional languages:**
-* Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/hellbown/))
+- Swedish (thanks to [@hellbown](https://hosted.weblate.org/user/hellbown/))
### ntfy server v2.6.0 (UNRELEASED)
**Bug fixes:**
-* Support encoding any header as RFC 2047 ([#737](https://github.com/binwiederhier/ntfy/issues/737), thanks to [@cfouche3005](https://github.com/cfouche3005) for reporting)
+- Support encoding any header as RFC 2047 ([#737](https://github.com/binwiederhier/ntfy/issues/737), thanks to [@cfouche3005](https://github.com/cfouche3005) for reporting)
**Maintenance:**
-* Improved GitHub Actions flow ([#745](https://github.com/binwiederhier/ntfy/pull/745), thanks to [@nimbleghost](https://github.com/nimbleghost))
-* Web: Add JS formatter "prettier" ([#746](https://github.com/binwiederhier/ntfy/pull/746), thanks to [@nimbleghost](https://github.com/nimbleghost))
-* Web: Add eslint with eslint-config-airbnb ([#748](https://github.com/binwiederhier/ntfy/pull/748), thanks to [@nimbleghost](https://github.com/nimbleghost))
-* Web: Switch to Vite ([#749](https://github.com/binwiederhier/ntfy/pull/749), thanks to [@nimbleghost](https://github.com/nimbleghost))
+- Improved GitHub Actions flow ([#745](https://github.com/binwiederhier/ntfy/pull/745), thanks to [@nimbleghost](https://github.com/nimbleghost))
+- Web: Add JS formatter "prettier" ([#746](https://github.com/binwiederhier/ntfy/pull/746), thanks to [@nimbleghost](https://github.com/nimbleghost))
+- Web: Add eslint with eslint-config-airbnb ([#748](https://github.com/binwiederhier/ntfy/pull/748), thanks to [@nimbleghost](https://github.com/nimbleghost))
+- Web: Switch to Vite ([#749](https://github.com/binwiederhier/ntfy/pull/749), thanks to [@nimbleghost](https://github.com/nimbleghost))
diff --git a/docs/static/css/extra.css b/docs/static/css/extra.css
index 3c53aed6..ca05ac25 100644
--- a/docs/static/css/extra.css
+++ b/docs/static/css/extra.css
@@ -1,216 +1,221 @@
:root > * {
- --md-primary-fg-color: #338574;
- --md-primary-fg-color--light: #338574;
- --md-primary-fg-color--dark: #338574;
- --md-footer-bg-color: #353744;
- --md-text-font: "Roboto";
- --md-code-font: "Roboto Mono";
+ --md-primary-fg-color: #338574;
+ --md-primary-fg-color--light: #338574;
+ --md-primary-fg-color--dark: #338574;
+ --md-footer-bg-color: #353744;
+ --md-text-font: "Roboto";
+ --md-code-font: "Roboto Mono";
}
.md-header__button.md-logo :is(img, svg) {
- width: unset !important;
+ width: unset !important;
}
.md-header__topic:first-child {
- font-weight: 400;
+ font-weight: 400;
}
.md-typeset h4 {
- font-weight: 500 !important;
- margin: 0 !important;
- font-size: 1.1em !important;
+ font-weight: 500 !important;
+ margin: 0 !important;
+ font-size: 1.1em !important;
}
.admonition {
- font-size: .74rem !important;
+ font-size: 0.74rem !important;
}
article {
- padding-bottom: 50px;
+ padding-bottom: 50px;
}
-figure img, figure video {
- border-radius: 7px;
+figure img,
+figure video {
+ border-radius: 7px;
}
header {
- background: linear-gradient(150deg, rgba(51,133,116,1) 0%, rgba(86,189,168,1) 100%);
+ background: linear-gradient(
+ 150deg,
+ rgba(51, 133, 116, 1) 0%,
+ rgba(86, 189, 168, 1) 100%
+ );
}
body[data-md-color-scheme="default"] header {
- filter: drop-shadow(0 5px 10px #ccc);
+ filter: drop-shadow(0 5px 10px #ccc);
}
body[data-md-color-scheme="slate"] header {
- filter: drop-shadow(0 5px 10px #333);
+ filter: drop-shadow(0 5px 10px #333);
}
body[data-md-color-scheme="default"] figure img,
body[data-md-color-scheme="default"] figure video,
body[data-md-color-scheme="default"] .screenshots img,
body[data-md-color-scheme="default"] .screenshots video {
- filter: drop-shadow(3px 3px 3px #ccc);
+ filter: drop-shadow(3px 3px 3px #ccc);
}
body[data-md-color-scheme="slate"] figure img,
body[data-md-color-scheme="slate"] figure video,
body[data-md-color-scheme="slate"] .screenshots img,
body[data-md-color-scheme="slate"] .screenshots video {
- filter: drop-shadow(3px 3px 3px #353744);
+ filter: drop-shadow(3px 3px 3px #353744);
}
figure video {
- width: 100%;
- max-height: 450px;
+ width: 100%;
+ max-height: 450px;
}
.remove-md-box {
- background: none;
- border: none;
- margin: 0 auto;
+ background: none;
+ border: none;
+ margin: 0 auto;
}
.remove-md-box td {
- padding: 0 10px;
+ padding: 0 10px;
}
.emoji-table .c {
- vertical-align: middle !important;
+ vertical-align: middle !important;
}
.emoji-table .e {
- font-size: 2.5em;
- padding: 0 2px !important;
- text-align: center !important;
- vertical-align: middle !important;
+ font-size: 2.5em;
+ padding: 0 2px !important;
+ text-align: center !important;
+ vertical-align: middle !important;
}
/* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */
.screenshots {
- text-align: center;
+ text-align: center;
}
.screenshots img {
- max-height: 230px;
- max-width: 300px;
- margin: 3px;
- border-radius: 5px;
- filter: drop-shadow(2px 2px 2px #ddd);
+ max-height: 230px;
+ max-width: 300px;
+ margin: 3px;
+ border-radius: 5px;
+ filter: drop-shadow(2px 2px 2px #ddd);
}
.screenshots .nowrap {
- white-space: nowrap;
+ white-space: nowrap;
}
.lightbox {
- opacity: 0;
- visibility: hidden;
- position: fixed;
- left:0;
- right: 0;
- top: 0;
- bottom: 0;
- z-index: -1;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.15s ease-in;
+ opacity: 0;
+ visibility: hidden;
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: -1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.15s ease-in;
}
.lightbox.show {
- background-color: rgba(0,0,0, 0.75);
- opacity: 1;
- visibility: visible;
- z-index: 1000;
+ background-color: rgba(0, 0, 0, 0.75);
+ opacity: 1;
+ visibility: visible;
+ z-index: 1000;
}
.lightbox img {
- max-width: 90%;
- max-height: 90%;
- filter: drop-shadow(5px 5px 10px #222);
- border-radius: 5px;
+ max-width: 90%;
+ max-height: 90%;
+ filter: drop-shadow(5px 5px 10px #222);
+ border-radius: 5px;
}
.lightbox .close-lightbox {
- cursor: pointer;
- position: absolute;
- top: 30px;
- right: 30px;
- width: 20px;
- height: 20px;
+ cursor: pointer;
+ position: absolute;
+ top: 30px;
+ right: 30px;
+ width: 20px;
+ height: 20px;
}
.lightbox .close-lightbox::after,
.lightbox .close-lightbox::before {
- content: '';
- width: 3px;
- height: 20px;
- background-color: #ddd;
- position: absolute;
- border-radius: 5px;
- transform: rotate(45deg);
+ content: "";
+ width: 3px;
+ height: 20px;
+ background-color: #ddd;
+ position: absolute;
+ border-radius: 5px;
+ transform: rotate(45deg);
}
.lightbox .close-lightbox::before {
- transform: rotate(-45deg);
+ transform: rotate(-45deg);
}
.lightbox .close-lightbox:hover::after,
.lightbox .close-lightbox:hover::before {
- background-color: #fff;
+ background-color: #fff;
}
/* roboto-300 - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto';
- font-style: normal;
- font-weight: 300;
- src: url('../fonts/roboto-v30-latin-300.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto";
+ font-style: normal;
+ font-weight: 300;
+ src: url("../fonts/roboto-v30-latin-300.woff2") format("woff2");
}
/* roboto-regular - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto';
- font-style: normal;
- font-weight: 400;
- src: url('../fonts/roboto-v30-latin-regular.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto";
+ font-style: normal;
+ font-weight: 400;
+ src: url("../fonts/roboto-v30-latin-regular.woff2") format("woff2");
}
/* roboto-italic - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto';
- font-style: italic;
- font-weight: 400;
- src: url('../fonts/roboto-v30-latin-italic.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto";
+ font-style: italic;
+ font-weight: 400;
+ src: url("../fonts/roboto-v30-latin-italic.woff2") format("woff2");
}
/* roboto-500 - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto';
- font-style: normal;
- font-weight: 500;
- src: url('../fonts/roboto-v30-latin-500.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto";
+ font-style: normal;
+ font-weight: 500;
+ src: url("../fonts/roboto-v30-latin-500.woff2") format("woff2");
}
/* roboto-700 - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto';
- font-style: normal;
- font-weight: 700;
- src: url('../fonts/roboto-v30-latin-700.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto";
+ font-style: normal;
+ font-weight: 700;
+ src: url("../fonts/roboto-v30-latin-700.woff2") format("woff2");
}
/* roboto-mono - latin */
@font-face {
- font-display: swap;
- font-family: 'Roboto Mono';
- font-style: normal;
- font-weight: 400;
- src: url('../fonts/roboto-mono-v22-latin-regular.woff2') format('woff2');
+ font-display: swap;
+ font-family: "Roboto Mono";
+ font-style: normal;
+ font-weight: 400;
+ src: url("../fonts/roboto-mono-v22-latin-regular.woff2") format("woff2");
}
diff --git a/docs/static/js/extra.js b/docs/static/js/extra.js
index 6ddf07a9..55101372 100644
--- a/docs/static/js/extra.js
+++ b/docs/static/js/extra.js
@@ -1,99 +1,109 @@
// Link tabs, as per https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs
-const savedCodeTab = localStorage.getItem('savedTab')
-const codeTabs = document.querySelectorAll(".tabbed-set > input")
+const savedCodeTab = localStorage.getItem("savedTab");
+const codeTabs = document.querySelectorAll(".tabbed-set > input");
for (const tab of codeTabs) {
- tab.addEventListener("click", () => {
- const current = document.querySelector(`label[for=${tab.id}]`)
- const pos = current.getBoundingClientRect().top
- const labelContent = current.innerHTML
- const labels = document.querySelectorAll('.tabbed-set > label, .tabbed-alternate > .tabbed-labels > label')
- for (const label of labels) {
- if (label.innerHTML === labelContent) {
- document.querySelector(`input[id=${label.getAttribute('for')}]`).checked = true
- }
- }
-
- // Preserve scroll position
- const delta = (current.getBoundingClientRect().top) - pos
- window.scrollBy(0, delta)
-
- // Save
- localStorage.setItem('savedTab', labelContent)
- })
-
- // Select saved tab
- const current = document.querySelector(`label[for=${tab.id}]`)
- const labelContent = current.innerHTML
- if (savedCodeTab === labelContent) {
- tab.checked = true
+ tab.addEventListener("click", () => {
+ const current = document.querySelector(`label[for=${tab.id}]`);
+ const pos = current.getBoundingClientRect().top;
+ const labelContent = current.innerHTML;
+ const labels = document.querySelectorAll(
+ ".tabbed-set > label, .tabbed-alternate > .tabbed-labels > label"
+ );
+ for (const label of labels) {
+ if (label.innerHTML === labelContent) {
+ document.querySelector(
+ `input[id=${label.getAttribute("for")}]`
+ ).checked = true;
+ }
}
+
+ // Preserve scroll position
+ const delta = current.getBoundingClientRect().top - pos;
+ window.scrollBy(0, delta);
+
+ // Save
+ localStorage.setItem("savedTab", labelContent);
+ });
+
+ // Select saved tab
+ const current = document.querySelector(`label[for=${tab.id}]`);
+ const labelContent = current.innerHTML;
+ if (savedCodeTab === labelContent) {
+ tab.checked = true;
+ }
}
// Lightbox for screenshot
-const lightbox = document.createElement('div');
-lightbox.classList.add('lightbox');
+const lightbox = document.createElement("div");
+lightbox.classList.add("lightbox");
document.body.appendChild(lightbox);
const showScreenshotOverlay = (e, el, group, index) => {
- lightbox.classList.add('show');
- document.addEventListener('keydown', nextScreenshotKeyboardListener);
- return showScreenshot(e, group, index);
+ lightbox.classList.add("show");
+ document.addEventListener("keydown", nextScreenshotKeyboardListener);
+ return showScreenshot(e, group, index);
};
const showScreenshot = (e, group, index) => {
- const actualIndex = resolveScreenshotIndex(group, index);
- lightbox.innerHTML = '
' + screenshots[group][actualIndex].innerHTML;
- lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e, group, actualIndex+1); };
- currentScreenshotGroup = group;
- currentScreenshotIndex = actualIndex;
- e.stopPropagation();
- return false;
+ const actualIndex = resolveScreenshotIndex(group, index);
+ lightbox.innerHTML =
+ '
' +
+ screenshots[group][actualIndex].innerHTML;
+ lightbox.querySelector("img").onclick = (e) => {
+ return showScreenshot(e, group, actualIndex + 1);
+ };
+ currentScreenshotGroup = group;
+ currentScreenshotIndex = actualIndex;
+ e.stopPropagation();
+ return false;
};
const nextScreenshot = (e) => {
- return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex+1);
+ return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex + 1);
};
const previousScreenshot = (e) => {
- return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex-1);
+ return showScreenshot(e, currentScreenshotGroup, currentScreenshotIndex - 1);
};
const resolveScreenshotIndex = (group, index) => {
- if (index < 0) {
- return screenshots[group].length - 1;
- } else if (index > screenshots[group].length - 1) {
- return 0;
- }
- return index;
+ if (index < 0) {
+ return screenshots[group].length - 1;
+ } else if (index > screenshots[group].length - 1) {
+ return 0;
+ }
+ return index;
};
const hideScreenshotOverlay = (e) => {
- lightbox.classList.remove('show');
- document.removeEventListener('keydown', nextScreenshotKeyboardListener);
+ lightbox.classList.remove("show");
+ document.removeEventListener("keydown", nextScreenshotKeyboardListener);
};
const nextScreenshotKeyboardListener = (e) => {
- switch (e.keyCode) {
- case 37:
- previousScreenshot(e);
- break;
- case 39:
- nextScreenshot(e);
- break;
- }
+ switch (e.keyCode) {
+ case 37:
+ previousScreenshot(e);
+ break;
+ case 39:
+ nextScreenshot(e);
+ break;
+ }
};
-let currentScreenshotGroup = '';
+let currentScreenshotGroup = "";
let currentScreenshotIndex = 0;
let screenshots = {};
-Array.from(document.getElementsByClassName('screenshots')).forEach((sg) => {
- const group = sg.id;
- screenshots[group] = [...sg.querySelectorAll('a')];
- screenshots[group].forEach((el, index) => {
- el.onclick = (e) => { return showScreenshotOverlay(e, el, group, index); };
- });
+Array.from(document.getElementsByClassName("screenshots")).forEach((sg) => {
+ const group = sg.id;
+ screenshots[group] = [...sg.querySelectorAll("a")];
+ screenshots[group].forEach((el, index) => {
+ el.onclick = (e) => {
+ return showScreenshotOverlay(e, el, group, index);
+ };
+ });
});
lightbox.onclick = hideScreenshotOverlay;
diff --git a/docs/subscribe/api.md b/docs/subscribe/api.md
index 58da9752..da2f4453 100644
--- a/docs/subscribe/api.md
+++ b/docs/subscribe/api.md
@@ -1,27 +1,31 @@
# Subscribe via API
+
You can create and subscribe to a topic in the [web UI](web.md), via the [phone app](phone.md), via the [ntfy CLI](cli.md),
-or in your own app or script by subscribing the API. This page describes how to subscribe via API. You may also want to
+or in your own app or script by subscribing the API. This page describes how to subscribe via API. You may also want to
check out the page that describes how to [publish messages](../publish.md).
-You can consume the subscription API as either a **[simple HTTP stream (JSON, SSE or raw)](#http-stream)**, or
+You can consume the subscription API as either a **[simple HTTP stream (JSON, SSE or raw)](#http-stream)**, or
**[via WebSockets](#websockets)**. Both are incredibly simple to use.
## HTTP stream
+
The HTTP stream-based API relies on a simple GET request with a streaming HTTP response, i.e **you open a GET request and
-the connection stays open forever**, sending messages back as they come in. There are three different API endpoints, which
+the connection stays open forever**, sending messages back as they come in. There are three different API endpoints, which
only differ in the response format:
-* [JSON stream](#subscribe-as-json-stream): `/json` returns a JSON stream, with one JSON message object per line
-* [SSE stream](#subscribe-as-sse-stream): `/sse` returns messages as [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events), which
+- [JSON stream](#subscribe-as-json-stream): `/json` returns a JSON stream, with one JSON message object per line
+- [SSE stream](#subscribe-as-sse-stream): `/sse` returns messages as [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events), which
can be used with [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
-* [Raw stream](#subscribe-as-raw-stream): `/raw` returns messages as raw text, with one line per message
+- [Raw stream](#subscribe-as-raw-stream): `/raw` returns messages as raw text, with one line per message
### Subscribe as JSON stream
-Here are a few examples of how to consume the JSON endpoint (`/json`). For almost all languages, **this is the
-recommended way to subscribe to a topic**. The notable exception is JavaScript, for which the
+
+Here are a few examples of how to consume the JSON endpoint (`/json`). For almost all languages, **this is the
+recommended way to subscribe to a topic**. The notable exception is JavaScript, for which the
[SSE/EventSource stream](#subscribe-as-sse-stream) is much easier to work with.
=== "Command line (curl)"
+
```
$ curl -s ntfy.sh/disk-alerts/json
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
@@ -31,6 +35,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
=== "ntfy CLI"
+
```
$ ntfy subcribe disk-alerts
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
@@ -38,14 +43,15 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
=== "HTTP"
- ``` http
+
+ ```http
GET /disk-alerts/json HTTP/1.1
Host: ntfy.sh
HTTP/1.1 200 OK
Content-Type: application/x-ndjson; charset=utf-8
Transfer-Encoding: chunked
-
+
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
@@ -53,7 +59,8 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
=== "Go"
- ``` go
+
+ ```go
resp, err := http.Get("https://ntfy.sh/disk-alerts/json")
if err != nil {
log.Fatal(err)
@@ -66,7 +73,8 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
=== "Python"
- ``` python
+
+ ```python
resp = requests.get("https://ntfy.sh/disk-alerts/json", stream=True)
for line in resp.iter_lines():
if line:
@@ -74,7 +82,8 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
$fp = fopen('https://ntfy.sh/disk-alerts/json', 'r');
if (!$fp) die('cannot open stream');
while (!feof($fp)) {
@@ -85,25 +94,28 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
```
### Subscribe as SSE stream
+
Using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) in JavaScript, you can consume
-notifications via a [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) stream. It's incredibly
+notifications via a [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) stream. It's incredibly
easy to use. Here's what it looks like. You may also want to check out the [full example on GitHub](https://github.com/binwiederhier/ntfy/tree/main/examples/web-example-eventsource).
=== "Command line (curl)"
+
```
$ curl -s ntfy.sh/mytopic/sse
event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
-
+
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
-
+
event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
...
```
=== "HTTP"
- ``` http
+
+ ```http
GET /mytopic/sse HTTP/1.1
Host: ntfy.sh
@@ -113,16 +125,17 @@ easy to use. Here's what it looks like. You may also want to check out the [full
event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
-
+
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
-
+
event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
...
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');
eventSource.onmessage = (e) => {
console.log(e.data);
@@ -130,21 +143,24 @@ easy to use. Here's what it looks like. You may also want to check out the [full
```
### Subscribe as raw stream
+
The `/raw` endpoint will output one line per message, and **will only include the message body**. It's useful for extremely
-simple scripts, and doesn't include all the data. Additional fields such as [priority](../publish.md#message-priority),
-[tags](../publish.md#tags--emojis--) or [message title](../publish.md#message-title) are not included in this output
+simple scripts, and doesn't include all the data. Additional fields such as [priority](../publish.md#message-priority),
+[tags](../publish.md#tags--emojis--) or [message title](../publish.md#message-title) are not included in this output
format. Keepalive messages are sent as empty lines.
=== "Command line (curl)"
+
```
$ curl -s ntfy.sh/disk-alerts/raw
-
+
Disk full
...
```
=== "HTTP"
- ``` http
+
+ ```http
GET /disk-alerts/raw HTTP/1.1
Host: ntfy.sh
@@ -157,7 +173,8 @@ format. Keepalive messages are sent as empty lines.
```
=== "Go"
- ``` go
+
+ ```go
resp, err := http.Get("https://ntfy.sh/disk-alerts/raw")
if err != nil {
log.Fatal(err)
@@ -170,7 +187,8 @@ format. Keepalive messages are sent as empty lines.
```
=== "Python"
- ``` python
+
+ ```python
resp = requests.get("https://ntfy.sh/disk-alerts/raw", stream=True)
for line in resp.iter_lines():
if line:
@@ -178,7 +196,8 @@ format. Keepalive messages are sent as empty lines.
```
=== "PHP"
- ``` php-inline
+
+ ```php-inline
$fp = fopen('https://ntfy.sh/disk-alerts/raw', 'r');
if (!$fp) die('cannot open stream');
while (!feof($fp)) {
@@ -189,15 +208,17 @@ format. Keepalive messages are sent as empty lines.
```
## WebSockets
-You may also subscribe to topics via [WebSockets](https://en.wikipedia.org/wiki/WebSocket), which is also widely
-supported in many languages. Most notably, WebSockets are natively supported in JavaScript. On the command line,
-I recommend [websocat](https://github.com/vi/websocat), a fantastic tool similar to `socat` or `curl`, but specifically
-for WebSockets.
-The WebSockets endpoint is available at `/ws` and returns messages as JSON objects similar to the
-[JSON stream endpoint](#subscribe-as-json-stream).
+You may also subscribe to topics via [WebSockets](https://en.wikipedia.org/wiki/WebSocket), which is also widely
+supported in many languages. Most notably, WebSockets are natively supported in JavaScript. On the command line,
+I recommend [websocat](https://github.com/vi/websocat), a fantastic tool similar to `socat` or `curl`, but specifically
+for WebSockets.
+
+The WebSockets endpoint is available at `/ws` and returns messages as JSON objects similar to the
+[JSON stream endpoint](#subscribe-as-json-stream).
=== "Command line (websocat)"
+
```
$ websocat wss://ntfy.sh/mytopic/ws
{"id":"qRHUCCvjj8","time":1642307388,"event":"open","topic":"mytopic"}
@@ -205,7 +226,8 @@ The WebSockets endpoint is available at `/ws` and returns messages as JSO
```
=== "HTTP"
- ``` http
+
+ ```http
GET /disk-alerts/ws HTTP/1.1
Host: ntfy.sh
Upgrade: websocket
@@ -218,15 +240,17 @@ The WebSockets endpoint is available at `/ws` and returns messages as JSO
```
=== "Go"
- ``` go
+
+ ```go
import "github.com/gorilla/websocket"
- ws, _, _ := websocket.DefaultDialer.Dial("wss://ntfy.sh/mytopic/ws", nil)
- messageType, data, err := ws.ReadMessage()
+ ws, _, _ := websocket.DefaultDialer.Dial("wss://ntfy.sh/mytopic/ws", nil)
+ messageType, data, err := ws.ReadMessage()
...
```
=== "JavaScript"
- ``` javascript
+
+ ```javascript
const socket = new WebSocket('wss://ntfy.sh/mytopic/ws');
socket.addEventListener('message', function (event) {
console.log(event.data);
@@ -236,6 +260,7 @@ The WebSockets endpoint is available at `/ws` and returns messages as JSO
## Advanced features
### Poll for messages
+
You can also just poll for messages if you don't like the long-standing connection using the `poll=1`
query parameter. The connection will end after all available messages have been read. This parameter can be
combined with `since=` (defaults to `since=all`).
@@ -245,8 +270,9 @@ curl -s "ntfy.sh/mytopic/json?poll=1"
```
### Fetch cached messages
+
Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network
-interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using
+interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using
the `since=` query parameter. It takes a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`),
a message ID (e.g. `nFS3knfcQ1xe`), or `all` (all cached messages).
@@ -257,9 +283,10 @@ curl -s "ntfy.sh/mytopic/json?since=nFS3knfcQ1xe"
```
### Fetch scheduled messages
-Messages that are [scheduled to be delivered](../publish.md#scheduled-delivery) at a later date are not typically
-returned when subscribing via the API, which makes sense, because after all, the messages have technically not been
-delivered yet. To also return scheduled messages from the API, you can use the `scheduled=1` (alias: `sched=1`)
+
+Messages that are [scheduled to be delivered](../publish.md#scheduled-delivery) at a later date are not typically
+returned when subscribing via the API, which makes sense, because after all, the messages have technically not been
+delivered yet. To also return scheduled messages from the API, you can use the `scheduled=1` (alias: `sched=1`)
parameter (makes most sense with the `poll=1` parameter):
```
@@ -267,9 +294,10 @@ curl -s "ntfy.sh/mytopic/json?poll=1&sched=1"
```
### Filter messages
+
You can filter which messages are returned based on the well-known message fields `id`, `message`, `title`, `priority` and
-`tags`. Here's an example that only returns messages of high or urgent priority that contains the both tags
-"zfs-error" and "error". Note that the `priority` filter is a logical OR and the `tags` filter is a logical AND.
+`tags`. Here's an example that only returns messages of high or urgent priority that contains the both tags
+"zfs-error" and "error". Note that the `priority` filter is a logical OR and the `tags` filter is a logical AND.
```
$ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error"
@@ -281,15 +309,16 @@ $ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error"
Available filters (all case-insensitive):
| Filter variable | Alias | Example | Description |
-|-----------------|---------------------------|-----------------------------------------------|-------------------------------------------------------------------------|
+| --------------- | ------------------------- | --------------------------------------------- | ----------------------------------------------------------------------- |
| `id` | `X-ID` | `ntfy.sh/mytopic/json?poll=1&id=pbkiz8SD7ZxG` | Only return messages that match this exact message ID |
| `message` | `X-Message`, `m` | `ntfy.sh/mytopic/json?message=lalala` | Only return messages that match this exact message string |
| `title` | `X-Title`, `t` | `ntfy.sh/mytopic/json?title=some+title` | Only return messages that match this exact title string |
-| `priority` | `X-Priority`, `prio`, `p` | `ntfy.sh/mytopic/json?p=high,urgent` | Only return messages that match *any priority listed* (comma-separated) |
-| `tags` | `X-Tags`, `tag`, `ta` | `ntfy.sh/mytopic?/jsontags=error,alert` | Only return messages that match *all listed tags* (comma-separated) |
+| `priority` | `X-Priority`, `prio`, `p` | `ntfy.sh/mytopic/json?p=high,urgent` | Only return messages that match _any priority listed_ (comma-separated) |
+| `tags` | `X-Tags`, `tag`, `ta` | `ntfy.sh/mytopic?/jsontags=error,alert` | Only return messages that match _all listed tags_ (comma-separated) |
### Subscribe to multiple topics
-It's possible to subscribe to multiple topics in one HTTP call by providing a comma-separated list of topics
+
+It's possible to subscribe to multiple topics in one HTTP call by providing a comma-separated list of topics
in the URL. This allows you to reduce the number of connections you have to maintain:
```
@@ -300,50 +329,53 @@ $ curl -s ntfy.sh/mytopic1,mytopic2/json
```
### Authentication
+
Depending on whether the server is configured to support [access control](../config.md#access-control), some topics
may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
To publish/subscribe to protected topics, you can:
-* Use [basic auth](../publish.md#basic-auth), e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
-* or use the [`auth` query parameter](../publish.md#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw`
+- Use [basic auth](../publish.md#basic-auth), e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
+- or use the [`auth` query parameter](../publish.md#query-param), e.g. `?auth=QmFzaWMgZEdWemRIVnpaWEk2Wm1GclpYQmhjM04zYjNKaw`
Please refer to the [publishing documentation](../publish.md#authentication) for additional details.
## JSON message format
+
Both the [`/json` endpoint](#subscribe-as-json-stream) and the [`/sse` endpoint](#subscribe-as-sse-stream) return a JSON
format of the message. It's very straight forward:
**Message**:
| Field | Required | Type | Example | Description |
-|--------------|----------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
-| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
-| `time` | ✔️ | *number* | `1635528741` | Message date time, as Unix time stamp |
-| `expires` | (✔)️ | *number* | `1673542291` | Unix time stamp indicating when the message will be deleted, not set if `Cache: no` is sent |
+| ------------ | -------- | ------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
+| `id` | ✔️ | _string_ | `hwQ2YpKdmg` | Randomly chosen message identifier |
+| `time` | ✔️ | _number_ | `1635528741` | Message date time, as Unix time stamp |
+| `expires` | (✔)️ | _number_ | `1673542291` | Unix time stamp indicating when the message will be deleted, not set if `Cache: no` is sent |
| `event` | ✔️ | `open`, `keepalive`, `message`, or `poll_request` | `message` | Message type, typically you'd be only interested in `message` |
-| `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
-| `message` | - | *string* | `Some message` | Message body; always present in `message` events |
-| `title` | - | *string* | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/` |
-| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](../publish.md#tags-emojis) that may or not map to emojis |
-| `priority` | - | *1, 2, 3, 4, or 5* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
-| `click` | - | *URL* | `https://example.com` | Website opened when notification is [clicked](../publish.md#click-action) |
-| `actions` | - | *JSON array* | *see [actions buttons](../publish.md#action-buttons)* | [Action buttons](../publish.md#action-buttons) that can be displayed in the notification |
-| `attachment` | - | *JSON object* | *see below* | Details about an attachment (name, URL, size, ...) |
+| `topic` | ✔️ | _string_ | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
+| `message` | - | _string_ | `Some message` | Message body; always present in `message` events |
+| `title` | - | _string_ | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/` |
+| `tags` | - | _string array_ | `["tag1","tag2"]` | List of [tags](../publish.md#tags-emojis) that may or not map to emojis |
+| `priority` | - | _1, 2, 3, 4, or 5_ | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
+| `click` | - | _URL_ | `https://example.com` | Website opened when notification is [clicked](../publish.md#click-action) |
+| `actions` | - | _JSON array_ | _see [actions buttons](../publish.md#action-buttons)_ | [Action buttons](../publish.md#action-buttons) that can be displayed in the notification |
+| `attachment` | - | _JSON object_ | _see below_ | Details about an attachment (name, URL, size, ...) |
**Attachment** (part of the message, see [attachments](../publish.md#attachments) for details):
| Field | Required | Type | Example | Description |
-|-----------|----------|-------------|--------------------------------|-----------------------------------------------------------------------------------------------------------|
-| `name` | ✔️ | *string* | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) |
-| `url` | ✔️ | *URL* | `https://example.com/file.jpg` | URL of the attachment |
-| `type` | -️ | *mime type* | `image/jpeg` | Mime type of the attachment, only defined if attachment was uploaded to ntfy server |
-| `size` | -️ | *number* | `33848` | Size of the attachment in bytes, only defined if attachment was uploaded to ntfy server |
-| `expires` | -️ | *number* | `1635528741` | Attachment expiry date as Unix time stamp, only defined if attachment was uploaded to ntfy server |
+| --------- | -------- | ----------- | ------------------------------ | --------------------------------------------------------------------------------------------------------- |
+| `name` | ✔️ | _string_ | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) |
+| `url` | ✔️ | _URL_ | `https://example.com/file.jpg` | URL of the attachment |
+| `type` | -️ | _mime type_ | `image/jpeg` | Mime type of the attachment, only defined if attachment was uploaded to ntfy server |
+| `size` | -️ | _number_ | `33848` | Size of the attachment in bytes, only defined if attachment was uploaded to ntfy server |
+| `expires` | -️ | _number_ | `1635528741` | Attachment expiry date as Unix time stamp, only defined if attachment was uploaded to ntfy server |
Here's an example for each message type:
=== "Notification message"
- ``` json
+
+ ```json
{
"id": "sPs71M8A2T",
"time": 1643935928,
@@ -368,9 +400,9 @@ Here's an example for each message type:
}
```
-
=== "Notification message (minimal)"
- ``` json
+
+ ```json
{
"id": "wze9zgqK41",
"time": 1638542110,
@@ -382,7 +414,8 @@ Here's an example for each message type:
```
=== "Open message"
- ``` json
+
+ ```json
{
"id": "2pgIAaGrQ8",
"time": 1638542215,
@@ -392,17 +425,19 @@ Here's an example for each message type:
```
=== "Keepalive message"
- ``` json
+
+ ```json
{
"id": "371sevb0pD",
"time": 1638542275,
"event": "keepalive",
"topic": "phil_alerts"
}
- ```
+ ```
=== "Poll request message"
- ``` json
+
+ ```json
{
"id": "371sevb0pD",
"time": 1638542275,
@@ -412,16 +447,17 @@ Here's an example for each message type:
```
## List of all parameters
+
The following is a list of all parameters that can be passed **when subscribing to a message**. Parameter names are **case-insensitive**,
and can be passed as **HTTP headers** or **query parameters in the URL**. They are listed in the table in their canonical form.
| Parameter | Aliases (case-insensitive) | Description |
-|-------------|----------------------------|---------------------------------------------------------------------------------|
+| ----------- | -------------------------- | ------------------------------------------------------------------------------- |
| `poll` | `X-Poll`, `po` | Return cached messages and close connection |
| `since` | `X-Since`, `si` | Return cached messages since timestamp, duration or message ID |
| `scheduled` | `X-Scheduled`, `sched` | Include scheduled/delayed messages in message list |
| `id` | `X-ID` | Filter: Only return messages that match this exact message ID |
| `message` | `X-Message`, `m` | Filter: Only return messages that match this exact message string |
| `title` | `X-Title`, `t` | Filter: Only return messages that match this exact title string |
-| `priority` | `X-Priority`, `prio`, `p` | Filter: Only return messages that match *any priority listed* (comma-separated) |
-| `tags` | `X-Tags`, `tag`, `ta` | Filter: Only return messages that match *all listed tags* (comma-separated) |
+| `priority` | `X-Priority`, `prio`, `p` | Filter: Only return messages that match _any priority listed_ (comma-separated) |
+| `tags` | `X-Tags`, `tag`, `ta` | Filter: Only return messages that match _all listed tags_ (comma-separated) |
diff --git a/docs/subscribe/cli.md b/docs/subscribe/cli.md
index 59cfc8e7..672b85b0 100644
--- a/docs/subscribe/cli.md
+++ b/docs/subscribe/cli.md
@@ -1,22 +1,24 @@
# Subscribe via ntfy CLI
+
In addition to subscribing via the [web UI](web.md), the [phone app](phone.md), or the [API](api.md), you can subscribe
to topics via the ntfy CLI. The CLI is included in the same `ntfy` binary that can be used to [self-host a server](../install.md).
!!! info
- The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md),
- and even use it to [subscribe to topics](api.md). It may be a little more convenient to use the ntfy CLI than writing
- your own script. It all depends on the use case. 😀
+The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md),
+and even use it to [subscribe to topics](api.md). It may be a little more convenient to use the ntfy CLI than writing
+your own script. It all depends on the use case. 😀
## Install + configure
-To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and
-client are the same binary, so it's all very convenient. After installing, you can (optionally) configure the client
-by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You
-can find a [skeleton config](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml) on GitHub.
+
+To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and
+client are the same binary, so it's all very convenient. After installing, you can (optionally) configure the client
+by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You
+can find a [skeleton config](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml) on GitHub.
If you just want to use [ntfy.sh](https://ntfy.sh), you don't have to change anything. If you **self-host your own server**,
you may want to edit the `default-host` option:
-``` yaml
+```yaml
# Base URL used to expand short topic names in the "ntfy publish" and "ntfy subscribe" commands.
# If you self-host a ntfy server, you'll likely want to change this.
#
@@ -24,19 +26,22 @@ default-host: https://ntfy.myhost.com
```
## Publish messages
-You can send messages with the ntfy CLI using the `ntfy publish` command (or any of its aliases `pub`, `send` or
+
+You can send messages with the ntfy CLI using the `ntfy publish` command (or any of its aliases `pub`, `send` or
`trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few
quick ones:
=== "Simple send"
- ```
+
+ ```sh
ntfy publish mytopic This is a message
ntfy publish mytopic "This is a message"
- ntfy pub mytopic "This is a message"
+ ntfy pub mytopic "This is a message"
```
=== "Send with title, priority, and tags"
- ```
+
+ ```sh
ntfy publish \
--title="Thing sold on eBay" \
--priority=high \
@@ -46,20 +51,23 @@ quick ones:
```
=== "Send at 8:30am"
- ```
+
+ ```sh
ntfy pub --at=8:30am delayed_topic Laterzz
```
=== "Triggering a webhook"
- ```
+
+ ```sh
ntfy trigger mywebhook
ntfy pub mywebhook
```
### Attaching a local file
+
You can easily upload and attach a local file to a notification:
-```
+```sh
$ ntfy pub --file README.md mytopic | jq .
{
"id": "meIlClVLABJQ",
@@ -78,13 +86,14 @@ $ ntfy pub --file README.md mytopic | jq .
```
### Wait for PID/command
-If you have a long-running command and want to **publish a notification when the command completes**,
+
+If you have a long-running command and want to **publish a notification when the command completes**,
you may wrap it with `ntfy publish --wait-cmd` (aliases: `--cmd`, `--done`). Or, if you forgot to wrap it, and the
command is already running, you can wait for the process to complete with `ntfy publish --wait-pid` (alias: `--pid`).
Run a command and wait for it to complete (here: `rsync ...`):
-```
+```sh
$ ntfy pub --wait-cmd mytopic rsync -av ./ root@example.com:/backups/ | jq .
{
"id": "Re0rWXZQM8WB",
@@ -98,7 +107,8 @@ $ ntfy pub --wait-cmd mytopic rsync -av ./ root@example.com:/backups/ | jq .
Or, if you already started the long-running process and want to wait for it using its process ID (PID), you can do this:
=== "Using a PID directly"
- ```
+
+ ```sh
$ ntfy pub --wait-pid 8458 mytopic | jq .
{
"id": "orM6hJKNYkWb",
@@ -110,7 +120,8 @@ Or, if you already started the long-running process and want to wait for it usin
```
=== "Using a `pidof`"
- ```
+
+ ```sh
$ ntfy pub --wait-pid $(pidof rsync) mytopic | jq .
{
"id": "orM6hJKNYkWb",
@@ -122,19 +133,22 @@ Or, if you already started the long-running process and want to wait for it usin
```
## Subscribe to topics
+
You can subscribe to topics using `ntfy subscribe`. Depending on how it is called, this command
-will either print or execute a command for every arriving message. There are a few different ways
+will either print or execute a command for every arriving message. There are a few different ways
in which the command can be run:
### Stream messages as JSON
-```
+
+```sh
ntfy subscribe TOPIC
```
-If you run the command like this, it prints the JSON representation of every incoming message. This is useful
-when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command
+
+If you run the command like this, it prints the JSON representation of every incoming message. This is useful
+when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command
stays open forever.
-```
+```sh
$ ntfy sub mytopic
{"id":"nZ8PjH5oox","time":1639971913,"event":"message","topic":"mytopic","message":"hi there"}
{"id":"sekSLWTujn","time":1639972063,"event":"message","topic":"mytopic",priority:5,"message":"Oh no!"}
@@ -147,13 +161,15 @@ $ ntfy sub mytopic
### Run command for every message
-```
+
+```sh
ntfy subscribe TOPIC COMMAND
```
+
If you run it like this, a COMMAND is executed for every incoming messages. Scroll down to see a list of available
environment variables. Here are a few examples:
-
-```
+
+```sh
ntfy sub mytopic 'notify-send "$m"'
ntfy sub topic1 /my/script.sh
ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had priority $p'
@@ -164,12 +180,12 @@ ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had prio
Execute command on incoming messages
-The message fields are passed to the command as environment variables and can be used in scripts. Note that since
+The message fields are passed to the command as environment variables and can be used in scripts. Note that since
these are environment variables, you typically don't have to worry about quoting too much, as long as you enclose them
in double-quotes, you should be fine:
| Variable | Aliases | Description |
-|------------------|----------------------------|----------------------------------------|
+| ---------------- | -------------------------- | -------------------------------------- |
| `$NTFY_ID` | `$id` | Unique message ID |
| `$NTFY_TIME` | `$time` | Unix timestamp of the message delivery |
| `$NTFY_TOPIC` | `$topic` | Topic name |
@@ -178,17 +194,20 @@ in double-quotes, you should be fine:
| `$NTFY_PRIORITY` | `$priority`, `$prio`, `$p` | Message priority (1=min, 5=max) |
| `$NTFY_TAGS` | `$tags`, `$tag`, `$ta` | Message tags (comma separated list) |
| `$NTFY_RAW` | `$raw` | Raw JSON message |
-
+
### Subscribe to multiple topics
-```
+
+```sh
ntfy subscribe --from-config
```
+
To subscribe to multiple topics at once, and run different commands for each one, you can use `ntfy subscribe --from-config`,
which will read the `subscribe` config from the config file. Please also check out the [ntfy-client systemd service](#using-the-systemd-service).
Here's an example config file that subscribes to three different topics, executing a different command for each of them:
=== "~/.config/ntfy/client.yml (Linux)"
+
```yaml
subscribe:
- topic: echo-this
@@ -210,8 +229,8 @@ Here's an example config file that subscribes to three different topics, executi
fi
```
-
=== "~/Library/Application Support/ntfy/client.yml (macOS)"
+
```yaml
subscribe:
- topic: echo-this
@@ -225,6 +244,7 @@ Here's an example config file that subscribes to three different topics, executi
```
=== "%AppData%\ntfy\client.yml (Windows)"
+
```yaml
subscribe:
- topic: echo-this
@@ -241,11 +261,11 @@ Here's an example config file that subscribes to three different topics, executi
In this example, when `ntfy subscribe --from-config` is executed:
-* Messages to `echo-this` simply echos to standard out
-* Messages to `alerts` display as desktop notification for high priority messages using [notify-send](https://manpages.ubuntu.com/manpages/focal/man1/notify-send.1.html) (Linux),
- [notifu](https://www.paralint.com/projects/notifu/) (Windows) or `osascript` (macOS)
-* Messages to `calc` open the calculator 😀 (*because, why not*)
-* Messages to `print-temp` execute an inline script and print the CPU temperature (Linux version only)
+- Messages to `echo-this` simply echos to standard out
+- Messages to `alerts` display as desktop notification for high priority messages using [notify-send](https://manpages.ubuntu.com/manpages/focal/man1/notify-send.1.html) (Linux),
+ [notifu](https://www.paralint.com/projects/notifu/) (Windows) or `osascript` (macOS)
+- Messages to `calc` open the calculator 😀 (_because, why not_)
+- Messages to `print-temp` execute an inline script and print the CPU temperature (Linux version only)
I hope this shows how powerful this command is. Here's a short video that demonstrates the above example:
@@ -259,20 +279,21 @@ You can also specify a `default-command` that will run when a message is receive
will be used, otherwise, the subscription settings will override the defaults.
!!! warning
- Because the `default-user`, `default-password`, and `default-token` will be sent for each topic that does not have its own username/password (even if the topic does not
- require authentication), be sure that the servers/topics you subscribe to use HTTPS to prevent leaking the username and password.
+Because the `default-user`, `default-password`, and `default-token` will be sent for each topic that does not have its own username/password (even if the topic does not
+require authentication), be sure that the servers/topics you subscribe to use HTTPS to prevent leaking the username and password.
### Using the systemd service
+
You can use the `ntfy-client` systemd service (see [ntfy-client.service](https://github.com/binwiederhier/ntfy/blob/main/client/ntfy-client.service))
to subscribe to multiple topics just like in the example above. The service is automatically installed (but not started)
if you install the deb/rpm package. To configure it, simply edit `/etc/ntfy/client.yml` and run `sudo systemctl restart ntfy-client`.
!!! info
- The `ntfy-client.service` runs as user `ntfy`, meaning that typical Linux permission restrictions apply. See below
- for how to fix this.
+The `ntfy-client.service` runs as user `ntfy`, meaning that typical Linux permission restrictions apply. See below
+for how to fix this.
-If the service runs on your personal desktop machine, you may want to override the service user/group (`User=` and `Group=`), and
-adjust the `DISPLAY` and `DBUS_SESSION_BUS_ADDRESS` environment variables. This will allow you to run commands in your X session
+If the service runs on your personal desktop machine, you may want to override the service user/group (`User=` and `Group=`), and
+adjust the `DISPLAY` and `DBUS_SESSION_BUS_ADDRESS` environment variables. This will allow you to run commands in your X session
as the primary machine user.
You can either manually override these systemd service entries with `sudo systemctl edit ntfy-client`, and add this
@@ -280,15 +301,17 @@ You can either manually override these systemd service entries with `sudo system
after editing the service file:
=== "/etc/systemd/system/ntfy-client.service.d/override.conf"
- ```
+
+ ```ini
[Service]
User=phil
Group=phil
Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
```
+
Or you can run the following script that creates this override config for you:
-```
+```sh
sudo sh -c 'cat > /etc/systemd/system/ntfy-client.service.d/override.conf' <
-You can get the Android app from both [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) and
+You can get the Android app from both [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) and
from [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/). Both are largely identical, with the one exception that
the F-Droid flavor does not use Firebase. The iOS app can be downloaded from the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347).
## Overview
+
A picture is worth a thousand words. Here are a few screenshots showing what the app looks like. It's all pretty
straight forward. You can add topics and as soon as you add them, you can [publish messages](../publish.md) to them.
@@ -33,6 +35,7 @@ If those screenshots are still not enough, here's a video:
## Message priority
+
_Supported on:_ :material-android: :material-apple:
When you [publish messages](../publish.md#message-priority) to a topic, you can **define a priority**. This priority defines
@@ -63,10 +66,11 @@ setting, and other settings such as popover or notification dot:
## Instant delivery
+
_Supported on:_ :material-android:
-Instant delivery allows you to receive messages on your phone instantly, **even when your phone is in doze mode**, i.e.
-when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which
+Instant delivery allows you to receive messages on your phone instantly, **even when your phone is in doze mode**, i.e.
+when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which
you'll see as a permanent notification that looks like this:
@@ -75,7 +79,7 @@ you'll see as a permanent notification that looks like this:
Android does not allow you to dismiss this notification, unless you turn off the notification channel in the settings.
-To do so, long-press on the foreground notification (screenshot above) and navigate to the settings. Then toggle the
+To do so, long-press on the foreground notification (screenshot above) and navigate to the settings. Then toggle the
"Subscription Service" off:
@@ -83,18 +87,19 @@ To do so, long-press on the foreground notification (screenshot above) and navig
Turning off the persistent instant delivery notification
-**Limitations without instant delivery**: Without instant delivery, **messages may arrive with a significant delay**
-(sometimes many minutes, or even hours later). If you've ever picked up your phone and
+**Limitations without instant delivery**: Without instant delivery, **messages may arrive with a significant delay**
+(sometimes many minutes, or even hours later). If you've ever picked up your phone and
suddenly had 10 messages that were sent long before you know what I'm talking about.
-The reason for this is [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging). FCM is the
-*only* Google approved way to send push messages to Android devices, and it's what pretty much all apps use to deliver push
+The reason for this is [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging). FCM is the
+_only_ Google approved way to send push messages to Android devices, and it's what pretty much all apps use to deliver push
notifications. Firebase is overall pretty bad at delivering messages in time, but on Android, most apps are stuck with it.
The ntfy Android app uses Firebase only for the main host `ntfy.sh`, and only in the Google Play flavor of the app.
It won't use Firebase for any self-hosted servers, and not at all in the the F-Droid flavor.
## Share to topic
+
_Supported on:_ :material-android:
You can share files to a topic using Android's "Share" feature. This works in almost any app that supports sharing files
@@ -109,33 +114,35 @@ The feature is pretty self-explanatory, and one picture says more than a thousan
## ntfy:// links
+
_Supported on:_ :material-android:
The ntfy Android app supports deep linking directly to topics. This is useful when integrating with [automation apps](#automation-apps)
such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid) or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm),
-or to simply directly link to a topic from a mobile website.
+or to simply directly link to a topic from a mobile website.
!!! info
- Android deep linking of http/https links is very brittle and limited, which is why something like `https:////subscribe` is
- **not possible**, and instead `ntfy://` links have to be used. More details in [issue #20](https://github.com/binwiederhier/ntfy/issues/20).
+Android deep linking of http/https links is very brittle and limited, which is why something like `https:////subscribe` is
+**not possible**, and instead `ntfy://` links have to be used. More details in [issue #20](https://github.com/binwiederhier/ntfy/issues/20).
**Supported link formats:**
| Link format | Example | Description |
-|-------------------------------------------------------------------------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| ----------------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ntfy:///` | `ntfy://ntfy.sh/mytopic` | Directly opens the Android app detail view for the given topic and server. Subscribes to the topic if not already subscribed. This is equivalent to the web view `https://ntfy.sh/mytopic` (HTTPS!) |
| `ntfy:///?secure=false` | `ntfy://example.com/mytopic?secure=false` | Same as above, except that this will use HTTP instead of HTTPS as topic URL. This is equivalent to the web view `http://example.com/mytopic` (HTTP!) |
## Integrations
### UnifiedPush
+
_Supported on:_ :material-android:
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
-[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications
-in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwarding messages to apps that support it.
+[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) service. It puts push notifications
+in the control of the user. ntfy can act as a **UnifiedPush distributor**, forwarding messages to apps that support it.
-To use ntfy as a distributor, simply select it in one of the [supported apps](https://unifiedpush.org/users/apps/).
+To use ntfy as a distributor, simply select it in one of the [supported apps](https://unifiedpush.org/users/apps/).
That's it. It's a one-step installation 😀. If desired, you can select your own [selfhosted ntfy server](../install.md)
to handle messages. Here's an example with [FluffyChat](https://fluffychat.im/):
@@ -146,6 +153,7 @@ to handle messages. Here's an example with [FluffyChat](https://fluffychat.im/):
### Automation apps
+
_Supported on:_ :material-android:
The ntfy Android app integrates nicely with automation apps such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
@@ -153,10 +161,11 @@ or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.
**react to incoming messages**, as well as **send messages**.
#### React to incoming messages
+
To react on incoming notifications, you have to register to intents with the `io.heckel.ntfy.MESSAGE_RECEIVED` action (see
[code for details](https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt)).
Here's an example using [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
-and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), but any app that can catch
+and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm), but any app that can catch
broadcasts is supported:
@@ -170,7 +179,7 @@ broadcasts is supported:
For MacroDroid, be sure to type in the package name `io.heckel.ntfy`, otherwise intents may be silently swallowed.
-If you're using topics to drive automation, you'll likely want to mute the topic in the ntfy app. This will prevent
+If you're using topics to drive automation, you'll likely want to mute the topic in the ntfy app. This will prevent
notification popups:
@@ -181,33 +190,34 @@ notification popups:
Here's a list of extras you can access. Most likely, you'll want to filter for `topic` and react on `message`:
| Extra name | Type | Example | Description |
-|----------------------|------------------------------|------------------------------------------|------------------------------------------------------------------------------------|
-| `id` | *String* | `bP8dMjO8ig` | Randomly chosen message identifier (likely not very useful for task automation) |
-| `base_url` | *String* | `https://ntfy.sh` | Root URL of the ntfy server this message came from |
-| `topic` ❤️ | *String* | `mytopic` | Topic name; **you'll likely want to filter for a specific topic** |
-| `muted` | *Boolean* | `true` | Indicates whether the subscription was muted in the app |
-| `muted_str` | *String (`true` or `false`)* | `true` | Same as `muted`, but as string `true` or `false` |
-| `time` | *Int* | `1635528741` | Message date time, as Unix time stamp |
-| `title` | *String* | `Some title` | Message [title](../publish.md#message-title); may be empty if not set |
-| `message` ❤️ | *String* | `Some message` | Message body; **this is likely what you're interested in** |
-| `message_bytes` | *ByteArray* | `(binary data)` | Message body as binary data |
-| `encoding`️ | *String* | - | Message encoding (empty or "base64") |
-| `tags` | *String* | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
-| `tags_map` | *String* | `0=tag1,1=tag2,..` | Map of tags to make it easier to map first, second, ... tag |
-| `priority` | *Int (between 1-5)* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
-| `click` | *String* | `https://google.com` | [Click action](../publish.md#click-action) URL, or empty if not set |
-| `attachment_name` | *String* | `attachment.jpg` | Filename of the attachment; may be empty if not set |
-| `attachment_type` | *String* | `image/jpeg` | Mime type of the attachment; may be empty if not set |
-| `attachment_size` | *Long* | `9923111` | Size in bytes of the attachment; may be zero if not set |
-| `attachment_expires` | *Long* | `1655514244` | Expiry date as Unix timestamp of the attachment URL; may be zero if not set |
-| `attachment_url` | *String* | `https://ntfy.sh/file/afUbjadfl7ErP.jpg` | URL of the attachment; may be empty if not set |
+| -------------------- | ---------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------- |
+| `id` | _String_ | `bP8dMjO8ig` | Randomly chosen message identifier (likely not very useful for task automation) |
+| `base_url` | _String_ | `https://ntfy.sh` | Root URL of the ntfy server this message came from |
+| `topic` ❤️ | _String_ | `mytopic` | Topic name; **you'll likely want to filter for a specific topic** |
+| `muted` | _Boolean_ | `true` | Indicates whether the subscription was muted in the app |
+| `muted_str` | _String (`true` or `false`)_ | `true` | Same as `muted`, but as string `true` or `false` |
+| `time` | _Int_ | `1635528741` | Message date time, as Unix time stamp |
+| `title` | _String_ | `Some title` | Message [title](../publish.md#message-title); may be empty if not set |
+| `message` ❤️ | _String_ | `Some message` | Message body; **this is likely what you're interested in** |
+| `message_bytes` | _ByteArray_ | `(binary data)` | Message body as binary data |
+| `encoding`️ | _String_ | - | Message encoding (empty or "base64") |
+| `tags` | _String_ | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
+| `tags_map` | _String_ | `0=tag1,1=tag2,..` | Map of tags to make it easier to map first, second, ... tag |
+| `priority` | _Int (between 1-5)_ | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
+| `click` | _String_ | `https://google.com` | [Click action](../publish.md#click-action) URL, or empty if not set |
+| `attachment_name` | _String_ | `attachment.jpg` | Filename of the attachment; may be empty if not set |
+| `attachment_type` | _String_ | `image/jpeg` | Mime type of the attachment; may be empty if not set |
+| `attachment_size` | _Long_ | `9923111` | Size in bytes of the attachment; may be zero if not set |
+| `attachment_expires` | _Long_ | `1655514244` | Expiry date as Unix timestamp of the attachment URL; may be zero if not set |
+| `attachment_url` | _String_ | `https://ntfy.sh/file/afUbjadfl7ErP.jpg` | URL of the attachment; may be empty if not set |
#### Send messages using intents
+
To send messages from other apps (such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
-and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)), you can
+and [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)), you can
broadcast an intent with the `io.heckel.ntfy.SEND_MESSAGE` action. The ntfy Android app will forward the intent as a HTTP
POST request to [publish a message](../publish.md). This is primarily useful for apps that do not support HTTP POST/PUT
-(like MacroDroid). In Tasker, you can simply use the "HTTP Request" action, which is a little easier and also works if
+(like MacroDroid). In Tasker, you can simply use the "HTTP Request" action, which is a little easier and also works if
ntfy is not installed.
Here's what that looks like:
@@ -223,10 +233,10 @@ Here's what that looks like:
The following intent extras are supported when for the intent with the `io.heckel.ntfy.SEND_MESSAGE` action:
| Extra name | Required | Type | Example | Description |
-|--------------|----------|-------------------------------|-------------------|------------------------------------------------------------------------------------|
-| `base_url` | - | *String* | `https://ntfy.sh` | Root URL of the ntfy server this message came from, defaults to `https://ntfy.sh` |
-| `topic` ❤️ | ✔ | *String* | `mytopic` | Topic name; **you must set this** |
-| `title` | - | *String* | `Some title` | Message [title](../publish.md#message-title); may be empty if not set |
-| `message` ❤️ | ✔ | *String* | `Some message` | Message body; **you must set this** |
-| `tags` | - | *String* | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
-| `priority` | - | *String or Int (between 1-5)* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
+| ------------ | -------- | ----------------------------- | ----------------- | ---------------------------------------------------------------------------------- |
+| `base_url` | - | _String_ | `https://ntfy.sh` | Root URL of the ntfy server this message came from, defaults to `https://ntfy.sh` |
+| `topic` ❤️ | ✔ | _String_ | `mytopic` | Topic name; **you must set this** |
+| `title` | - | _String_ | `Some title` | Message [title](../publish.md#message-title); may be empty if not set |
+| `message` ❤️ | ✔ | _String_ | `Some message` | Message body; **you must set this** |
+| `tags` | - | _String_ | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
+| `priority` | - | _String or Int (between 1-5)_ | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
diff --git a/docs/subscribe/web.md b/docs/subscribe/web.md
index 5c2672f0..d37556d6 100644
--- a/docs/subscribe/web.md
+++ b/docs/subscribe/web.md
@@ -1,6 +1,7 @@
# Subscribe from the Web UI
+
You can use the Web UI to subscribe to topics as well. If you do, and you keep the website open, **notifications will
-pop up as desktop notifications**. Simply type in the topic name and click the *Subscribe* button. The browser will
+pop up as desktop notifications**. Simply type in the topic name and click the _Subscribe_ button. The browser will
keep a connection open and listen for incoming notifications.
To learn how to send messages, check out the [publishing page](../publish.md).
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index d37561c5..e6bc3d8f 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -1,20 +1,24 @@
# Troubleshooting
-This page lists a few suggestions of what to do when things don't work as expected. This is not a complete list.
+
+This page lists a few suggestions of what to do when things don't work as expected. This is not a complete list.
If this page does not help, feel free to drop by the [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)
and ask there. We're happy to help.
## ntfy server
+
If you host your own ntfy server, and you're having issues with any component, it is always helpful to enable debugging/tracing
in the server. You can find detailed instructions in the [Logging & Debugging](config.md#logging-debugging) section, but it ultimately
boils down to setting `log-level: debug` or `log-level: trace` in the `server.yml` file:
=== "server.yml (debug)"
- ``` yaml
+
+ ```yaml
log-level: debug
```
=== "server.yml (trace)"
- ``` yaml
+
+ ```yaml
log-level: trace
```
@@ -23,6 +27,7 @@ to the `ntfy serve` command, e.g. `ntfy serve --trace`. If you're using systemd
the logs using `journalctl -u ntfy -f`. The logs will look something like this:
=== "Example logs (debug)"
+
```
$ ntfy serve --debug
2023/03/20 14:45:38 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is DEBUG (tag=startup)
@@ -33,10 +38,11 @@ the logs using `journalctl -u ntfy -f`. The logs will look something like this:
2023/03/20 14:45:39 DEBUG Adding message to cache (http_method=POST, http_path=/mytopic, message_body_size=2, message_event=message, message_id=EZu6i2WZjH0v, message_sender=127.0.0.1, message_time=1679337939, tag=publish, topic=mytopic, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.000259165, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG HTTP request finished (http_method=POST, http_path=/mytopic, tag=http, time_taken_ms=2, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=1, visitor_messages_limit=500, visitor_messages_remaining=499, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=59.0004147334, visitor_seen=2023-03-20T14:45:39.7-04:00)
2023/03/20 14:45:39 DEBUG Wrote 1 message(s) in 8.285712ms (tag=message_cache)
- ...
+ ...
```
=== "Example logs (trace)"
+
```
$ ntfy serve --trace
2023/03/20 14:40:42 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is TRACE (tag=startup)
@@ -47,7 +53,7 @@ the logs using `journalctl -u ntfy -f`. The logs will look something like this:
Accept: */*
Content-Length: 2
Content-Type: application/x-www-form-urlencoded
-
+
hi, tag=http, visitor_auth_limiter_limit=0.016666666666666666, visitor_auth_limiter_tokens=10, visitor_emails=0, visitor_emails_limit=12, visitor_emails_remaining=12, visitor_id=ip:127.0.0.1, visitor_ip=127.0.0.1, visitor_messages=0, visitor_messages_limit=500, visitor_messages_remaining=500, visitor_request_limiter_limit=0.2, visitor_request_limiter_tokens=60, visitor_seen=2023-03-20T14:40:59.893-04:00)
2023/03/20 14:40:59 TRACE Received message (http_method=POST, http_path=/mytopic, message_body={
"id": "Khaup1RVclU3",
@@ -65,8 +71,9 @@ the logs using `journalctl -u ntfy -f`. The logs will look something like this:
```
## Android app
+
On Android, you can turn on logging in the settings under **Settings → Record logs**. This will store up to 1,000 log
-entries, which you can then copy or upload.
+entries, which you can then copy or upload.
{ width=400 }
@@ -119,7 +126,8 @@ adb -s 192.168.1.137:39539 logcat --pid=$(adb -s 192.168.1.137:39539 shell pidof
```
## Web app
-The web app logs everything to the **developer console**, which you can open by **pressing the F12 key** on your
+
+The web app logs everything to the **developer console**, which you can open by **pressing the F12 key** on your
keyboard.
@@ -128,4 +136,5 @@ keyboard.
## iOS app
+
Sorry, there is no way to debug or get the logs from the iOS app (yet), outside of running the app in Xcode.
diff --git a/examples/grafana-dashboard/ntfy-grafana.json b/examples/grafana-dashboard/ntfy-grafana.json
index 11273da3..e6f83f7a 100644
--- a/examples/grafana-dashboard/ntfy-grafana.json
+++ b/examples/grafana-dashboard/ntfy-grafana.json
@@ -114,9 +114,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -175,9 +173,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -236,9 +232,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -302,9 +296,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -364,9 +356,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -426,9 +416,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
- "calcs": [
- "last"
- ],
+ "calcs": ["last"],
"fields": "",
"values": false
},
@@ -1083,9 +1071,7 @@
"id": 41,
"options": {
"legend": {
- "calcs": [
- "mean"
- ],
+ "calcs": ["mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1179,9 +1165,7 @@
"id": 16,
"options": {
"legend": {
- "calcs": [
- "mean"
- ],
+ "calcs": ["mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2397,4 +2381,4 @@
"uid": "TO6HgexVz",
"version": 24,
"weekStart": ""
-}
\ No newline at end of file
+}
diff --git a/examples/web-example-eventsource/example-sse.html b/examples/web-example-eventsource/example-sse.html
index e558ef12..12daf880 100644
--- a/examples/web-example-eventsource/example-sse.html
+++ b/examples/web-example-eventsource/example-sse.html
@@ -1,56 +1,64 @@
-
-
+
+
ntfy.sh: EventSource Example
-
-
-ntfy.sh: EventSource Example
-
- This is an example showing how to use ntfy.sh with
- EventSource .
- This example doesn't need a server. You can just save the HTML page and run it from anywhere.
-
-Send test notification
-Log:
-
+
+
+ ntfy.sh: EventSource Example
+
+ This is an example showing how to use
+ ntfy.sh with
+ EventSource .
+ This example doesn't need a server. You can just save the HTML page and
+ run it from anywhere.
+
+ Send test notification
+ Log:
+
-
-
-
+ };
+
+
diff --git a/mkdocs.yml b/mkdocs.yml
index 4a7db366..651c8874 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -17,12 +17,12 @@ theme:
include_search_page: false
search_index_only: true
palette:
- - media: "(prefers-color-scheme: light)" # Light mode
+ - media: "(prefers-color-scheme: light)" # Light mode
scheme: default
toggle:
icon: material/lightbulb-outline
name: Switch to dark mode
- - media: "(prefers-color-scheme: dark)" # Dark mode
+ - media: "(prefers-color-scheme: dark)" # Dark mode
scheme: slate
accent: indigo
toggle:
@@ -76,27 +76,25 @@ plugins:
on_post_build: "docs.hooks:copy_fonts"
nav:
-- "Getting started": index.md
-- "Publishing":
- - "Sending messages": publish.md
-- "Subscribing":
- - "From your phone": subscribe/phone.md
- - "From the Web app": subscribe/web.md
- - "From the CLI": subscribe/cli.md
- - "Using the API": subscribe/api.md
-- "Self-hosting":
- - "Installation": install.md
- - "Configuration": config.md
-- "Other things":
- - "FAQs": faq.md
- - "Examples": examples.md
- - "Integrations + projects": integrations.md
- - "Release notes": releases.md
- - "Emojis 🥳 🎉": emojis.md
- - "Troubleshooting": troubleshooting.md
- - "Known issues": known-issues.md
- - "Deprecation notices": deprecations.md
- - "Development": develop.md
- - "Privacy policy": privacy.md
-
-
+ - "Getting started": index.md
+ - "Publishing":
+ - "Sending messages": publish.md
+ - "Subscribing":
+ - "From your phone": subscribe/phone.md
+ - "From the Web app": subscribe/web.md
+ - "From the CLI": subscribe/cli.md
+ - "Using the API": subscribe/api.md
+ - "Self-hosting":
+ - "Installation": install.md
+ - "Configuration": config.md
+ - "Other things":
+ - "FAQs": faq.md
+ - "Examples": examples.md
+ - "Integrations + projects": integrations.md
+ - "Release notes": releases.md
+ - "Emojis 🥳 🎉": emojis.md
+ - "Troubleshooting": troubleshooting.md
+ - "Known issues": known-issues.md
+ - "Deprecation notices": deprecations.md
+ - "Development": develop.md
+ - "Privacy policy": privacy.md
diff --git a/tools/fbsend/README.md b/tools/fbsend/README.md
index 1cd785a0..b2e3e7f4 100644
--- a/tools/fbsend/README.md
+++ b/tools/fbsend/README.md
@@ -1,2 +1,3 @@
# fbsend
+
fbsend is a tiny tool to send data messages to Firebase. It's only used for testing.