Merge 9eb9719239
into 953efbee47
This commit is contained in:
commit
f8c526e812
44 changed files with 2869 additions and 2233 deletions
6
.editorconfig
Normal file
6
.editorconfig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
|
@ -9,3 +9,6 @@ ca5d736a7169eb6b4b0d849e061d5bf9565dcc53
|
||||||
# Run eslint (https://github.com/binwiederhier/ntfy/pull/748)
|
# Run eslint (https://github.com/binwiederhier/ntfy/pull/748)
|
||||||
f558b4dbe9bb5b9e0e87fada1215de2558353173
|
f558b4dbe9bb5b9e0e87fada1215de2558353173
|
||||||
8319f1cf26113167fb29fe12edaff5db74caf35f
|
8319f1cf26113167fb29fe12edaff5db74caf35f
|
||||||
|
|
||||||
|
# Run prettier on everything else (https://github.com/binwiederhier/ntfy/pull/758)
|
||||||
|
c1ff20f5be4fc0928ab027ec60e97e5b12aa5cd9
|
||||||
|
|
11
.github/ISSUE_TEMPLATE/1_bug_report.md
vendored
11
.github/ISSUE_TEMPLATE/1_bug_report.md
vendored
|
@ -1,19 +1,21 @@
|
||||||
---
|
---
|
||||||
name: 🐛 Bug Report
|
name: 🐛 Bug Report
|
||||||
about: Report any errors and problems
|
about: Report any errors and problems
|
||||||
title: ''
|
title: ""
|
||||||
labels: '🪲 bug'
|
labels: "🪲 bug"
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
:lady_beetle: **Describe the bug**
|
:lady_beetle: **Describe the bug**
|
||||||
|
|
||||||
<!-- A clear and concise description of the problem. -->
|
<!-- A clear and concise description of the problem. -->
|
||||||
|
|
||||||
:computer: **Components impacted**
|
:computer: **Components impacted**
|
||||||
|
|
||||||
<!-- ntfy server, Android app, iOS app, web app -->
|
<!-- ntfy server, Android app, iOS app, web app -->
|
||||||
|
|
||||||
:bulb: **Screenshots and/or logs**
|
:bulb: **Screenshots and/or logs**
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If applicable, add screenshots or share logs help explain your problem.
|
If applicable, add screenshots or share logs help explain your problem.
|
||||||
To get logs from the ...
|
To get logs from the ...
|
||||||
|
@ -23,4 +25,5 @@ To get logs from the ...
|
||||||
-->
|
-->
|
||||||
|
|
||||||
:crystal_ball: **Additional context**
|
:crystal_ball: **Additional context**
|
||||||
|
|
||||||
<!-- Add any other context about the problem here. -->
|
<!-- Add any other context about the problem here. -->
|
||||||
|
|
10
.github/ISSUE_TEMPLATE/2_enhancement_request.md
vendored
10
.github/ISSUE_TEMPLATE/2_enhancement_request.md
vendored
|
@ -1,10 +1,9 @@
|
||||||
---
|
---
|
||||||
name: 💡 Feature/Enhancement Request
|
name: 💡 Feature/Enhancement Request
|
||||||
about: Got a great idea? Let us know!
|
about: Got a great idea? Let us know!
|
||||||
title: ''
|
title: ""
|
||||||
labels: 'enhancement'
|
labels: "enhancement"
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -18,9 +17,10 @@ sooner, and there are more people there to help!
|
||||||
-->
|
-->
|
||||||
|
|
||||||
:bulb: **Idea**
|
:bulb: **Idea**
|
||||||
|
|
||||||
<!-- Share your thoughts; try to be detailed if you can -->
|
<!-- Share your thoughts; try to be detailed if you can -->
|
||||||
|
|
||||||
:computer: **Target components**
|
:computer: **Target components**
|
||||||
|
|
||||||
<!-- Where should this feature/enhancement be added? -->
|
<!-- Where should this feature/enhancement be added? -->
|
||||||
<!-- e.g. ntfy server, Android app, iOS app, web app -->
|
<!-- e.g. ntfy server, Android app, iOS app, web app -->
|
||||||
|
|
||||||
|
|
8
.github/ISSUE_TEMPLATE/3_tech_support.md
vendored
8
.github/ISSUE_TEMPLATE/3_tech_support.md
vendored
|
@ -1,13 +1,11 @@
|
||||||
---
|
---
|
||||||
name: 🆘 I need help with ...
|
name: 🆘 I need help with ...
|
||||||
about: Installing ntfy, configuring the app, etc.
|
about: Installing ntfy, configuring the app, etc.
|
||||||
title: ''
|
title: ""
|
||||||
labels: 'tech-support'
|
labels: "tech-support"
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
STOP!
|
STOP!
|
||||||
|
|
8
.github/ISSUE_TEMPLATE/4_question.md
vendored
8
.github/ISSUE_TEMPLATE/4_question.md
vendored
|
@ -1,10 +1,9 @@
|
||||||
---
|
---
|
||||||
name: ❓ Question
|
name: ❓ Question
|
||||||
about: Ask a question about ntfy
|
about: Ask a question about ntfy
|
||||||
title: ''
|
title: ""
|
||||||
labels: 'question'
|
labels: "question"
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -18,4 +17,5 @@ sooner, and there are more people there to help!
|
||||||
-->
|
-->
|
||||||
|
|
||||||
:question: **Question**
|
:question: **Question**
|
||||||
|
|
||||||
<!-- Go ahead and ask your question here :) -->
|
<!-- Go ahead and ask your question here :) -->
|
||||||
|
|
26
.github/workflows/build.yaml
vendored
26
.github/workflows/build.yaml
vendored
|
@ -4,27 +4,21 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checkout code
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
-
|
- name: Install Go
|
||||||
name: Install Go
|
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.19.x'
|
go-version: "1.19.x"
|
||||||
-
|
- name: Install node
|
||||||
name: Install node
|
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "18"
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
cache-dependency-path: './web/package-lock.json'
|
cache-dependency-path: "./web/package-lock.json"
|
||||||
-
|
- name: Install dependencies
|
||||||
name: Install dependencies
|
|
||||||
run: make build-deps-ubuntu
|
run: make build-deps-ubuntu
|
||||||
-
|
- name: Build all the things
|
||||||
name: Build all the things
|
|
||||||
run: make build
|
run: make build
|
||||||
-
|
- name: Print build results and checksums
|
||||||
name: Print build results and checksums
|
|
||||||
run: make cli-build-results
|
run: make cli-build-results
|
||||||
|
|
15
.github/workflows/docs.yaml
vendored
15
.github/workflows/docs.yaml
vendored
|
@ -7,11 +7,9 @@ jobs:
|
||||||
publish-docs:
|
publish-docs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checkout ntfy code
|
||||||
name: Checkout ntfy code
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
-
|
- name: Checkout docs pages code
|
||||||
name: Checkout docs pages code
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: binwiederhier/ntfy-docs.github.io
|
repository: binwiederhier/ntfy-docs.github.io
|
||||||
|
@ -19,14 +17,11 @@ jobs:
|
||||||
token: ${{secrets.NTFY_DOCS_PUSH_TOKEN}}
|
token: ${{secrets.NTFY_DOCS_PUSH_TOKEN}}
|
||||||
# Expires after 1 year, re-generate via
|
# Expires after 1 year, re-generate via
|
||||||
# User -> Settings -> Developer options -> Personal Access Tokens -> Fine Grained Token
|
# User -> Settings -> Developer options -> Personal Access Tokens -> Fine Grained Token
|
||||||
-
|
- name: Build docs
|
||||||
name: Build docs
|
|
||||||
run: make 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/
|
run: rsync -av --exclude CNAME --delete server/docs/ build/ntfy-docs.github.io/docs/
|
||||||
-
|
- name: Publish docs
|
||||||
name: Publish docs
|
|
||||||
run: |
|
run: |
|
||||||
cd build/ntfy-docs.github.io
|
cd build/ntfy-docs.github.io
|
||||||
git config user.name "GitHub Actions Bot"
|
git config user.name "GitHub Actions Bot"
|
||||||
|
|
31
.github/workflows/release.yaml
vendored
31
.github/workflows/release.yaml
vendored
|
@ -2,40 +2,33 @@ name: release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checkout code
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
-
|
- name: Install Go
|
||||||
name: Install Go
|
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.19.x'
|
go-version: "1.19.x"
|
||||||
-
|
- name: Install node
|
||||||
name: Install node
|
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "18"
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
cache-dependency-path: './web/package-lock.json'
|
cache-dependency-path: "./web/package-lock.json"
|
||||||
-
|
- name: Docker login
|
||||||
name: Docker login
|
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||||
-
|
- name: Install dependencies
|
||||||
name: Install dependencies
|
|
||||||
run: make build-deps-ubuntu
|
run: make build-deps-ubuntu
|
||||||
-
|
- name: Build and publish
|
||||||
name: Build and publish
|
|
||||||
run: make release
|
run: make release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
-
|
- name: Print build results and checksums
|
||||||
name: Print build results and checksums
|
|
||||||
run: make cli-build-results
|
run: make cli-build-results
|
||||||
|
|
35
.github/workflows/test.yaml
vendored
35
.github/workflows/test.yaml
vendored
|
@ -4,36 +4,27 @@ jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checkout code
|
||||||
name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
-
|
- name: Install Go
|
||||||
name: Install Go
|
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.19.x'
|
go-version: "1.19.x"
|
||||||
-
|
- name: Install node
|
||||||
name: Install node
|
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "18"
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
cache-dependency-path: './web/package-lock.json'
|
cache-dependency-path: "./web/package-lock.json"
|
||||||
-
|
- name: Install dependencies
|
||||||
name: Install dependencies
|
|
||||||
run: make build-deps-ubuntu
|
run: make build-deps-ubuntu
|
||||||
-
|
- name: Build docs (required for tests)
|
||||||
name: Build docs (required for tests)
|
|
||||||
run: make docs
|
run: make docs
|
||||||
-
|
- name: Build web app (required for tests)
|
||||||
name: Build web app (required for tests)
|
|
||||||
run: make web
|
run: make web
|
||||||
-
|
- name: Run tests, formatting, vetting and linting
|
||||||
name: Run tests, formatting, vetting and linting
|
|
||||||
run: make check
|
run: make check
|
||||||
-
|
- name: Run coverage
|
||||||
name: Run coverage
|
|
||||||
run: make coverage
|
run: make coverage
|
||||||
-
|
- name: Upload coverage to codecov.io
|
||||||
name: Upload coverage to codecov.io
|
|
||||||
run: make coverage-upload
|
run: make coverage-upload
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,7 +1,6 @@
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
|
||||||
*.swp
|
*.swp
|
||||||
server/docs/
|
server/docs/
|
||||||
server/site/
|
server/site/
|
||||||
|
|
|
@ -3,8 +3,7 @@ before:
|
||||||
- go mod download
|
- go mod download
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
builds:
|
builds:
|
||||||
-
|
- id: ntfy_linux_amd64
|
||||||
id: ntfy_linux_amd64
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=1 # required for go-sqlite3
|
- CGO_ENABLED=1 # required for go-sqlite3
|
||||||
|
@ -13,8 +12,7 @@ builds:
|
||||||
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
|
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
|
||||||
goos: [linux]
|
goos: [linux]
|
||||||
goarch: [amd64]
|
goarch: [amd64]
|
||||||
-
|
- id: ntfy_linux_armv6
|
||||||
id: ntfy_linux_armv6
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=1 # required for go-sqlite3
|
- CGO_ENABLED=1 # required for go-sqlite3
|
||||||
|
@ -25,8 +23,7 @@ builds:
|
||||||
goos: [linux]
|
goos: [linux]
|
||||||
goarch: [arm]
|
goarch: [arm]
|
||||||
goarm: [6]
|
goarm: [6]
|
||||||
-
|
- id: ntfy_linux_armv7
|
||||||
id: ntfy_linux_armv7
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=1 # required for go-sqlite3
|
- CGO_ENABLED=1 # required for go-sqlite3
|
||||||
|
@ -37,8 +34,7 @@ builds:
|
||||||
goos: [linux]
|
goos: [linux]
|
||||||
goarch: [arm]
|
goarch: [arm]
|
||||||
goarm: [7]
|
goarm: [7]
|
||||||
-
|
- id: ntfy_linux_arm64
|
||||||
id: ntfy_linux_arm64
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=1 # required for go-sqlite3
|
- CGO_ENABLED=1 # required for go-sqlite3
|
||||||
|
@ -48,8 +44,7 @@ builds:
|
||||||
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
|
- "-linkmode=external -extldflags=-static -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
|
||||||
goos: [linux]
|
goos: [linux]
|
||||||
goarch: [arm64]
|
goarch: [arm64]
|
||||||
-
|
- id: ntfy_windows_amd64
|
||||||
id: ntfy_windows_amd64
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
|
- 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}}"
|
- "-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}"
|
||||||
goos: [windows]
|
goos: [windows]
|
||||||
goarch: [amd64]
|
goarch: [amd64]
|
||||||
-
|
- id: ntfy_darwin_all
|
||||||
id: ntfy_darwin_all
|
|
||||||
binary: ntfy
|
binary: ntfy
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
|
- CGO_ENABLED=0 # explicitly disable, since we don't need go-sqlite3
|
||||||
|
@ -69,8 +63,7 @@ builds:
|
||||||
goos: [darwin]
|
goos: [darwin]
|
||||||
goarch: [amd64, arm64] # will be combined to "universal binary" (see below)
|
goarch: [amd64, arm64] # will be combined to "universal binary" (see below)
|
||||||
nfpms:
|
nfpms:
|
||||||
-
|
- package_name: ntfy
|
||||||
package_name: ntfy
|
|
||||||
homepage: https://heckel.io/ntfy
|
homepage: https://heckel.io/ntfy
|
||||||
maintainer: Philipp C. Heckel <philipp.heckel@gmail.com>
|
maintainer: Philipp C. Heckel <philipp.heckel@gmail.com>
|
||||||
description: Simple pub-sub notification service
|
description: Simple pub-sub notification service
|
||||||
|
@ -104,8 +97,7 @@ nfpms:
|
||||||
preremove: "scripts/prerm.sh"
|
preremove: "scripts/prerm.sh"
|
||||||
postremove: "scripts/postrm.sh"
|
postremove: "scripts/postrm.sh"
|
||||||
archives:
|
archives:
|
||||||
-
|
- id: ntfy_linux
|
||||||
id: ntfy_linux
|
|
||||||
builds:
|
builds:
|
||||||
- ntfy_linux_amd64
|
- ntfy_linux_amd64
|
||||||
- ntfy_linux_armv6
|
- ntfy_linux_armv6
|
||||||
|
@ -121,8 +113,7 @@ archives:
|
||||||
- client/ntfy-client.service
|
- client/ntfy-client.service
|
||||||
replacements:
|
replacements:
|
||||||
amd64: x86_64
|
amd64: x86_64
|
||||||
-
|
- id: ntfy_windows
|
||||||
id: ntfy_windows
|
|
||||||
builds:
|
builds:
|
||||||
- ntfy_windows_amd64
|
- ntfy_windows_amd64
|
||||||
format: zip
|
format: zip
|
||||||
|
@ -133,8 +124,7 @@ archives:
|
||||||
- client/client.yml
|
- client/client.yml
|
||||||
replacements:
|
replacements:
|
||||||
amd64: x86_64
|
amd64: x86_64
|
||||||
-
|
- id: ntfy_darwin
|
||||||
id: ntfy_darwin
|
|
||||||
builds:
|
builds:
|
||||||
- ntfy_darwin_all
|
- ntfy_darwin_all
|
||||||
wrap_in_directory: true
|
wrap_in_directory: true
|
||||||
|
@ -145,20 +135,19 @@ archives:
|
||||||
replacements:
|
replacements:
|
||||||
darwin: macOS
|
darwin: macOS
|
||||||
universal_binaries:
|
universal_binaries:
|
||||||
-
|
- id: ntfy_darwin_all
|
||||||
id: ntfy_darwin_all
|
|
||||||
replace: true
|
replace: true
|
||||||
name_template: ntfy
|
name_template: ntfy
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: "checksums.txt"
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Tag }}-next"
|
name_template: "{{ .Tag }}-next"
|
||||||
changelog:
|
changelog:
|
||||||
sort: asc
|
sort: asc
|
||||||
filters:
|
filters:
|
||||||
exclude:
|
exclude:
|
||||||
- '^docs:'
|
- "^docs:"
|
||||||
- '^test:'
|
- "^test:"
|
||||||
dockers:
|
dockers:
|
||||||
- image_templates:
|
- image_templates:
|
||||||
- &amd64_image "binwiederhier/ntfy:{{ .Tag }}-amd64"
|
- &amd64_image "binwiederhier/ntfy:{{ .Tag }}-amd64"
|
||||||
|
|
6
.prettierignore
Normal file
6
.prettierignore
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
server/docs/
|
||||||
|
server/site/
|
||||||
|
server/mailer_emoji_map.json
|
||||||
|
scripts/emoji.json
|
||||||
|
dist/
|
||||||
|
web/
|
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"golang.go"
|
||||||
|
]
|
||||||
|
}
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
|
||||||
Examples of behavior that contributes to a positive environment for our
|
Examples of behavior that contributes to a positive environment for our
|
||||||
community include:
|
community include:
|
||||||
|
|
||||||
* Demonstrating empathy and kindness toward other people
|
- Demonstrating empathy and kindness toward other people
|
||||||
* Being respectful of differing opinions, viewpoints, and experiences
|
- Being respectful of differing opinions, viewpoints, and experiences
|
||||||
* Giving and gracefully accepting constructive feedback
|
- Giving and gracefully accepting constructive feedback
|
||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
and learning from the experience
|
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
|
community
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
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
|
any kind
|
||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
- Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or email address,
|
- Publishing others' private information, such as a physical or email address,
|
||||||
without their explicit permission
|
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
|
professional setting
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
## Enforcement Responsibilities
|
||||||
|
@ -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
|
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||||
[FAQ]: https://www.contributor-covenant.org/faq
|
[FAQ]: https://www.contributor-covenant.org/faq
|
||||||
[translations]: https://www.contributor-covenant.org/translations
|
[translations]: https://www.contributor-covenant.org/translations
|
||||||
|
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -55,6 +55,8 @@ help:
|
||||||
@echo " make coverage-upload - Upload coverage results to codecov.io"
|
@echo " make coverage-upload - Upload coverage results to codecov.io"
|
||||||
@echo
|
@echo
|
||||||
@echo "Lint/format:"
|
@echo "Lint/format:"
|
||||||
|
@echo " make format - Run prettier on config files, docs, etc excluding the web app"
|
||||||
|
@echo " make format-check - Run prettier on config files, docs, etc excluding the web app, but don't change anything"
|
||||||
@echo " make fmt - Run 'go fmt'"
|
@echo " make fmt - Run 'go fmt'"
|
||||||
@echo " make fmt-check - Run 'go fmt', but don't change anything"
|
@echo " make fmt-check - Run 'go fmt', but don't change anything"
|
||||||
@echo " make vet - Run 'go vet'"
|
@echo " make vet - Run 'go vet'"
|
||||||
|
@ -248,7 +250,7 @@ cli-build-results:
|
||||||
|
|
||||||
# Test/check targets
|
# Test/check targets
|
||||||
|
|
||||||
check: test web-format-check fmt-check vet web-lint lint staticcheck
|
check: test format-check web-format-check fmt-check vet web-lint lint staticcheck
|
||||||
|
|
||||||
test: .PHONY
|
test: .PHONY
|
||||||
go test $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
go test $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
||||||
|
@ -275,6 +277,12 @@ coverage-upload:
|
||||||
|
|
||||||
# Lint/formatting targets
|
# Lint/formatting targets
|
||||||
|
|
||||||
|
format: web-deps
|
||||||
|
./web/node_modules/.bin/prettier . --write
|
||||||
|
|
||||||
|
format-check: web-deps
|
||||||
|
./web/node_modules/.bin/prettier . --check
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
gofmt -s -w .
|
gofmt -s -w .
|
||||||
|
|
||||||
|
|
61
README.md
61
README.md
|
@ -1,6 +1,7 @@
|
||||||

|

|
||||||
|
|
||||||
# ntfy.sh | Send push notifications to your phone or desktop via PUT/POST
|
# ntfy.sh | Send push notifications to your phone or desktop via PUT/POST
|
||||||
|
|
||||||
[](https://github.com/binwiederhier/ntfy/releases/latest)
|
[](https://github.com/binwiederhier/ntfy/releases/latest)
|
||||||
[](https://pkg.go.dev/heckel.io/ntfy)
|
[](https://pkg.go.dev/heckel.io/ntfy)
|
||||||
[](https://github.com/binwiederhier/ntfy/actions)
|
[](https://github.com/binwiederhier/ntfy/actions)
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
[](https://ntfy.statuspage.io/)
|
[](https://ntfy.statuspage.io/)
|
||||||
[](https://gitpod.io/#https://github.com/binwiederhier/ntfy)
|
[](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)
|
**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,
|
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
|
**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.
|
so since ntfy is open source.
|
||||||
|
@ -31,6 +32,7 @@ as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) a
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## [ntfy Pro](https://ntfy.sh/app) 💸 🎉
|
## [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/)**
|
## **[Documentation](https://ntfy.sh/docs/)**
|
||||||
|
@ -42,21 +44,24 @@ I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self
|
||||||
[Building](https://ntfy.sh/docs/develop/)
|
[Building](https://ntfy.sh/docs/develop/)
|
||||||
|
|
||||||
## Chat / forum
|
## 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
|
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:
|
works best for you:
|
||||||
|
|
||||||
* [Discord server](https://discord.gg/cT7ECsZj9w) - direct chat with the community
|
- [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
|
- [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_)
|
- [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
|
- [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_)
|
- [Email](https://heckel.io/about) - reach me directly (_I usually prefer the other methods_)
|
||||||
|
|
||||||
## Announcements / beta testers
|
## 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,
|
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).
|
join Discord/Matrix (I'll eventually make a testing channel in Google Play).
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
I welcome any and all contributions. Just create a PR or an issue. For larger features/ideas, please reach out
|
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
|
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
|
||||||
|
@ -67,6 +72,7 @@ for the server and the Android app. Or, if you'd like to help translate 🇩🇪
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier),
|
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:
|
account costs. Even small donations are very much appreciated. A big fat **Thank You** to the folks already sponsoring ntfy:
|
||||||
|
@ -143,11 +149,12 @@ account costs. Even small donations are very much appreciated. A big fat **Thank
|
||||||
<a href="https://github.com/jonathan-kosgei"><img src="https://github.com/jonathan-kosgei.png" width="40px" /></a>
|
<a href="https://github.com/jonathan-kosgei"><img src="https://github.com/jonathan-kosgei.png" width="40px" /></a>
|
||||||
|
|
||||||
I'd also like to thank JetBrains for providing their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/) to me for free,
|
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:
|
||||||
|
|
||||||
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
|
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
|
||||||
|
|
||||||
## Code of Conduct
|
## 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 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.**
|
**We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.**
|
||||||
|
@ -155,26 +162,28 @@ We as members, contributors, and leaders pledge to make participation in our com
|
||||||
_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
|
## 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).
|
The project is dual licensed under the [Apache License 2.0](LICENSE) and the [GPLv2 License](LICENSE.GPLv2).
|
||||||
|
|
||||||
Third party libraries and resources:
|
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
|
- [github.com/urfave/cli](https://github.com/urfave/cli) (MIT) is used to drive the CLI
|
||||||
* [Sounds from notificationsounds.com](https://notificationsounds.com) (Creative Commons Attribution) are used as notification sounds
|
- [Mixkit sounds](https://mixkit.co/free-sound-effects/notification/) (Mixkit Free License) are used as notification sounds
|
||||||
* [Roboto Font](https://fonts.google.com/specimen/Roboto) (Apache 2.0) is used as a font in everything web
|
- [Sounds from notificationsounds.com](https://notificationsounds.com) (Creative Commons Attribution) are used as notification sounds
|
||||||
* [React](https://reactjs.org/) (MIT) is used for the web app
|
- [Roboto Font](https://fonts.google.com/specimen/Roboto) (Apache 2.0) is used as a font in everything web
|
||||||
* [Material UI components](https://mui.com/) (MIT) are used in the web app
|
- [React](https://reactjs.org/) (MIT) is used for 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
|
- [Material UI components](https://mui.com/) (MIT) are used in the web app
|
||||||
* [Dexie.js](https://github.com/dexie/Dexie.js) (Apache 2.0) is used for web app persistence in IndexedDB
|
- [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
|
||||||
* [GoReleaser](https://goreleaser.com/) (MIT) is used to create releases
|
- [Dexie.js](https://github.com/dexie/Dexie.js) (Apache 2.0) is used for web app persistence in IndexedDB
|
||||||
* [go-smtp](https://github.com/emersion/go-smtp) (MIT) is used to receive e-mails
|
- [GoReleaser](https://goreleaser.com/) (MIT) is used to create releases
|
||||||
* [stretchr/testify](https://github.com/stretchr/testify) (MIT) is used for unit and integration tests
|
- [go-smtp](https://github.com/emersion/go-smtp) (MIT) is used to receive e-mails
|
||||||
* [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
|
- [stretchr/testify](https://github.com/stretchr/testify) (MIT) is used for unit and integration tests
|
||||||
* [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
|
- [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) (MIT) is used to provide the persistent message cache
|
||||||
* [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)
|
- [Firebase Admin SDK](https://github.com/firebase/firebase-admin-go) (Apache 2.0) is used to send FCM messages
|
||||||
* [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page
|
- [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)
|
||||||
* [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files
|
- [Lightbox with vanilla JS](https://yossiabramov.com/blog/vanilla-js-lightbox) as a lightbox on the landing page
|
||||||
* [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
|
- [HTTP middleware for gzip compression](https://gist.github.com/CJEnright/bc2d8b8dc0c1389a9feeddb110f822d7) (MIT) is used for serving static files
|
||||||
* [Statically linking go-sqlite3](https://www.arp242.net/static-go.html)
|
- [Regex for auto-linking](https://github.com/bryanwoods/autolink-js) (MIT) is used to highlight links (the library is not used)
|
||||||
* [Linked tabs in mkdocs](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs)
|
- [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)
|
||||||
|
|
|
@ -14,4 +14,3 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %} {% block announce %}
|
||||||
|
|
||||||
{% block announce %}
|
|
||||||
<style>
|
<style>
|
||||||
div[data-md-component="announce"] {
|
div[data-md-component="announce"] {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
@ -10,7 +8,8 @@
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
div[data-md-component="announce"] a:hover, div[data-md-component="announce"] a:focus {
|
div[data-md-component="announce"] a:hover,
|
||||||
|
div[data-md-component="announce"] a:focus {
|
||||||
transition: ease-in 150ms;
|
transition: ease-in 150ms;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
@ -27,24 +26,52 @@
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<button id="announce-bar-close" class="md-banner__button md-icon" aria-label="Don't show this again">
|
<button
|
||||||
|
id="announce-bar-close"
|
||||||
|
class="md-banner__button md-icon"
|
||||||
|
aria-label="Don't show this again"
|
||||||
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"></path>
|
<path
|
||||||
|
d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"
|
||||||
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
If you like ntfy, please consider sponsoring me via <a target="_blank" href="https://github.com/sponsors/binwiederhier"><strong>GitHub Sponsors</strong></a>
|
If you like ntfy, please consider sponsoring me via
|
||||||
or <a target="_blank" href="https://en.liberapay.com/ntfy/"><strong>Liberapay</strong></a>
|
<a target="_blank" href="https://github.com/sponsors/binwiederhier"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 36 36" class="twemoji md-footer-custom-text">
|
><strong>GitHub Sponsors</strong></a
|
||||||
<path fill="#DD2E44" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"/>
|
>
|
||||||
</svg>, or subscribing to <a target="_blank" href="https://ntfy.sh/app"><strong>ntfy Pro</strong></a>.
|
or
|
||||||
|
<a target="_blank" href="https://en.liberapay.com/ntfy/"
|
||||||
|
><strong>Liberapay</strong></a
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 36 36"
|
||||||
|
class="twemoji md-footer-custom-text"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#DD2E44"
|
||||||
|
d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"
|
||||||
|
/></svg
|
||||||
|
>, or subscribing to
|
||||||
|
<a target="_blank" href="https://ntfy.sh/app"><strong>ntfy Pro</strong></a
|
||||||
|
>.
|
||||||
<script>
|
<script>
|
||||||
announceBarKey = 'announce-bar-closed-sponsor';
|
announceBarKey = "announce-bar-closed-sponsor";
|
||||||
document.getElementById('announce-bar-close').addEventListener('click', (e) => {
|
document
|
||||||
localStorage.setItem(announceBarKey, 'true');
|
.getElementById("announce-bar-close")
|
||||||
document.querySelector('div[data-md-component="announce"] .md-banner').style.display = 'none';
|
.addEventListener("click", (e) => {
|
||||||
|
localStorage.setItem(announceBarKey, "true");
|
||||||
|
document.querySelector(
|
||||||
|
'div[data-md-component="announce"] .md-banner'
|
||||||
|
).style.display = "none";
|
||||||
});
|
});
|
||||||
if (localStorage.getItem(announceBarKey) === 'true') {
|
if (localStorage.getItem(announceBarKey) === "true") {
|
||||||
document.querySelector('div[data-md-component="announce"] .md-banner').style.display = 'none';
|
document.querySelector(
|
||||||
|
'div[data-md-component="announce"] .md-banner'
|
||||||
|
).style.display = "none";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
314
docs/config.md
314
docs/config.md
|
@ -1,11 +1,14 @@
|
||||||
# Configuring the ntfy server
|
# Configuring the ntfy server
|
||||||
|
|
||||||
The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`,
|
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
|
see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)), via command line arguments
|
||||||
or using environment variables.
|
or using environment variables.
|
||||||
|
|
||||||
## Quick start
|
## 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:
|
If everything works as it should, you'll see something like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ntfy serve
|
$ ntfy serve
|
||||||
2021/11/30 19:59:08 Listening on :80
|
2021/11/30 19:59:08 Listening on :80
|
||||||
|
@ -17,6 +20,7 @@ the server further, check out the [config options table](#config-options) or sim
|
||||||
get a list of [command line options](#command-line-options).
|
get a list of [command line options](#command-line-options).
|
||||||
|
|
||||||
## Example config
|
## Example config
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
Definitely check out the **[server.yml](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml)** file.
|
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.
|
It contains examples and detailed descriptions of all the settings.
|
||||||
|
@ -27,6 +31,7 @@ and `listen-https`), and socket path (`listen-unix`). All the other things are a
|
||||||
Here are a few working sample configs:
|
Here are a few working sample configs:
|
||||||
|
|
||||||
=== "server.yml (HTTP-only, with cache + attachments)"
|
=== "server.yml (HTTP-only, with cache + attachments)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
base-url: "http://ntfy.example.com"
|
base-url: "http://ntfy.example.com"
|
||||||
cache-file: "/var/cache/ntfy/cache.db"
|
cache-file: "/var/cache/ntfy/cache.db"
|
||||||
|
@ -34,6 +39,7 @@ Here are a few working sample configs:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "server.yml (HTTP+HTTPS, with cache + attachments)"
|
=== "server.yml (HTTP+HTTPS, with cache + attachments)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
base-url: "http://ntfy.example.com"
|
base-url: "http://ntfy.example.com"
|
||||||
listen-http: ":80"
|
listen-http: ":80"
|
||||||
|
@ -45,6 +51,7 @@ Here are a few working sample configs:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "server.yml (ntfy.sh config)"
|
=== "server.yml (ntfy.sh config)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# All the things: Behind a proxy, Firebase, cache, attachments,
|
# All the things: Behind a proxy, Firebase, cache, attachments,
|
||||||
# SMTP publishing & receiving
|
# SMTP publishing & receiving
|
||||||
|
@ -66,6 +73,7 @@ Here are a few working sample configs:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Message cache
|
## Message cache
|
||||||
|
|
||||||
If desired, ntfy can temporarily keep notifications in an in-memory or an on-disk cache. Caching messages for a short period
|
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
|
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.
|
||||||
|
@ -73,9 +81,9 @@ 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
|
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:
|
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**.
|
**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
|
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
|
passed on to the connected subscribers, but never stored on disk or even kept in memory longer than is needed to forward
|
||||||
|
@ -85,6 +93,7 @@ Subscribers can retrieve cached messaging using the [`poll=1` parameter](subscri
|
||||||
[`since=` parameter](subscribe/api.md#fetch-cached-messages).
|
[`since=` parameter](subscribe/api.md#fetch-cached-messages).
|
||||||
|
|
||||||
## Attachments
|
## Attachments
|
||||||
|
|
||||||
If desired, you may allow users to upload and [attach files to notifications](publish.md#attachments). To enable
|
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.
|
Once these options are set and the directory is writable by the server user, you can upload attachments via PUT.
|
||||||
|
@ -93,21 +102,23 @@ By default, attachments are stored in the disk-cache **for only 3 hours**. The m
|
||||||
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:
|
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
|
- `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-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-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-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)
|
- `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)"
|
=== "/etc/ntfy/server.yml (minimal)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
base-url: "https://ntfy.sh"
|
base-url: "https://ntfy.sh"
|
||||||
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "/etc/ntfy/server.yml (all options)"
|
=== "/etc/ntfy/server.yml (all options)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
base-url: "https://ntfy.sh"
|
base-url: "https://ntfy.sh"
|
||||||
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
||||||
|
@ -122,6 +133,7 @@ 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.
|
and `visitor-attachment-daily-bandwidth-limit`. Setting these conservatively is necessary to avoid abuse.
|
||||||
|
|
||||||
## Access control
|
## Access control
|
||||||
|
|
||||||
By default, the ntfy server is open for everyone, meaning **everyone can read and write to any topic** (this is how
|
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.sh is configured). To restrict access to your own server, you can optionally configure authentication and authorization.
|
||||||
|
|
||||||
|
@ -131,9 +143,9 @@ Access control entries can be applied to users as well as the special everyone u
|
||||||
|
|
||||||
To set up auth, simply **configure the following two options**:
|
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)
|
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`.
|
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
|
Once configured, you can use the `ntfy user` command to [add or modify users](#users-and-roles), and the `ntfy access` command
|
||||||
|
@ -142,15 +154,16 @@ commands **directly edit the auth database** (as defined in `auth-file`), so the
|
||||||
accessing them has the right permissions.
|
accessing them has the right permissions.
|
||||||
|
|
||||||
### Users and roles
|
### Users and roles
|
||||||
|
|
||||||
The `ntfy user` command allows you to add/remove/change users in the ntfy user database, as well as change
|
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)).
|
user with `ntfy user add --role=admin ...` and be done with all this (see [example below](#example-private-instance)).
|
||||||
|
|
||||||
**Roles:**
|
**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)).
|
(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):
|
**Example commands** (type `ntfy user --help` or `ntfy user COMMAND --help` for more details):
|
||||||
|
|
||||||
|
@ -165,6 +178,7 @@ ntfy user change-tier phil pro # Change phil's tier to "pro"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Access control list (ACL)
|
### Access control list (ACL)
|
||||||
|
|
||||||
The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access (`everyone`/`*`)**.
|
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.
|
||||||
|
|
||||||
|
@ -185,13 +199,14 @@ number of characters.
|
||||||
|
|
||||||
A `PERMISSION` is any of the following supported permissions:
|
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
|
[subscribing](subscribe/api.md) and reading messages
|
||||||
* `read-only` (aliases: `read`, `ro`): Allows only subscribing and reading messages, but not publishing to the 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
|
- `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
|
- `deny` (alias: `none`): Allows neither publishing nor subscribing to a topic
|
||||||
|
|
||||||
**Example commands** (type `ntfy access --help` for more details):
|
**Example commands** (type `ntfy access --help` for more details):
|
||||||
|
|
||||||
```
|
```
|
||||||
ntfy access # Shows entire access control list
|
ntfy access # Shows entire access control list
|
||||||
ntfy access phil # Shows access for user phil
|
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:**
|
**Example ACL:**
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ntfy access
|
$ ntfy access
|
||||||
user phil (admin)
|
user phil (admin)
|
||||||
|
@ -224,6 +240,7 @@ 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.
|
(called `*`/`everyone`) only have read access to the `announcements` and `server-stats` topics.
|
||||||
|
|
||||||
### Access tokens
|
### Access tokens
|
||||||
|
|
||||||
In addition to username/password auth, ntfy also provides authentication via access tokens. Access tokens are useful
|
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
|
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.
|
want to use a dedicated token to publish from your backup host, and one from your home automation system.
|
||||||
|
@ -237,7 +254,8 @@ The `ntfy token` command can be used to manage access tokens for users. Tokens c
|
||||||
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):
|
**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 # Shows list of tokens for all users
|
||||||
ntfy token list phil # Shows list of tokens for user phil
|
ntfy token list phil # Shows list of tokens for user phil
|
||||||
ntfy token add phil # Create token for user phil which never expires
|
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:**
|
**Creating an access token:**
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy token add --expires=30d --label="backups" phil
|
$ ntfy token add --expires=30d --label="backups" phil
|
||||||
$ ntfy token list
|
$ ntfy token list
|
||||||
user phil
|
user phil
|
||||||
|
@ -257,9 +276,11 @@ 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).
|
subscribe to topics**. To learn how, check out [authenticate via access tokens](publish.md#access-tokens).
|
||||||
|
|
||||||
### Example: Private instance
|
### Example: Private instance
|
||||||
|
|
||||||
The easiest way to configure a private instance is to set `auth-default-access` to `deny-all` in the `server.yml`:
|
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"
|
=== "/etc/ntfy/server.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
auth-file: "/var/lib/ntfy/user.db"
|
auth-file: "/var/lib/ntfy/user.db"
|
||||||
auth-default-access: "deny-all"
|
auth-default-access: "deny-all"
|
||||||
|
@ -267,7 +288,7 @@ The easiest way to configure a private instance is to set `auth-default-access`
|
||||||
|
|
||||||
After that, simply create an `admin` user:
|
After that, simply create an `admin` user:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ ntfy user add --role=admin phil
|
$ ntfy user add --role=admin phil
|
||||||
password: mypass
|
password: mypass
|
||||||
confirm: mypass
|
confirm: mypass
|
||||||
|
@ -278,7 +299,8 @@ Once you've done that, you can publish and subscribe using [Basic Auth](https://
|
||||||
with the given username/password. Be sure to use HTTPS to avoid eavesdropping and exposing your password. Here's a simple example:
|
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)"
|
=== "Command line (curl)"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
curl \
|
curl \
|
||||||
-u phil:mypass \
|
-u phil:mypass \
|
||||||
-d "Look ma, with auth" \
|
-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"
|
=== "ntfy CLI"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy publish \
|
ntfy publish \
|
||||||
-u phil:mypass \
|
-u phil:mypass \
|
||||||
ntfy.example.com/mysecrets \
|
ntfy.example.com/mysecrets \
|
||||||
|
@ -294,7 +317,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
``` http
|
|
||||||
|
```sh
|
||||||
POST /mysecrets HTTP/1.1
|
POST /mysecrets HTTP/1.1
|
||||||
Host: ntfy.example.com
|
Host: ntfy.example.com
|
||||||
Authorization: Basic cGhpbDpteXBhc3M=
|
Authorization: Basic cGhpbDpteXBhc3M=
|
||||||
|
@ -303,7 +327,8 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JavaScript"
|
=== "JavaScript"
|
||||||
``` javascript
|
|
||||||
|
```js
|
||||||
fetch('https://ntfy.example.com/mysecrets', {
|
fetch('https://ntfy.example.com/mysecrets', {
|
||||||
method: 'POST', // PUT works too
|
method: 'POST', // PUT works too
|
||||||
body: 'Look ma, with auth',
|
body: 'Look ma, with auth',
|
||||||
|
@ -314,6 +339,7 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Go"
|
=== "Go"
|
||||||
|
|
||||||
```go
|
```go
|
||||||
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
|
req, _ := http.NewRequest("POST", "https://ntfy.example.com/mysecrets",
|
||||||
strings.NewReader("Look ma, with auth"))
|
strings.NewReader("Look ma, with auth"))
|
||||||
|
@ -322,6 +348,7 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
|
|
||||||
```python
|
```python
|
||||||
requests.post("https://ntfy.example.com/mysecrets",
|
requests.post("https://ntfy.example.com/mysecrets",
|
||||||
data="Look ma, with auth",
|
data="Look ma, with auth",
|
||||||
|
@ -331,6 +358,7 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "PHP"
|
=== "PHP"
|
||||||
|
|
||||||
```php-inline
|
```php-inline
|
||||||
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
|
file_get_contents('https://ntfy.example.com/mysecrets', false, stream_context_create([
|
||||||
'http' => [
|
'http' => [
|
||||||
|
@ -344,6 +372,7 @@ with the given username/password. Be sure to use HTTPS to avoid eavesdropping an
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example: UnifiedPush
|
### Example: UnifiedPush
|
||||||
|
|
||||||
[UnifiedPush](https://unifiedpush.org) requires that the [application server](https://unifiedpush.org/spec/definitions/#application-server) (e.g. Synapse, Fediverse Server, …)
|
[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.
|
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
|
The topic names used by UnifiedPush all start with the `up*` prefix. Please refer to the
|
||||||
|
@ -353,16 +382,19 @@ To enable support for UnifiedPush for private servers (i.e. `auth-default-access
|
||||||
allow anonymous write access for the entire prefix or explicitly per topic:
|
allow anonymous write access for the entire prefix or explicitly per topic:
|
||||||
|
|
||||||
=== "Prefix"
|
=== "Prefix"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy access '*' 'up*' write-only
|
$ ntfy access '*' 'up*' write-only
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Explicitly"
|
=== "Explicitly"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy access '*' upYzMtZGZiYTY5 write-only
|
$ ntfy access '*' upYzMtZGZiYTY5 write-only
|
||||||
```
|
```
|
||||||
|
|
||||||
## E-mail notifications
|
## E-mail notifications
|
||||||
|
|
||||||
To allow forwarding messages via e-mail, you can configure an **SMTP server for outgoing messages**. Once configured,
|
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.
|
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`).
|
`curl -d "hi there" -H "X-Email: phil@example.com" ntfy.sh/mytopic`).
|
||||||
|
@ -370,15 +402,16 @@ you can set the `X-Email` header to [send messages via e-mail](publish.md#e-mail
|
||||||
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:
|
following settings:
|
||||||
|
|
||||||
* `base-url` is the root URL for the ntfy server; this is needed for e-mail footer
|
- `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-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-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
|
- `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`):
|
configured for `ntfy.sh`):
|
||||||
|
|
||||||
=== "/etc/ntfy/server.yml"
|
=== "/etc/ntfy/server.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
base-url: "https://ntfy.sh"
|
base-url: "https://ntfy.sh"
|
||||||
smtp-sender-addr: "email-smtp.us-east-2.amazonaws.com:587"
|
smtp-sender-addr: "email-smtp.us-east-2.amazonaws.com:587"
|
||||||
|
@ -391,6 +424,7 @@ Please also refer to the [rate limiting](#rate-limiting) settings below, specifi
|
||||||
and `visitor-email-limit-burst`. Setting these conservatively is necessary to avoid abuse.
|
and `visitor-email-limit-burst`. Setting these conservatively is necessary to avoid abuse.
|
||||||
|
|
||||||
## E-mail publishing
|
## E-mail publishing
|
||||||
|
|
||||||
To allow publishing messages via e-mail, ntfy can run a lightweight **SMTP server for incoming messages**. Once configured,
|
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
|
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
|
`myprefix-mytopic@ntfy.sh`) to publish messages to a topic. This is useful for e-mail based integrations such as for
|
||||||
|
@ -398,15 +432,16 @@ statuspage.io (though these days most services also support webhooks and HTTP ca
|
||||||
|
|
||||||
To configure the SMTP server, you must at least set `smtp-server-listen` and `smtp-server-domain`:
|
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-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-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-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
|
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).
|
accepted (which may obviously be a spam problem).
|
||||||
|
|
||||||
Here's an example config (this is how it is configured for `ntfy.sh`):
|
Here's an example config (this is how it is configured for `ntfy.sh`):
|
||||||
|
|
||||||
=== "/etc/ntfy/server.yml"
|
=== "/etc/ntfy/server.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
smtp-server-listen: ":25"
|
smtp-server-listen: ":25"
|
||||||
smtp-server-domain: "ntfy.sh"
|
smtp-server-domain: "ntfy.sh"
|
||||||
|
@ -440,7 +475,7 @@ 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.
|
ntfy server. Read them carefully.
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ cat email.txt | nc -N ntfy.sh 25
|
$ cat email.txt | nc -N ntfy.sh 25
|
||||||
220 ntfy.sh ESMTP Service Ready
|
220 ntfy.sh ESMTP Service Ready
|
||||||
250-Hello example.com
|
250-Hello example.com
|
||||||
|
@ -451,7 +486,7 @@ $ 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:
|
As for the DNS setup, be sure to verify that `dig MX` and `dig A` are returning results similar to this:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ dig MX ntfy.sh +short
|
$ dig MX ntfy.sh +short
|
||||||
10 mx1.ntfy.sh.
|
10 mx1.ntfy.sh.
|
||||||
$ dig A mx1.ntfy.sh +short
|
$ dig A mx1.ntfy.sh +short
|
||||||
|
@ -459,6 +494,7 @@ $ dig A mx1.ntfy.sh +short
|
||||||
```
|
```
|
||||||
|
|
||||||
## Behind a proxy (TLS, etc.)
|
## Behind a proxy (TLS, etc.)
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
If you are running ntfy behind a proxy, you must set the `behind-proxy` flag. Otherwise, all visitors are
|
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.
|
[rate limited](#rate-limiting) as if they are one.
|
||||||
|
@ -473,12 +509,14 @@ as opposed to the remote IP address. If the `behind-proxy` flag is not set, all
|
||||||
be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address.
|
be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address.
|
||||||
|
|
||||||
=== "/etc/ntfy/server.yml"
|
=== "/etc/ntfy/server.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Tell ntfy to use "X-Forwarded-For" to identify visitors
|
# Tell ntfy to use "X-Forwarded-For" to identify visitors
|
||||||
behind-proxy: true
|
behind-proxy: true
|
||||||
```
|
```
|
||||||
|
|
||||||
### TLS/SSL
|
### 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).
|
are behind a proxy, it is recommended that TLS/SSL termination is done by the proxy itself (see below).
|
||||||
|
|
||||||
|
@ -488,6 +526,7 @@ HTTP challenge. I've found [this guide](https://nandovieira.com/using-lets-encry
|
||||||
be incredibly helpful.
|
be incredibly helpful.
|
||||||
|
|
||||||
### nginx/Apache2/caddy
|
### nginx/Apache2/caddy
|
||||||
|
|
||||||
For your convenience, here's a working config that'll help configure things behind a proxy. Be sure to **enable WebSockets**
|
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.
|
||||||
|
|
||||||
|
@ -495,6 +534,7 @@ In this example, ntfy runs on `:2586` and we proxy traffic to it. We also redire
|
||||||
or the root domain:
|
or the root domain:
|
||||||
|
|
||||||
=== "nginx (convenient)"
|
=== "nginx (convenient)"
|
||||||
|
|
||||||
```
|
```
|
||||||
# /etc/nginx/sites-*/ntfy
|
# /etc/nginx/sites-*/ntfy
|
||||||
#
|
#
|
||||||
|
@ -580,6 +620,7 @@ or the root domain:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "nginx (more secure)"
|
=== "nginx (more secure)"
|
||||||
|
|
||||||
```
|
```
|
||||||
# /etc/nginx/sites-*/ntfy
|
# /etc/nginx/sites-*/ntfy
|
||||||
#
|
#
|
||||||
|
@ -643,6 +684,7 @@ or the root domain:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Apache2"
|
=== "Apache2"
|
||||||
|
|
||||||
```
|
```
|
||||||
# /etc/apache2/sites-*/ntfy.conf
|
# /etc/apache2/sites-*/ntfy.conf
|
||||||
|
|
||||||
|
@ -702,6 +744,7 @@ or the root domain:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "caddy"
|
=== "caddy"
|
||||||
|
|
||||||
```
|
```
|
||||||
# Note that this config is most certainly incomplete. Please help out and let me know what's missing
|
# 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.
|
# via Discord/Matrix or in a GitHub issue.
|
||||||
|
@ -721,6 +764,7 @@ or the root domain:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Firebase (FCM)
|
## Firebase (FCM)
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
Using Firebase is **optional** and only works if you modify and [build your own Android .apk](develop.md#android-app).
|
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.
|
For a self-hosted instance, it's easier to just not bother with FCM.
|
||||||
|
@ -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)
|
4. Build your own Android .apk following [these instructions](develop.md#android-app)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
|
||||||
|
```yaml
|
||||||
# If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app.
|
# 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).
|
# This is optional and only required to support Android apps (which don't allow background services anymore).
|
||||||
#
|
#
|
||||||
|
@ -748,6 +793,7 @@ firebase-key-file: "/etc/ntfy/ntfy-sh-firebase-adminsdk-ahnce-9f4d6f14b5.json"
|
||||||
```
|
```
|
||||||
|
|
||||||
## iOS instant notifications
|
## iOS instant notifications
|
||||||
|
|
||||||
Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant
|
Unlike Android, iOS heavily restricts background processing, which sadly makes it impossible to implement instant
|
||||||
push notifications without a central server.
|
push notifications without a central server.
|
||||||
|
|
||||||
|
@ -780,7 +826,7 @@ In case you're curious, here's an example of the entire flow:
|
||||||
|
|
||||||
Here's an example of what the self-hosted server forwards to the upstream server. The request is equivalent to this curl:
|
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
|
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"}
|
{"id":"4HsClFEuCIcs","time":1654087955,"event":"poll_request","topic":"6de73be8dfb7d69e32fb2c00c23fe7adbd8b5504406e3068c273aa24cef4055b","message":"New message","poll_id":"s4PdJozxM8na"}
|
||||||
```
|
```
|
||||||
|
@ -790,6 +836,7 @@ may be `Some other message`. This is so that if iOS cannot talk to the self-host
|
||||||
it'll show `New message` as a popup.
|
it'll show `New message` as a popup.
|
||||||
|
|
||||||
## Tiers
|
## 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),
|
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
|
tiers can be paid or unpaid, and users can upgrade/downgrade between them. If payments are disabled, then the only way
|
||||||
|
@ -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.
|
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):
|
**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 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 change --name="Pro" pro # Update the name of an existing tier
|
||||||
ntfy tier del starter # Delete 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):**
|
**Creating a tier (full example):**
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy tier add \
|
ntfy tier add \
|
||||||
--name="Pro" \
|
--name="Pro" \
|
||||||
--message-limit=10000 \
|
--message-limit=10000 \
|
||||||
|
@ -826,6 +875,7 @@ ntfy tier add \
|
||||||
```
|
```
|
||||||
|
|
||||||
## Payments
|
## Payments
|
||||||
|
|
||||||
ntfy supports paid [tiers](#tiers) via [Stripe](https://stripe.com/) as a payment provider. If payments are enabled,
|
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).
|
are enabled (e.g. showing an upgrade banner, or "ntfy Pro" tags).
|
||||||
|
@ -837,11 +887,11 @@ are enabled (e.g. showing an upgrade banner, or "ntfy Pro" tags).
|
||||||
To enable payments, sign up with [Stripe](https://stripe.com/), set the `stripe-secret-key` and `stripe-webhook-key`
|
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
|
- `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).
|
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.
|
- `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).
|
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
|
- `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.
|
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)
|
In addition to setting these two options, you also need to define a [Stripe webhook](https://dashboard.stripe.com/webhooks)
|
||||||
|
@ -857,6 +907,7 @@ billing-contact: "phil@example.com"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Phone calls
|
## Phone calls
|
||||||
|
|
||||||
ntfy supports phone calls via [Twilio](https://www.twilio.com/) as a call provider. If phone calls are enabled,
|
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.
|
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.
|
See [publishing page](publish.md#phone-calls) for more details.
|
||||||
|
@ -864,15 +915,16 @@ 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
|
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:
|
are the easiest), and then configure the following options:
|
||||||
|
|
||||||
* `twilio-account` is the Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586
|
- `twilio-account` is the Twilio account SID, e.g. AC12345beefbeef67890beefbeef122586
|
||||||
* `twilio-auth-token` is the Twilio auth token, e.g. affebeef258625862586258625862586
|
- `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-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-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 ...`),
|
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.
|
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
|
## Rate limiting
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
Be aware that if you are running ntfy behind a proxy, you must set the `behind-proxy` flag.
|
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.
|
Otherwise, all visitors are rate limited as if they are one.
|
||||||
|
@ -880,8 +932,8 @@ and then assign it to a user. Users may then use the `X-Call` header to receive
|
||||||
By default, ntfy runs without authentication, so it is vitally important that we protect the server from abuse or overload.
|
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:
|
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)
|
- **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
|
- **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
|
(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.
|
only on a per-visitor basis.
|
||||||
|
|
||||||
|
@ -889,12 +941,14 @@ During normal usage, you shouldn't encounter these limits at all, and even if yo
|
||||||
(e.g. when you reconnect after a connection drop), it shouldn't have any effect.
|
(e.g. when you reconnect after a connection drop), it shouldn't have any effect.
|
||||||
|
|
||||||
### General limits
|
### General limits
|
||||||
|
|
||||||
Let's do the easy limits first:
|
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.
|
- `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.
|
- `visitor-subscription-limit` is the number of subscriptions (open connections) per visitor. This value defaults to 30.
|
||||||
|
|
||||||
### Request limits
|
### Request limits
|
||||||
|
|
||||||
In addition to the limits above, there is a requests/second limit per visitor for all sensitive GET/PUT/POST requests.
|
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)):
|
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)):
|
||||||
|
|
||||||
|
@ -902,12 +956,13 @@ Each visitor has a bucket of 60 requests they can fire against the server (defin
|
||||||
After the 60, new requests will encounter a `429 Too Many Requests` response. The visitor request bucket is refilled at a rate of one
|
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`)
|
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-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-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-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.
|
limiting; hostnames are resolved at the time the server is started. Defaults to an empty list.
|
||||||
|
|
||||||
### Message limits
|
### 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
|
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 publish messages, then that is the daily message limit.
|
||||||
|
@ -916,24 +971,27 @@ To limit the number of daily messages per visitor, you can set `visitor-message-
|
||||||
of messages a visitor can send in a day. This counter is reset every day at midnight (UTC).
|
of messages a visitor can send in a day. This counter is reset every day at midnight (UTC).
|
||||||
|
|
||||||
### Attachment limits
|
### 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:
|
per-visitor limits:
|
||||||
|
|
||||||
* `visitor-attachment-total-size-limit` is the total storage limit used for attachments per visitor. It defaults to 100M.
|
- `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`,
|
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.
|
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-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
|
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.
|
most cloud providers. This defaults to 500M.
|
||||||
|
|
||||||
### E-mail limits
|
### 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):
|
are enabled):
|
||||||
|
|
||||||
* `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16.
|
- `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-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h.
|
||||||
|
|
||||||
### Firebase limits
|
### 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)
|
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
|
on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time
|
||||||
|
@ -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.
|
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:
|
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
|
WARN Firebase quota exceeded (likely for topic), temporarily denying Firebase access to visitor
|
||||||
```
|
```
|
||||||
|
|
||||||
### Subscriber-based rate limiting
|
### Subscriber-based rate limiting
|
||||||
|
|
||||||
By default, ntfy puts almost all rate limits on the message publisher, e.g. number of messages, requests, and attachment
|
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
|
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.**
|
of a topic's subscriber, instead of the limits of the publisher.**
|
||||||
|
@ -970,14 +1030,16 @@ response if no "rate visitor" has been previously registered. This is to avoid b
|
||||||
To enable subscriber-based rate limiting, set `visitor-subscriber-rate-limiting: true`.
|
To enable subscriber-based rate limiting, set `visitor-subscriber-rate-limiting: true`.
|
||||||
|
|
||||||
## Tuning for scale
|
## 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 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**.
|
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
|
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/).
|
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
|
### Message cache
|
||||||
|
|
||||||
By default, the [message cache](#message-cache) (defined by `cache-file`) uses the SQLite default settings, which means it
|
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,
|
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.
|
||||||
|
@ -1001,36 +1063,42 @@ cache-startup-queries: |
|
||||||
```
|
```
|
||||||
|
|
||||||
### For systemd services
|
### For systemd services
|
||||||
|
|
||||||
If you're running ntfy in a systemd service (e.g. for .deb/.rpm packages), the main limiting factor is the
|
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
|
`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`
|
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.
|
is not relevant.
|
||||||
|
|
||||||
=== "/etc/systemd/system/ntfy.service.d/override.conf"
|
=== "/etc/systemd/system/ntfy.service.d/override.conf"
|
||||||
```
|
|
||||||
|
```ini
|
||||||
# Allow 20,000 ntfy connections (and give room for other file handles)
|
# Allow 20,000 ntfy connections (and give room for other file handles)
|
||||||
[Service]
|
[Service]
|
||||||
LimitNOFILE=20500
|
LimitNOFILE=20500
|
||||||
```
|
```
|
||||||
|
|
||||||
### Outside of systemd
|
### Outside of systemd
|
||||||
|
|
||||||
If you're running outside systemd, you may want to adjust your `/etc/security/limits.conf` file to
|
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
|
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`.
|
by running `ulimit -n`, or manually override it temporarily by running `ulimit -n 50000`.
|
||||||
|
|
||||||
=== "/etc/security/limits.conf"
|
=== "/etc/security/limits.conf"
|
||||||
|
|
||||||
```
|
```
|
||||||
# Increase open files limit globally
|
# Increase open files limit globally
|
||||||
* hard nofile 20500
|
* hard nofile 20500
|
||||||
```
|
```
|
||||||
|
|
||||||
### Proxy limits (nginx, Apache2)
|
### 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
|
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
|
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
|
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.
|
to maintain the client connection and the connection to ntfy.
|
||||||
|
|
||||||
=== "/etc/nginx/nginx.conf"
|
=== "/etc/nginx/nginx.conf"
|
||||||
|
|
||||||
```
|
```
|
||||||
events {
|
events {
|
||||||
# Allow 40,000 proxy connections (2x of the desired ntfy connection count;
|
# 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"
|
=== "/etc/systemd/system/nginx.service.d/override.conf"
|
||||||
|
|
||||||
```
|
```
|
||||||
# Allow 40,000 proxy connections (2x of the desired ntfy connection count;
|
# Allow 40,000 proxy connections (2x of the desired ntfy connection count;
|
||||||
# and give room for other file handles)
|
# and give room for other file handles)
|
||||||
|
@ -1048,6 +1117,7 @@ to maintain the client connection and the connection to ntfy.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Banning bad actors (fail2ban)
|
### 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/)
|
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
|
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.
|
to ban client IPs if they misbehave. This is on top of the [rate limiting](#rate-limiting) inside the ntfy server.
|
||||||
|
@ -1056,6 +1126,7 @@ Here's an example for how ntfy.sh is configured, following the instructions from
|
||||||
and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-attack/)):
|
and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-attack/)):
|
||||||
|
|
||||||
=== "/etc/nginx/nginx.conf"
|
=== "/etc/nginx/nginx.conf"
|
||||||
|
|
||||||
```
|
```
|
||||||
# Rate limit all IP addresses
|
# Rate limit all IP addresses
|
||||||
http {
|
http {
|
||||||
|
@ -1079,6 +1150,7 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "/etc/nginx/sites-enabled/ntfy.sh"
|
=== "/etc/nginx/sites-enabled/ntfy.sh"
|
||||||
|
|
||||||
```
|
```
|
||||||
# For each server/location block
|
# For each server/location block
|
||||||
server {
|
server {
|
||||||
|
@ -1089,6 +1161,7 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "/etc/fail2ban/filter.d/nginx-req-limit.conf"
|
=== "/etc/fail2ban/filter.d/nginx-req-limit.conf"
|
||||||
|
|
||||||
```
|
```
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = limiting requests, excess:.* by zone.*client: <HOST>
|
failregex = limiting requests, excess:.* by zone.*client: <HOST>
|
||||||
|
@ -1096,7 +1169,8 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "/etc/fail2ban/jail.local"
|
=== "/etc/fail2ban/jail.local"
|
||||||
```
|
|
||||||
|
```ini
|
||||||
[nginx-req-limit]
|
[nginx-req-limit]
|
||||||
enabled = true
|
enabled = true
|
||||||
filter = nginx-req-limit
|
filter = nginx-req-limit
|
||||||
|
@ -1108,6 +1182,7 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
|
||||||
```
|
```
|
||||||
|
|
||||||
## Health checks
|
## Health checks
|
||||||
|
|
||||||
A preliminary health check API endpoint is exposed at `/v1/health`. The endpoint returns a `json` response in the format shown below.
|
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.
|
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.
|
||||||
|
|
||||||
|
@ -1118,6 +1193,7 @@ If a non-200 HTTP status code is returned or if the returned `health` field is `
|
||||||
See [Installation for Docker](install.md#docker) for an example of how this could be used in a `docker-compose` environment.
|
See [Installation for Docker](install.md#docker) for an example of how this could be used in a `docker-compose` environment.
|
||||||
|
|
||||||
## Monitoring
|
## Monitoring
|
||||||
|
|
||||||
If configured, ntfy can expose a `/metrics` endpoint for [Prometheus](https://prometheus.io/), which can then be used to
|
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/)).
|
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"
|
enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
|
||||||
|
|
||||||
=== "server.yml (Using default port)"
|
=== "server.yml (Using default port)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
enable-metrics: true
|
enable-metrics: true
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "server.yml (Using dedicated IP/port)"
|
=== "server.yml (Using dedicated IP/port)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
metrics-listen-http: "10.0.1.1:9090"
|
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:
|
In Prometheus, an example scrape config would look like this:
|
||||||
|
|
||||||
=== "prometheus.yml"
|
=== "prometheus.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
scrape_configs:
|
scrape_configs:
|
||||||
- job_name: "ntfy"
|
- job_name: "ntfy"
|
||||||
|
@ -1157,11 +1236,13 @@ Here's an example Grafana dashboard built from the metrics (see [Grafana JSON on
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
## Profiling
|
## 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://<ip>:<port>/debug/pprof/`.
|
If enabled, ntfy will listen on a dedicated listen IP/port, which can be accessed via the web browser on `http://<ip>:<port>/debug/pprof/`.
|
||||||
This can be helpful to expose bottlenecks, and visualize call flows. To enable, simply set the `profile-listen-http` config option.
|
This can be helpful to expose bottlenecks, and visualize call flows. To enable, simply set the `profile-listen-http` config option.
|
||||||
|
|
||||||
## Logging & debugging
|
## Logging & debugging
|
||||||
|
|
||||||
By default, ntfy logs to the console (stderr), with an `info` log level, and in a human-readable text format.
|
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
|
ntfy supports five different log levels, can also write to a file, log as JSON, and even supports granular
|
||||||
|
@ -1170,17 +1251,18 @@ by calling `kill -HUP $pid` or `systemctl reload ntfy`.
|
||||||
|
|
||||||
The following config options define the logging behavior:
|
The following config options define the logging behavior:
|
||||||
|
|
||||||
* `log-format` defines the output format, can be `text` (default) or `json`
|
- `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-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-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.
|
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).
|
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:
|
This is an array of strings in the format:
|
||||||
- `field=value -> level` to match a value exactly, e.g. `tag=manager -> trace`
|
- `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 -> level` to match any value, e.g. `time_taken_ms -> debug`
|
||||||
|
|
||||||
**Logging config (good for production use):**
|
**Logging config (good for production use):**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
log-level: info
|
log-level: info
|
||||||
log-format: json
|
log-format: json
|
||||||
|
@ -1197,6 +1279,7 @@ a username (`user_name`), or a tag (`tag`). There are dozens of fields you can u
|
||||||
they are, either turn the log-level to `trace` and observe, or reference the [source code](https://github.com/binwiederhier/ntfy).
|
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:
|
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: info
|
||||||
log-level-overrides:
|
log-level-overrides:
|
||||||
|
@ -1221,6 +1304,7 @@ $ ntfy serve
|
||||||
```
|
```
|
||||||
|
|
||||||
## Config options
|
## Config options
|
||||||
|
|
||||||
Each config option can be set in the config file `/etc/ntfy/server.yml` (e.g. `listen-http: :80`) or as a
|
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
|
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`).
|
variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
|
||||||
|
@ -1231,66 +1315,67 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
|
||||||
not support dashes.
|
not support dashes.
|
||||||
|
|
||||||
| Config option | Env variable | Format | Default | Description |
|
| 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-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-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` | `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 |
|
| `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. |
|
| `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. |
|
| `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). |
|
| `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-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-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-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-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) |
|
| `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-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`. |
|
| `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. |
|
| `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-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-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-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`. |
|
| `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-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-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-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-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-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-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-` |
|
| `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-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-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-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 |
|
| `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. |
|
| `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. |
|
| `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. |
|
| `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-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 |
|
| `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-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-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-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-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-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-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-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-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-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 |
|
| `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) |
|
| `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-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-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) |
|
| `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-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 |
|
| `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 |
|
| `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: `<number>(smh)`, e.g. 30s, 20m or 1h.
|
The format for a _duration_ is: `<number>(smh)`, e.g. 30s, 20m or 1h.
|
||||||
The format for a *size* is: `<number>(GMK)`, e.g. 1G, 200M or 4000k.
|
The format for a _size_ is: `<number>(GMK)`, e.g. 1G, 200M or 4000k.
|
||||||
|
|
||||||
## Command line options
|
## Command line options
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy serve --help
|
$ ntfy serve --help
|
||||||
NAME:
|
NAME:
|
||||||
ntfy serve - Run the ntfy server
|
ntfy serve - Run the ntfy server
|
||||||
|
@ -1371,4 +1456,3 @@ OPTIONS:
|
||||||
--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)
|
--help, -h show help (default: false)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,36 @@
|
||||||
# Deprecation notices
|
# 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
|
**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.
|
before the behavior is changed depends on the severity of the change, and how prominent the feature is.
|
||||||
|
|
||||||
## Active deprecations
|
## Active deprecations
|
||||||
|
|
||||||
_No active deprecations_
|
_No active deprecations_
|
||||||
|
|
||||||
## Previous deprecations
|
## Previous deprecations
|
||||||
|
|
||||||
### ntfy CLI: `ntfy publish --env-topic` will be removed
|
### ntfy CLI: `ntfy publish --env-topic` will be removed
|
||||||
|
|
||||||
> Active since 2022-06-20, behavior changed with v1.30.1
|
> 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
|
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.
|
`NTFY_TOPIC` environment variable, but it won't be necessary anymore to specify the `--env-topic` flag.
|
||||||
|
|
||||||
=== "Before"
|
=== "Before"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ NTFY_TOPIC=mytopic ntfy publish --env-topic "this is the message"
|
$ NTFY_TOPIC=mytopic ntfy publish --env-topic "this is the message"
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "After"
|
=== "After"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ NTFY_TOPIC=mytopic ntfy publish "this is the message"
|
$ NTFY_TOPIC=mytopic ntfy publish "this is the message"
|
||||||
```
|
```
|
||||||
|
|
||||||
### <del>Android app: WebSockets will become the default connection protocol</del>
|
### <del>Android app: WebSockets will become the default connection protocol</del>
|
||||||
|
|
||||||
> Active since 2022-03-13, behavior will not change (deprecation removed 2022-06-20)
|
> 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
|
Instant delivery connections and connections to self-hosted servers in the Android app were going to switch
|
||||||
|
@ -32,6 +38,7 @@ 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.
|
and add a notice banner in the Android app instead.
|
||||||
|
|
||||||
### Android app: Using `since=<timestamp>` instead of `since=<id>`
|
### Android app: Using `since=<timestamp>` instead of `since=<id>`
|
||||||
|
|
||||||
> Active since 2022-02-27, behavior changed with v1.14.0
|
> Active since 2022-02-27, behavior changed with v1.14.0
|
||||||
|
|
||||||
The Android app started using `since=<id>` instead of `since=<timestamp>`, which means as of Android app v1.14.0,
|
The Android app started using `since=<id>` instead of `since=<timestamp>`, which means as of Android app v1.14.0,
|
||||||
|
@ -40,6 +47,7 @@ it will not work with servers older than v1.16.0 anymore. This is to simplify ha
|
||||||
The `since=<timestamp>` endpoint will continue to work. This is merely a notice that the Android app behavior will change.
|
The `since=<timestamp>` 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`)
|
### Running server via `ntfy` (instead of `ntfy serve`)
|
||||||
|
|
||||||
> Deprecated 2021-12-17, behavior changed with v1.10.0
|
> 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
|
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.
|
just the server.
|
||||||
|
|
||||||
=== "Before"
|
=== "Before"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy
|
$ ntfy
|
||||||
2021/12/17 08:16:01 Listening on :80/http
|
2021/12/17 08:16:01 Listening on :80/http
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "After"
|
=== "After"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy serve
|
$ ntfy serve
|
||||||
2021/12/17 08:16:01 Listening on :80/http
|
2021/12/17 08:16:01 Listening on :80/http
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,49 +1,52 @@
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
Hurray 🥳 🎉, you are interested in writing code for ntfy! **That's awesome.** 😎
|
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)**.
|
hesitate to **contact me on [Discord](https://discord.gg/cT7ECsZj9w) or [Matrix](https://matrix.to/#/#ntfy:matrix.org)**.
|
||||||
|
|
||||||
## ntfy server
|
## ntfy server
|
||||||
|
|
||||||
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the
|
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy). The codebase for the
|
||||||
server consists of three components:
|
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
|
- **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
|
[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
|
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
|
[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).
|
[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
|
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.
|
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/)
|
- **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`)
|
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*).
|
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
|
### Navigating the code
|
||||||
|
|
||||||
Code:
|
Code:
|
||||||
|
|
||||||
* [main.go](https://github.com/binwiederhier/ntfy/blob/main/main.go) - Main entrypoint into the CLI, for both server and client
|
- [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`
|
- [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
|
- [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`
|
- [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`
|
- [web/](https://github.com/binwiederhier/ntfy/tree/main/web) - The [React](https://reactjs.org/) application, also see `web/package.json`
|
||||||
|
|
||||||
Build related:
|
Build related:
|
||||||
|
|
||||||
* [Makefile](https://github.com/binwiederhier/ntfy/blob/main/Makefile) - Main entrypoint for all things related to building
|
- [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/))
|
- [.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
|
- [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/))
|
- [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)
|
- [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 `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).
|
the generated output is copied to `server/site` (web app and landing page) and `server/docs` (documentation).
|
||||||
|
|
||||||
### Build/test on Gitpod
|
### 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,
|
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/).
|
I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
|
||||||
|
@ -52,18 +55,20 @@ I do suggest a proper IDE like [IntelliJ IDEA](https://www.jetbrains.com/idea/).
|
||||||
|
|
||||||
### Build requirements
|
### Build requirements
|
||||||
|
|
||||||
* [Go](https://go.dev/) (required for main server)
|
- [Go](https://go.dev/) (required for main server)
|
||||||
* [gcc](https://gcc.gnu.org/) (required main server, for SQLite cgo-based bindings)
|
- [gcc](https://gcc.gnu.org/) (required main server, for SQLite cgo-based bindings)
|
||||||
* [Make](https://www.gnu.org/software/make/) (required for convenience)
|
- [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)
|
- [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)
|
- [GoReleaser](https://goreleaser.com/) (required for a proper main server build)
|
||||||
* [Python](https://www.python.org/) (for `pip`, only to build the docs)
|
- [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)
|
- [nodejs](https://nodejs.org/en/) (for `npm`, only to build the web app)
|
||||||
|
|
||||||
### Install dependencies
|
### Install dependencies
|
||||||
|
|
||||||
These steps **assume Ubuntu**. Steps may vary on different Linux distributions.
|
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)):
|
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
|
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
|
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.19.1.linux-amd64.tar.gz
|
||||||
|
@ -72,12 +77,14 @@ go version # verifies that it worked
|
||||||
```
|
```
|
||||||
|
|
||||||
Install [GoReleaser](https://goreleaser.com/) (see [official instructions](https://goreleaser.com/install/)):
|
Install [GoReleaser](https://goreleaser.com/) (see [official instructions](https://goreleaser.com/install/)):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
go install github.com/goreleaser/goreleaser@latest
|
go install github.com/goreleaser/goreleaser@latest
|
||||||
goreleaser -v # verifies that it worked
|
goreleaser -v # verifies that it worked
|
||||||
```
|
```
|
||||||
|
|
||||||
Install [nodejs](https://nodejs.org/en/) (see [official instructions](https://nodejs.org/en/download/package-manager/)):
|
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 -
|
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||||
sudo apt-get install -y nodejs
|
sudo apt-get install -y nodejs
|
||||||
|
@ -85,6 +92,7 @@ npm -v # verifies that it worked
|
||||||
```
|
```
|
||||||
|
|
||||||
Then install a few other things required:
|
Then install a few other things required:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt install \
|
sudo apt install \
|
||||||
build-essential \
|
build-essential \
|
||||||
|
@ -96,21 +104,25 @@ sudo apt install \
|
||||||
```
|
```
|
||||||
|
|
||||||
### Check out code
|
### Check out code
|
||||||
|
|
||||||
Now check out via git from the [GitHub repository](https://github.com/binwiederhier/ntfy):
|
Now check out via git from the [GitHub repository](https://github.com/binwiederhier/ntfy):
|
||||||
|
|
||||||
=== "via HTTPS"
|
=== "via HTTPS"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/binwiederhier/ntfy.git
|
git clone https://github.com/binwiederhier/ntfy.git
|
||||||
cd ntfy
|
cd ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "via SSH"
|
=== "via SSH"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone git@github.com:binwiederhier/ntfy.git
|
git clone git@github.com:binwiederhier/ntfy.git
|
||||||
cd ntfy
|
cd ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build all the things
|
### 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`:
|
by typing `make`:
|
||||||
|
|
||||||
|
@ -173,6 +185,7 @@ $ docker run --rm -p 80:80 binwiederhier/ntfy:dev serve
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build the ntfy binary
|
### Build the ntfy binary
|
||||||
|
|
||||||
To build only the `ntfy` binary **without the web app or documentation**, use the `make cli-...` targets:
|
To build only the `ntfy` binary **without the web app or documentation**, use the `make cli-...` targets:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -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
|
$ go run main.go serve
|
||||||
server/server.go:85:13: pattern docs: no matching files found
|
server/server.go:85:13: pattern docs: no matching files found
|
||||||
|
@ -221,6 +235,7 @@ While not officially supported (or released), you can build and run the server *
|
||||||
`make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it.
|
`make cli-darwin-server` to build a binary, or `go run main.go serve` (see above) to run it.
|
||||||
|
|
||||||
### Build the web app
|
### 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:
|
is really simple. Just type `make web` and you're in business:
|
||||||
|
|
||||||
|
@ -242,6 +257,7 @@ $ npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build the docs
|
### 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:
|
documentation. As long as you have `mkdocs` installed (see above), this should work fine:
|
||||||
|
|
||||||
|
@ -264,32 +280,38 @@ 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.
|
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
|
## Android app
|
||||||
|
|
||||||
The ntfy Android app source code is available [on GitHub](https://github.com/binwiederhier/ntfy-android).
|
The ntfy Android app source code is available [on GitHub](https://github.com/binwiederhier/ntfy-android).
|
||||||
The Android app has two flavors:
|
The Android app has two flavors:
|
||||||
|
|
||||||
* **Google Play:** The `play` flavor includes [Firebase (FCM)](https://firebase.google.com/) and requires a Firebase account
|
- **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
|
- **F-Droid:** The `fdroid` flavor does not include Firebase or Google dependencies
|
||||||
|
|
||||||
### Navigating the code
|
### 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
|
- [main/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/main) - Main Android app source code
|
||||||
* [fdroid/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/fdroid) - F-Droid Firebase stubs
|
- [play/](https://github.com/binwiederhier/ntfy-android/tree/main/app/src/play) - Google Play / Firebase specific code
|
||||||
* [build.gradle](https://github.com/binwiederhier/ntfy-android/blob/main/app/build.gradle) - Main build file
|
- [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
|
### IDE/Environment
|
||||||
|
|
||||||
You should download [Android Studio](https://developer.android.com/studio) (or [IntelliJ IDEA](https://www.jetbrains.com/idea/)
|
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. 😀
|
with the relevant Android plugins). Everything else will just be a pain for you. Do yourself a favor. 😀
|
||||||
|
|
||||||
### Check out the code
|
### Check out the code
|
||||||
|
|
||||||
First check out the repository:
|
First check out the repository:
|
||||||
|
|
||||||
=== "via HTTPS"
|
=== "via HTTPS"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/binwiederhier/ntfy-android.git
|
git clone https://github.com/binwiederhier/ntfy-android.git
|
||||||
cd ntfy-android
|
cd ntfy-android
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "via SSH"
|
=== "via SSH"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone git@github.com:binwiederhier/ntfy-android.git
|
git clone git@github.com:binwiederhier/ntfy-android.git
|
||||||
cd ntfy-android
|
cd ntfy-android
|
||||||
|
@ -298,12 +320,14 @@ First check out the repository:
|
||||||
Then either follow the steps for building with or without Firebase.
|
Then either follow the steps for building with or without Firebase.
|
||||||
|
|
||||||
### Build F-Droid flavor (no FCM)
|
### Build F-Droid flavor (no FCM)
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
|
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.
|
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)
|
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:
|
if you're self-hosting the server. Then run:
|
||||||
|
|
||||||
```
|
```
|
||||||
# Remove Google dependencies (FCM)
|
# Remove Google dependencies (FCM)
|
||||||
sed -i -e '/google-services/d' build.gradle
|
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)
|
### Build Play flavor (FCM)
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
I do build the ntfy Android app using IntelliJ IDEA (Android Studio), so I don't know if these Gradle commands will
|
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.
|
work without issues. Please give me feedback if it does/doesn't work for you.
|
||||||
|
|
||||||
To build your own version with Firebase, you must:
|
To build your own version with Firebase, you must:
|
||||||
|
|
||||||
* Create a Firebase/FCM account
|
- Create a Firebase/FCM account
|
||||||
* Place your account file at `app/google-services.json`
|
- 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)
|
- 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:
|
- Then run:
|
||||||
|
|
||||||
```
|
```
|
||||||
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
|
# To build an unsigned .apk (app/build/outputs/apk/play/*.apk)
|
||||||
./gradlew assemblePlayRelease
|
./gradlew assemblePlayRelease
|
||||||
|
@ -336,10 +362,12 @@ To build your own version with Firebase, you must:
|
||||||
```
|
```
|
||||||
|
|
||||||
## iOS app
|
## 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.
|
strictly based off of my development on this app. There may be other versions of macOS / XCode that work.
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
1. macOS Monterey or later
|
1. macOS Monterey or later
|
||||||
1. XCode 13.2+
|
1. XCode 13.2+
|
||||||
1. A physical iOS device (for push notifications, Firebase does not work in the XCode simulator)
|
1. A physical iOS device (for push notifications, Firebase does not work in the XCode simulator)
|
||||||
|
@ -383,6 +411,7 @@ recommended.
|
||||||
1. Click "Generate new private key" to generate and download a private key to use for sending messages via the ntfy server
|
1. Click "Generate new private key" to generate and download a private key to use for sending messages via the ntfy server
|
||||||
|
|
||||||
### 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
|
Note that the ntfy server is not officially supported on macOS. It should, however, be able to run on macOS using these
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
@ -400,6 +429,7 @@ steps:
|
||||||
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
|
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
|
### 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:
|
`GoogleService-Info.plist` file to your project. Here's how to do that:
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ those out, too.
|
||||||
I cannot guarantee that all of these examples are functional. Many of them I have not tried myself.
|
I cannot guarantee that all of these examples are functional. Many of them I have not tried myself.
|
||||||
|
|
||||||
## Cronjobs
|
## Cronjobs
|
||||||
|
|
||||||
ntfy is perfect for any kind of cronjobs or just when long processes are done (backups, pipelines, rsync copy commands, ...).
|
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 <tt>curl</tt> call
|
I started adding notifications pretty much all of my scripts. Typically, I just chain the <tt>curl</tt> call
|
||||||
|
@ -31,8 +32,8 @@ 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
|
*/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
|
## 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
|
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.
|
effective.
|
||||||
|
|
||||||
|
@ -54,17 +55,20 @@ fi
|
||||||
```
|
```
|
||||||
|
|
||||||
## SSH login alerts
|
## 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
|
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 <a href="https://en.wikipedia.org/wiki/Linux_PAM">PAM</a>
|
own, I now message myself. Here's an example of how to use <a href="https://en.wikipedia.org/wiki/Linux_PAM">PAM</a>
|
||||||
to notify yourself on SSH login.
|
to notify yourself on SSH login.
|
||||||
|
|
||||||
=== "/etc/pam.d/sshd"
|
=== "/etc/pam.d/sshd"
|
||||||
|
|
||||||
```
|
```
|
||||||
# at the end of the file
|
# at the end of the file
|
||||||
session optional pam_exec.so /usr/bin/ntfy-ssh-login.sh
|
session optional pam_exec.so /usr/bin/ntfy-ssh-login.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "/usr/bin/ntfy-ssh-login.sh"
|
=== "/usr/bin/ntfy-ssh-login.sh"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
if [ "${PAM_TYPE}" = "open_session" ]; then
|
if [ "${PAM_TYPE}" = "open_session" ]; then
|
||||||
|
@ -77,6 +81,7 @@ to notify yourself on SSH login.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Collect data from multiple machines
|
## Collect data from multiple machines
|
||||||
|
|
||||||
The other day I was running tasks on 20 servers, and I wanted to collect the interim results
|
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`).
|
and I had one central collector to grab the results as they came in (`collect-results.sh`).
|
||||||
|
@ -84,12 +89,15 @@ and I had one central collector to grab the results as they came in (`collect-re
|
||||||
It looked something like this:
|
It looked something like this:
|
||||||
|
|
||||||
=== "collect-results.sh"
|
=== "collect-results.sh"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
while read result; do
|
while read result; do
|
||||||
[ -n "$result" ] && echo "$result" >> results.csv
|
[ -n "$result" ] && echo "$result" >> results.csv
|
||||||
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
|
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "publish-result.sh"
|
=== "publish-result.sh"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
// This script was run on each of the 20 servers. It was doing heavy processing ...
|
// This script was run on each of the 20 servers. It was doing heavy processing ...
|
||||||
|
|
||||||
|
@ -98,6 +106,7 @@ It looked something like this:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ansible, Salt and Puppet
|
## Ansible, Salt and Puppet
|
||||||
|
|
||||||
You can easily integrate ntfy into Ansible, Salt, or Puppet to notify you when runs are done or are highstated.
|
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:
|
One of my co-workers uses the following Ansible task to let him know when things are done:
|
||||||
|
|
||||||
|
@ -123,7 +132,9 @@ to ntfy at its default URL (`attrs` and other attributes are optional):
|
||||||
```
|
```
|
||||||
|
|
||||||
## GitHub Actions
|
## 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.
|
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
|
- name: Actions Ntfy
|
||||||
run: |
|
run: |
|
||||||
|
@ -136,6 +147,7 @@ You can send a message during a workflow run with curl. Here is an example sendi
|
||||||
```
|
```
|
||||||
|
|
||||||
## Watchtower (shoutrrr)
|
## 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.
|
[Watchtower](https://github.com/containrrr/watchtower/) notifications to your ntfy topic.
|
||||||
|
|
||||||
|
@ -151,6 +163,7 @@ services:
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you only want to send notifications using shoutrrr:
|
Or, if you only want to send notifications using shoutrrr:
|
||||||
|
|
||||||
```
|
```
|
||||||
shoutrrr send -u "ntfy://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
|
shoutrrr send -u "ntfy://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
|
||||||
```
|
```
|
||||||
|
@ -165,6 +178,7 @@ 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).
|
Some simple bash scripts to achieve this are kindly provided in [nickexyz's ntfy-shellscripts repository](https://github.com/nickexyz/ntfy-shellscripts).
|
||||||
|
|
||||||
## Node-RED
|
## Node-RED
|
||||||
|
|
||||||
You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples:
|
You can use the HTTP request node to send messages with [Node-RED](https://nodered.org), some examples:
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -186,17 +200,13 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"proxy": "",
|
"proxy": "",
|
||||||
"authType": "",
|
"authType": "",
|
||||||
"senderr": false,
|
"senderr": false,
|
||||||
"credentials":
|
"credentials": {
|
||||||
{
|
|
||||||
"user": "",
|
"user": "",
|
||||||
"password": ""
|
"password": ""
|
||||||
},
|
},
|
||||||
"x": 590,
|
"x": 590,
|
||||||
"y": 3160,
|
"y": 3160,
|
||||||
"wires":
|
"wires": [[]]
|
||||||
[
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "32ee1eade51fae50",
|
"id": "32ee1eade51fae50",
|
||||||
|
@ -211,20 +221,14 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"libs": [],
|
"libs": [],
|
||||||
"x": 470,
|
"x": 470,
|
||||||
"y": 3160,
|
"y": 3160,
|
||||||
"wires":
|
"wires": [["c956e688cc74ad8e"]]
|
||||||
[
|
|
||||||
[
|
|
||||||
"c956e688cc74ad8e"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "b287e59cd2311815",
|
"id": "b287e59cd2311815",
|
||||||
"type": "inject",
|
"type": "inject",
|
||||||
"z": "fabdd7a3.4045a",
|
"z": "fabdd7a3.4045a",
|
||||||
"name": "Manual start",
|
"name": "Manual start",
|
||||||
"props":
|
"props": [
|
||||||
[
|
|
||||||
{
|
{
|
||||||
"p": "payload"
|
"p": "payload"
|
||||||
},
|
},
|
||||||
|
@ -242,12 +246,7 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"payloadType": "date",
|
"payloadType": "date",
|
||||||
"x": 330,
|
"x": 330,
|
||||||
"y": 3160,
|
"y": 3160,
|
||||||
"wires":
|
"wires": [["32ee1eade51fae50"]]
|
||||||
[
|
|
||||||
[
|
|
||||||
"32ee1eade51fae50"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
@ -275,19 +274,13 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"proxy": "",
|
"proxy": "",
|
||||||
"authType": "",
|
"authType": "",
|
||||||
"senderr": false,
|
"senderr": false,
|
||||||
"credentials":
|
"credentials": {
|
||||||
{
|
|
||||||
"user": "",
|
"user": "",
|
||||||
"password": ""
|
"password": ""
|
||||||
},
|
},
|
||||||
"x": 490,
|
"x": 490,
|
||||||
"y": 3320,
|
"y": 3320,
|
||||||
"wires":
|
"wires": [["6e75bc41d2ec4a03"]]
|
||||||
[
|
|
||||||
[
|
|
||||||
"6e75bc41d2ec4a03"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "6e75bc41d2ec4a03",
|
"id": "6e75bc41d2ec4a03",
|
||||||
|
@ -302,12 +295,7 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"libs": [],
|
"libs": [],
|
||||||
"x": 650,
|
"x": 650,
|
||||||
"y": 3320,
|
"y": 3320,
|
||||||
"wires":
|
"wires": [["eb160615b6ceda98"]]
|
||||||
[
|
|
||||||
[
|
|
||||||
"eb160615b6ceda98"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "eb160615b6ceda98",
|
"id": "eb160615b6ceda98",
|
||||||
|
@ -323,25 +311,20 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"proxy": "",
|
"proxy": "",
|
||||||
"authType": "",
|
"authType": "",
|
||||||
"senderr": false,
|
"senderr": false,
|
||||||
"credentials":
|
"credentials": {
|
||||||
{
|
|
||||||
"user": "",
|
"user": "",
|
||||||
"password": ""
|
"password": ""
|
||||||
},
|
},
|
||||||
"x": 770,
|
"x": 770,
|
||||||
"y": 3320,
|
"y": 3320,
|
||||||
"wires":
|
"wires": [[]]
|
||||||
[
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "5b8dbf15c8a7a3a5",
|
"id": "5b8dbf15c8a7a3a5",
|
||||||
"type": "inject",
|
"type": "inject",
|
||||||
"z": "fabdd7a3.4045a",
|
"z": "fabdd7a3.4045a",
|
||||||
"name": "Manual start",
|
"name": "Manual start",
|
||||||
"props":
|
"props": [
|
||||||
[
|
|
||||||
{
|
{
|
||||||
"p": "payload"
|
"p": "payload"
|
||||||
},
|
},
|
||||||
|
@ -359,12 +342,7 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||
"payloadType": "date",
|
"payloadType": "date",
|
||||||
"x": 310,
|
"x": 310,
|
||||||
"y": 3320,
|
"y": 3320,
|
||||||
"wires":
|
"wires": [["d135a13eadeb9d6d"]]
|
||||||
[
|
|
||||||
[
|
|
||||||
"d135a13eadeb9d6d"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
@ -374,6 +352,7 @@ You can use the HTTP request node to send messages with [Node-RED](https://noder
|
||||||

|

|
||||||
|
|
||||||
## Gatus
|
## Gatus
|
||||||
|
|
||||||
To use ntfy with [Gatus](https://github.com/TwiN/gatus), you can use the `ntfy` alerting provider like so:
|
To use ntfy with [Gatus](https://github.com/TwiN/gatus), you can use the `ntfy` alerting provider like so:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -416,8 +395,8 @@ alerting:
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
## Jellyseerr/Overseerr webhook
|
## Jellyseerr/Overseerr webhook
|
||||||
|
|
||||||
Here is an example for [jellyseerr](https://github.com/Fallenbagel/jellyseerr)/[overseerr](https://overseerr.dev/) 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.
|
And if you're not using the request `topic`, make sure to change it in the JSON payload to your topic.
|
||||||
|
@ -434,6 +413,7 @@ And if you're not using the request `topic`, make sure to change it in the JSON
|
||||||
```
|
```
|
||||||
|
|
||||||
## Home Assistant
|
## Home Assistant
|
||||||
|
|
||||||
Here is an example for the configuration.yml file to setup a REST notify component.
|
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.
|
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
|
## Uptime Kuma
|
||||||
|
|
||||||
Go to your [Uptime Kuma](https://github.com/louislam/uptime-kuma) Settings > Notifications, click on **Setup Notification**.
|
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)**:
|
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:
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## UptimeRobot
|
## UptimeRobot
|
||||||
|
|
||||||
Go to your [UptimeRobot](https://github.com/uptimerobot) My Settings > Alert Contacts > Add Alert Contact
|
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.
|
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.
|
||||||
|
|
||||||
|
@ -516,6 +498,7 @@ Select **Alert Contact Type** = Webhook. Then set your desired **Friendly Name**
|
||||||
"click": https://uptimerobot.com/dashboard#*monitorID*
|
"click": https://uptimerobot.com/dashboard#*monitorID*
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can create two Alert Contacts each with a different icon and priority, for example:
|
You can create two Alert Contacts each with a different icon and priority, for example:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -528,14 +511,15 @@ You can create two Alert Contacts each with a different icon and priority, for e
|
||||||
"click": https://uptimerobot.com/dashboard#*monitorID*
|
"click": https://uptimerobot.com/dashboard#*monitorID*
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can now add the created Alerts Contact(s) to the monitor(s) and test the notifications:
|
You can now add the created Alerts Contact(s) to the monitor(s) and test the notifications:
|
||||||
|
|
||||||
<div id="uptimerobot-monitor-screenshots" class="screenshots">
|
<div id="uptimerobot-monitor-screenshots" class="screenshots">
|
||||||
<a href="../static/img/uptimerobot-test.jpg"><img src="../static/img/uptimerobot-test.jpg"/></a>
|
<a href="../static/img/uptimerobot-test.jpg"><img src="../static/img/uptimerobot-test.jpg"/></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Apprise
|
## 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)).
|
[Apprise/ntfy wiki page](https://github.com/caronc/apprise/wiki/Notify_ntfy)).
|
||||||
|
|
||||||
|
@ -553,8 +537,8 @@ apprise -vv -t "Test Message Title" -b "Test Message Body" \
|
||||||
ntfy://ntfy.example.com/mytopic
|
ntfy://ntfy.example.com/mytopic
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Rundeck
|
## 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) :
|
[rundeck-config.properties](https://docs.rundeck.com/docs/administration/configuration/config-file-reference.html) :
|
||||||
|
|
||||||
|
@ -565,6 +549,7 @@ rundeck.mail.template.log.formatted=false
|
||||||
```
|
```
|
||||||
|
|
||||||
Example `template.html`:
|
Example `template.html`:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div>Execution ${execution.id} was <b>${execution.status}</b></div>
|
<div>Execution ${execution.id} was <b>${execution.status}</b></div>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -579,11 +564,13 @@ Add notification on Rundeck (attachment type must be: `Attached as file to email
|
||||||

|

|
||||||
|
|
||||||
## Traccar
|
## 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
|
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.
|
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))
|
**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
|
```xml
|
||||||
<entry key='sms.http.url'>https://ntfy.sh</entry>
|
<entry key='sms.http.url'>https://ntfy.sh</entry>
|
||||||
<entry key='sms.http.template'>
|
<entry key='sms.http.template'>
|
||||||
|
@ -593,11 +580,15 @@ The easiest way to integrate traccar with ntfy, is to configure ntfy as the SMS
|
||||||
}
|
}
|
||||||
</entry>
|
</entry>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
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
|
```xml
|
||||||
<entry key='sms.http.authorization'>Bearer tk_JhbsnoMrgy2FcfHeofv97Pi5uXaZZ</entry>
|
<entry key='sms.http.authorization'>Bearer tk_JhbsnoMrgy2FcfHeofv97Pi5uXaZZ</entry>
|
||||||
```
|
```
|
||||||
|
|
||||||
or by simply providing traccar with a valid username/password combination.
|
or by simply providing traccar with a valid username/password combination.
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<entry key='sms.http.user'>phil</entry>
|
<entry key='sms.http.user'>phil</entry>
|
||||||
<entry key='sms.http.password'>mypass</entry>
|
<entry key='sms.http.password'>mypass</entry>
|
||||||
|
|
16
docs/faq.md
16
docs/faq.md
|
@ -1,13 +1,16 @@
|
||||||
# Frequently asked questions (FAQ)
|
# Frequently asked questions (FAQ)
|
||||||
|
|
||||||
## Isn't this like ...?
|
## Isn't this like ...?
|
||||||
|
|
||||||
Who knows. I didn't do a lot of research before making this. It was fun making it.
|
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?
|
## 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
|
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.
|
server without signup and free of charge, I may also offer paid plans in the future.
|
||||||
|
|
||||||
## What are the uptime guarantees?
|
## 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,
|
ntfy currently runs on a single DigitalOcean droplet, without any scale out strategy or redundancies. When the time comes,
|
||||||
|
@ -20,19 +23,23 @@ There is a [status page](https://ntfy.statuspage.io/) which is updated based on
|
||||||
awesome [healthchecks.io](https://healthchecks.io/) (_no affiliation, just a fan_).
|
awesome [healthchecks.io](https://healthchecks.io/) (_no affiliation, just a fan_).
|
||||||
|
|
||||||
## What happens if there are multiple subscribers to the same topic?
|
## 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.
|
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?
|
## 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.
|
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
|
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.
|
to facilitate service restarts, message polling and to overcome client network disruptions.
|
||||||
|
|
||||||
## Can I self-host it?
|
## 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
|
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).
|
your own server as well. Check out the [install instructions](install.md).
|
||||||
|
|
||||||
## Is Firebase used?
|
## Is Firebase used?
|
||||||
|
|
||||||
In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
|
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
|
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.
|
||||||
|
@ -41,32 +48,38 @@ If you do not care for Firebase, I suggest you install the [F-Droid version](htt
|
||||||
of the app and [self-host your own ntfy server](install.md).
|
of the app and [self-host your own ntfy server](install.md).
|
||||||
|
|
||||||
## How much battery does the Android app use?
|
## 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,
|
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,
|
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/)),
|
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).
|
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.
|
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?
|
## 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
|
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
|
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.
|
limits.
|
||||||
|
|
||||||
## What is instant delivery?
|
## 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
|
[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),
|
server and listens for incoming notifications. This consumes additional battery (see above),
|
||||||
but delivers notifications instantly.
|
but delivers notifications instantly.
|
||||||
|
|
||||||
## Can you implement feature X?
|
## Can you implement feature X?
|
||||||
|
|
||||||
Yes, maybe. Check out [existing GitHub issues](https://github.com/binwiederhier/ntfy/issues) to see if somebody else had
|
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.
|
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?
|
## 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
|
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
|
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.
|
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?
|
## 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
|
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.
|
security risk. So technically, it does not need to be disabled.
|
||||||
|
@ -77,6 +90,7 @@ Think of the ntfy web app like an Android/iOS app. It is freely available and ac
|
||||||
a proper backend. So as long as you secure your backend with ACLs, exposing the ntfy web app to the Internet is harmless.
|
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?
|
## Where can I donate?
|
||||||
|
|
||||||
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier).
|
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
|
I would be humbled if you helped me carry the server and developer account costs. Even small donations are very much
|
||||||
appreciated.
|
appreciated.
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
ntfy lets you **send push notifications to your phone or desktop via scripts from any computer**, using simple HTTP PUT
|
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.
|
or POST requests. I use it to notify myself when scripts fail, or long-running commands complete.
|
||||||
|
|
||||||
## Step 1: Get the app
|
## Step 1: Get the app
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
|
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
|
||||||
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
|
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
|
||||||
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="../../static/img/badge-appstore.png"></a>
|
<a href="https://apps.apple.com/us/app/ntfy/id1625396347"><img src="../../static/img/badge-appstore.png"></a>
|
||||||
|
@ -22,21 +24,25 @@ 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.
|
That's it. After you tap "Subscribe", the app is listening for new messages on that topic.
|
||||||
|
|
||||||
## Step 2: Send a message
|
## 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,
|
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:
|
simple message using a POST request:
|
||||||
|
|
||||||
=== "Command line (curl)"
|
=== "Command line (curl)"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
curl -d "Backup successful 😀" ntfy.sh/mytopic
|
curl -d "Backup successful 😀" ntfy.sh/mytopic
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ntfy CLI"
|
=== "ntfy CLI"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy publish mytopic "Backup successful 😀"
|
ntfy publish mytopic "Backup successful 😀"
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
|
|
||||||
```http
|
```http
|
||||||
POST /mytopic HTTP/1.1
|
POST /mytopic HTTP/1.1
|
||||||
Host: ntfy.sh
|
Host: ntfy.sh
|
||||||
|
@ -45,6 +51,7 @@ simple message using a POST request:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JavaScript"
|
=== "JavaScript"
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
fetch('https://ntfy.sh/mytopic', {
|
fetch('https://ntfy.sh/mytopic', {
|
||||||
method: 'POST', // PUT works too
|
method: 'POST', // PUT works too
|
||||||
|
@ -53,18 +60,21 @@ simple message using a POST request:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Go"
|
=== "Go"
|
||||||
|
|
||||||
```go
|
```go
|
||||||
http.Post("https://ntfy.sh/mytopic", "text/plain",
|
http.Post("https://ntfy.sh/mytopic", "text/plain",
|
||||||
strings.NewReader("Backup successful 😀"))
|
strings.NewReader("Backup successful 😀"))
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
|
|
||||||
```python
|
```python
|
||||||
requests.post("https://ntfy.sh/mytopic",
|
requests.post("https://ntfy.sh/mytopic",
|
||||||
data="Backup successful 😀".encode(encoding='utf-8'))
|
data="Backup successful 😀".encode(encoding='utf-8'))
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "PHP"
|
=== "PHP"
|
||||||
|
|
||||||
```php-inline
|
```php-inline
|
||||||
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
|
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
|
||||||
'http' => [
|
'http' => [
|
||||||
|
@ -91,5 +101,3 @@ Here's another video showing the entire process:
|
||||||
<video controls muted autoplay loop width="650" src="static/img/android-video-overview.mp4"></video>
|
<video controls muted autoplay loop width="650" src="static/img/android-video-overview.mp4"></video>
|
||||||
<figcaption>Sending push notifications to your Android phone</figcaption>
|
<figcaption>Sending push notifications to your Android phone</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Installing ntfy
|
# Installing ntfy
|
||||||
|
|
||||||
The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to
|
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,
|
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.
|
configure it and run it. Just like any other software. No fuzz.
|
||||||
|
@ -9,6 +10,7 @@ configure it and run it. Just like any other software. No fuzz.
|
||||||
`curl`.
|
`curl`.
|
||||||
|
|
||||||
## General steps
|
## General steps
|
||||||
|
|
||||||
The ntfy server comes as a statically linked binary and is shipped as tarball, deb/rpm packages and as a Docker image.
|
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.
|
We support amd64, armv7 and arm64.
|
||||||
|
|
||||||
|
@ -24,10 +26,12 @@ If you like video tutorials, check out :simple-youtube: [Kris Occhipinti's ntfy
|
||||||
It's short and to the point. _I am not affiliated with Kris, I just liked the video._
|
It's short and to the point. _I am not affiliated with Kris, I just liked the video._
|
||||||
|
|
||||||
## Linux binaries
|
## Linux binaries
|
||||||
|
|
||||||
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
|
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
|
||||||
deb/rpm packages.
|
deb/rpm packages.
|
||||||
|
|
||||||
=== "x86_64/amd64"
|
=== "x86_64/amd64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_x86_64.tar.gz
|
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
|
tar zxvf ntfy_2.5.0_linux_x86_64.tar.gz
|
||||||
|
@ -37,6 +41,7 @@ deb/rpm packages.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv6"
|
=== "armv6"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.tar.gz
|
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
|
tar zxvf ntfy_2.5.0_linux_armv6.tar.gz
|
||||||
|
@ -46,6 +51,7 @@ deb/rpm packages.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv7/armhf"
|
=== "armv7/armhf"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.tar.gz
|
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
|
tar zxvf ntfy_2.5.0_linux_armv7.tar.gz
|
||||||
|
@ -55,6 +61,7 @@ deb/rpm packages.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "arm64"
|
=== "arm64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.tar.gz
|
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
|
tar zxvf ntfy_2.5.0_linux_arm64.tar.gz
|
||||||
|
@ -64,9 +71,11 @@ deb/rpm packages.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Debian/Ubuntu repository
|
## Debian/Ubuntu repository
|
||||||
|
|
||||||
Installation via Debian repository:
|
Installation via Debian repository:
|
||||||
|
|
||||||
=== "x86_64/amd64"
|
=== "x86_64/amd64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /etc/apt/keyrings
|
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
|
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
|
||||||
|
@ -80,6 +89,7 @@ Installation via Debian repository:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv7/armhf"
|
=== "armv7/armhf"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /etc/apt/keyrings
|
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
|
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"
|
=== "arm64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /etc/apt/keyrings
|
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
|
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:
|
Manually installing the .deb file:
|
||||||
|
|
||||||
=== "x86_64/amd64"
|
=== "x86_64/amd64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_amd64.deb
|
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_amd64.deb
|
||||||
sudo dpkg -i ntfy_*.deb
|
sudo dpkg -i ntfy_*.deb
|
||||||
|
@ -116,6 +128,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv6"
|
=== "armv6"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.deb
|
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.deb
|
||||||
sudo dpkg -i ntfy_*.deb
|
sudo dpkg -i ntfy_*.deb
|
||||||
|
@ -124,6 +137,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv7/armhf"
|
=== "armv7/armhf"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.deb
|
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.deb
|
||||||
sudo dpkg -i ntfy_*.deb
|
sudo dpkg -i ntfy_*.deb
|
||||||
|
@ -132,6 +146,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "arm64"
|
=== "arm64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.deb
|
wget https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.deb
|
||||||
sudo dpkg -i ntfy_*.deb
|
sudo dpkg -i ntfy_*.deb
|
||||||
|
@ -142,6 +157,7 @@ Manually installing the .deb file:
|
||||||
## Fedora/RHEL/CentOS
|
## Fedora/RHEL/CentOS
|
||||||
|
|
||||||
=== "x86_64/amd64"
|
=== "x86_64/amd64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_amd64.rpm
|
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
|
||||||
|
@ -149,6 +165,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv6"
|
=== "armv6"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.rpm
|
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv6.rpm
|
||||||
sudo systemctl enable ntfy
|
sudo systemctl enable ntfy
|
||||||
|
@ -156,6 +173,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "armv7/armhf"
|
=== "armv7/armhf"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_armv7.rpm
|
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
|
||||||
|
@ -163,6 +181,7 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "arm64"
|
=== "arm64"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v2.5.0/ntfy_2.5.0_linux_arm64.rpm
|
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
|
||||||
|
@ -170,12 +189,15 @@ Manually installing the .deb file:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Arch Linux
|
## 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.
|
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
|
paru -S ntfysh-bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, run the following commands to install ntfy manually:
|
Alternatively, run the following commands to install ntfy manually:
|
||||||
|
|
||||||
```
|
```
|
||||||
curl https://aur.archlinux.org/cgit/aur.git/snapshot/ntfysh-bin.tar.gz | tar xzv
|
curl https://aur.archlinux.org/cgit/aur.git/snapshot/ntfysh-bin.tar.gz | tar xzv
|
||||||
cd ntfysh-bin
|
cd ntfysh-bin
|
||||||
|
@ -183,7 +205,9 @@ makepkg -si
|
||||||
```
|
```
|
||||||
|
|
||||||
## NixOS / Nix
|
## 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:
|
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
|
nix-env -iA ntfy-sh
|
||||||
```
|
```
|
||||||
|
@ -191,6 +215,7 @@ 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
|
## macOS
|
||||||
|
|
||||||
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on macOS as well.
|
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),
|
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`).
|
extract it and place it somewhere in your `PATH` (e.g. `/usr/local/bin/ntfy`).
|
||||||
|
@ -212,14 +237,16 @@ ntfy --help
|
||||||
development as well. Check out the [build instructions](develop.md) for details.
|
development as well. Check out the [build instructions](develop.md) for details.
|
||||||
|
|
||||||
## Homebrew
|
## Homebrew
|
||||||
|
|
||||||
To install the [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) via Homebrew (Linux and macOS),
|
To install the [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) via Homebrew (Linux and macOS),
|
||||||
simply run:
|
simply run:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install ntfy
|
brew install ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
The [ntfy CLI](subscribe/cli.md) (`ntfy publish` and `ntfy subscribe` only) is supported on Windows as well.
|
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),
|
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%`.
|
||||||
|
@ -235,6 +262,7 @@ Also available in [Scoop's](https://scoop.sh) Main repository:
|
||||||
[GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.
|
[GitHub issue](https://github.com/binwiederhier/ntfy/issues) to let me know.
|
||||||
|
|
||||||
## Docker
|
## 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.
|
be pretty straight forward to use.
|
||||||
|
|
||||||
|
@ -248,11 +276,13 @@ you should map `/etc/ntfy`, so you can edit `/etc/ntfy/server.yml`.
|
||||||
use the [`server.yml` file on GitHub](https://github.com/binwiederhier/ntfy/blob/main/server/server.yml) as a template.
|
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):
|
Basic usage (no cache or additional config):
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -p 80:80 -it binwiederhier/ntfy serve
|
docker run -p 80:80 -it binwiederhier/ntfy serve
|
||||||
```
|
```
|
||||||
|
|
||||||
With persistent cache (configured as command line arguments):
|
With persistent cache (configured as command line arguments):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run \
|
docker run \
|
||||||
-v /var/cache/ntfy:/var/cache/ntfy \
|
-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):
|
With other config options, timezone, and non-root user (configured via `/etc/ntfy/server.yml`, see [configuration](config.md) for details):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run \
|
docker run \
|
||||||
-v /etc/ntfy:/etc/ntfy \
|
-v /etc/ntfy:/etc/ntfy \
|
||||||
|
@ -276,6 +307,7 @@ docker run \
|
||||||
```
|
```
|
||||||
|
|
||||||
Using docker-compose with non-root user and healthchecks enabled:
|
Using docker-compose with non-root user and healthchecks enabled:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "2.1"
|
version: "2.1"
|
||||||
|
|
||||||
|
@ -294,7 +326,11 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
healthcheck: # optional: remember to adapt the host:port to your environment
|
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"]
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1",
|
||||||
|
]
|
||||||
interval: 60s
|
interval: 60s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
@ -305,11 +341,13 @@ services:
|
||||||
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.
|
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.
|
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
|
FROM binwiederhier/ntfy
|
||||||
COPY server.yml /etc/ntfy/server.yml
|
COPY server.yml /etc/ntfy/server.yml
|
||||||
ENTRYPOINT ["ntfy", "serve"]
|
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.
|
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
|
## 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
|
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.
|
unmanned pod.
|
||||||
|
|
||||||
|
|
||||||
=== "deployment"
|
=== "deployment"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
@ -368,6 +406,7 @@ unmanned pod.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "stateful set"
|
=== "stateful set"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
|
@ -411,6 +450,7 @@ unmanned pod.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "pod"
|
=== "pod"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
|
@ -442,6 +482,7 @@ unmanned pod.
|
||||||
Configuration is relatively straightforward. As an example, a minimal configuration is provided.
|
Configuration is relatively straightforward. As an example, a minimal configuration is provided.
|
||||||
|
|
||||||
=== "resource definition"
|
=== "resource definition"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
|
@ -454,6 +495,7 @@ Configuration is relatively straightforward. As an example, a minimal configurat
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "from-file"
|
=== "from-file"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl create configmap ntfy --from-file=server.yml
|
kubectl create configmap ntfy --from-file=server.yml
|
||||||
```
|
```
|
||||||
|
@ -480,6 +522,7 @@ kubectl apply -k /ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "kustomization.yaml"
|
=== "kustomization.yaml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
|
@ -494,7 +537,9 @@ kubectl apply -k /ntfy
|
||||||
- server.yml
|
- server.yml
|
||||||
namespace: TESTNAMESPACE # select namespace for whole application
|
namespace: TESTNAMESPACE # select namespace for whole application
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ntfy-deployment.yaml"
|
=== "ntfy-deployment.yaml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
@ -552,6 +597,7 @@ kubectl apply -k /ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ntfy-pvc.yaml"
|
=== "ntfy-pvc.yaml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
|
@ -567,6 +613,7 @@ kubectl apply -k /ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ntfy-svc.yaml"
|
=== "ntfy-svc.yaml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
@ -584,6 +631,7 @@ kubectl apply -k /ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "ntfy-ingress.yaml"
|
=== "ntfy-ingress.yaml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
|
@ -604,6 +652,7 @@ kubectl apply -k /ntfy
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "server.yml"
|
=== "server.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
cache-file: "/var/cache/ntfy/cache.db"
|
cache-file: "/var/cache/ntfy/cache.db"
|
||||||
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
attachment-cache-dir: "/var/cache/ntfy/attachments"
|
||||||
|
|
|
@ -79,7 +79,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
|
||||||
- [grav-plugin-whistleblower](https://github.com/Himmlisch-Studios/grav-plugin-whistleblower) - Grav CMS plugin to get notifications via ntfy (PHP)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
@ -149,7 +149,7 @@ I've added a ⭐ to projects or posts that have a significant following, or had
|
||||||
- [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
|
- [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
|
- [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
|
- [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
|
- [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
|
- [Pointer | Issue #367](https://www.pointer.io/archives/a9495a2a6f/) - pointer.io - 11/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
|
- [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
|
- [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
|
## 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
|
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!**
|
ntfy community. Thanks to everyone running a public server. **You guys rock!**
|
||||||
|
|
||||||
| URL | Country |
|
| URL | Country |
|
||||||
|---------------------------------------------------|--------------------|
|
| ------------------------------------------------- | ---------------- |
|
||||||
| [ntfy.sh](https://ntfy.sh/) (*Official*) | 🇺🇸 United States |
|
| [ntfy.sh](https://ntfy.sh/) (_Official_) | 🇺🇸 United States |
|
||||||
| [ntfy.tedomum.net](https://ntfy.tedomum.net/) | 🇫🇷 France |
|
| [ntfy.tedomum.net](https://ntfy.tedomum.net/) | 🇫🇷 France |
|
||||||
| [ntfy.jae.fi](https://ntfy.jae.fi/) | 🇫🇮 Finland |
|
| [ntfy.jae.fi](https://ntfy.jae.fi/) | 🇫🇮 Finland |
|
||||||
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
|
| [ntfy.adminforge.de](https://ntfy.adminforge.de/) | 🇩🇪 Germany |
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
# Known issues
|
# Known issues
|
||||||
|
|
||||||
This is an incomplete list of known issues with the ntfy server, Android app, and iOS app. You can find a complete
|
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
|
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.
|
to have the prominent ones here to link to.
|
||||||
|
|
||||||
## iOS app not refreshing (see [#267](https://github.com/binwiederhier/ntfy/issues/267))
|
## 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
|
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.
|
swipe down, you do not see the newly arrived messages, even though the popup appeared before.
|
||||||
|
|
||||||
|
@ -13,6 +15,7 @@ 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.
|
Please send experienced iOS developers my way to help me figure this out.
|
||||||
|
|
||||||
## iOS app not receiving notifications (anymore)
|
## 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):
|
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**:
|
**Firebase+APNS are being weird and buggy**:
|
||||||
|
@ -24,5 +27,5 @@ 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).
|
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:
|
Be sure that in your selfhosted server:
|
||||||
|
|
||||||
* Set `upstream-base-url: "https://ntfy.sh"` (**not your own hostname!**)
|
- 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
|
- Ensure that the URL you set in `base-url` **matches exactly** what you set the Default Server in iOS to
|
||||||
|
|
406
docs/publish.md
406
docs/publish.md
File diff suppressed because it is too large
Load diff
839
docs/releases.md
839
docs/releases.md
File diff suppressed because it is too large
Load diff
37
docs/static/css/extra.css
vendored
37
docs/static/css/extra.css
vendored
|
@ -22,19 +22,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.admonition {
|
.admonition {
|
||||||
font-size: .74rem !important;
|
font-size: 0.74rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
article {
|
article {
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
figure img, figure video {
|
figure img,
|
||||||
|
figure video {
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
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 {
|
body[data-md-color-scheme="default"] header {
|
||||||
|
@ -143,7 +148,7 @@ figure video {
|
||||||
|
|
||||||
.lightbox .close-lightbox::after,
|
.lightbox .close-lightbox::after,
|
||||||
.lightbox .close-lightbox::before {
|
.lightbox .close-lightbox::before {
|
||||||
content: '';
|
content: "";
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background-color: #ddd;
|
background-color: #ddd;
|
||||||
|
@ -164,53 +169,53 @@ figure video {
|
||||||
/* roboto-300 - latin */
|
/* roboto-300 - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto';
|
font-family: "Roboto";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: url('../fonts/roboto-v30-latin-300.woff2') format('woff2');
|
src: url("../fonts/roboto-v30-latin-300.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* roboto-regular - latin */
|
/* roboto-regular - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto';
|
font-family: "Roboto";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url('../fonts/roboto-v30-latin-regular.woff2') format('woff2');
|
src: url("../fonts/roboto-v30-latin-regular.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* roboto-italic - latin */
|
/* roboto-italic - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto';
|
font-family: "Roboto";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url('../fonts/roboto-v30-latin-italic.woff2') format('woff2');
|
src: url("../fonts/roboto-v30-latin-italic.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* roboto-500 - latin */
|
/* roboto-500 - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto';
|
font-family: "Roboto";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src: url('../fonts/roboto-v30-latin-500.woff2') format('woff2');
|
src: url("../fonts/roboto-v30-latin-500.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* roboto-700 - latin */
|
/* roboto-700 - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto';
|
font-family: "Roboto";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: url('../fonts/roboto-v30-latin-700.woff2') format('woff2');
|
src: url("../fonts/roboto-v30-latin-700.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* roboto-mono - latin */
|
/* roboto-mono - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
font-family: 'Roboto Mono';
|
font-family: "Roboto Mono";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: url('../fonts/roboto-mono-v22-latin-regular.woff2') format('woff2');
|
src: url("../fonts/roboto-mono-v22-latin-regular.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
62
docs/static/js/extra.js
vendored
62
docs/static/js/extra.js
vendored
|
@ -1,51 +1,59 @@
|
||||||
// Link tabs, as per https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs
|
// Link tabs, as per https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/#linked-tabs
|
||||||
|
|
||||||
const savedCodeTab = localStorage.getItem('savedTab')
|
const savedCodeTab = localStorage.getItem("savedTab");
|
||||||
const codeTabs = document.querySelectorAll(".tabbed-set > input")
|
const codeTabs = document.querySelectorAll(".tabbed-set > input");
|
||||||
for (const tab of codeTabs) {
|
for (const tab of codeTabs) {
|
||||||
tab.addEventListener("click", () => {
|
tab.addEventListener("click", () => {
|
||||||
const current = document.querySelector(`label[for=${tab.id}]`)
|
const current = document.querySelector(`label[for=${tab.id}]`);
|
||||||
const pos = current.getBoundingClientRect().top
|
const pos = current.getBoundingClientRect().top;
|
||||||
const labelContent = current.innerHTML
|
const labelContent = current.innerHTML;
|
||||||
const labels = document.querySelectorAll('.tabbed-set > label, .tabbed-alternate > .tabbed-labels > label')
|
const labels = document.querySelectorAll(
|
||||||
|
".tabbed-set > label, .tabbed-alternate > .tabbed-labels > label"
|
||||||
|
);
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
if (label.innerHTML === labelContent) {
|
if (label.innerHTML === labelContent) {
|
||||||
document.querySelector(`input[id=${label.getAttribute('for')}]`).checked = true
|
document.querySelector(
|
||||||
|
`input[id=${label.getAttribute("for")}]`
|
||||||
|
).checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preserve scroll position
|
// Preserve scroll position
|
||||||
const delta = (current.getBoundingClientRect().top) - pos
|
const delta = current.getBoundingClientRect().top - pos;
|
||||||
window.scrollBy(0, delta)
|
window.scrollBy(0, delta);
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
localStorage.setItem('savedTab', labelContent)
|
localStorage.setItem("savedTab", labelContent);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Select saved tab
|
// Select saved tab
|
||||||
const current = document.querySelector(`label[for=${tab.id}]`)
|
const current = document.querySelector(`label[for=${tab.id}]`);
|
||||||
const labelContent = current.innerHTML
|
const labelContent = current.innerHTML;
|
||||||
if (savedCodeTab === labelContent) {
|
if (savedCodeTab === labelContent) {
|
||||||
tab.checked = true
|
tab.checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lightbox for screenshot
|
// Lightbox for screenshot
|
||||||
|
|
||||||
const lightbox = document.createElement('div');
|
const lightbox = document.createElement("div");
|
||||||
lightbox.classList.add('lightbox');
|
lightbox.classList.add("lightbox");
|
||||||
document.body.appendChild(lightbox);
|
document.body.appendChild(lightbox);
|
||||||
|
|
||||||
const showScreenshotOverlay = (e, el, group, index) => {
|
const showScreenshotOverlay = (e, el, group, index) => {
|
||||||
lightbox.classList.add('show');
|
lightbox.classList.add("show");
|
||||||
document.addEventListener('keydown', nextScreenshotKeyboardListener);
|
document.addEventListener("keydown", nextScreenshotKeyboardListener);
|
||||||
return showScreenshot(e, group, index);
|
return showScreenshot(e, group, index);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showScreenshot = (e, group, index) => {
|
const showScreenshot = (e, group, index) => {
|
||||||
const actualIndex = resolveScreenshotIndex(group, index);
|
const actualIndex = resolveScreenshotIndex(group, index);
|
||||||
lightbox.innerHTML = '<div class="close-lightbox"></div>' + screenshots[group][actualIndex].innerHTML;
|
lightbox.innerHTML =
|
||||||
lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e, group, actualIndex+1); };
|
'<div class="close-lightbox"></div>' +
|
||||||
|
screenshots[group][actualIndex].innerHTML;
|
||||||
|
lightbox.querySelector("img").onclick = (e) => {
|
||||||
|
return showScreenshot(e, group, actualIndex + 1);
|
||||||
|
};
|
||||||
currentScreenshotGroup = group;
|
currentScreenshotGroup = group;
|
||||||
currentScreenshotIndex = actualIndex;
|
currentScreenshotIndex = actualIndex;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -70,8 +78,8 @@ const resolveScreenshotIndex = (group, index) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const hideScreenshotOverlay = (e) => {
|
const hideScreenshotOverlay = (e) => {
|
||||||
lightbox.classList.remove('show');
|
lightbox.classList.remove("show");
|
||||||
document.removeEventListener('keydown', nextScreenshotKeyboardListener);
|
document.removeEventListener("keydown", nextScreenshotKeyboardListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextScreenshotKeyboardListener = (e) => {
|
const nextScreenshotKeyboardListener = (e) => {
|
||||||
|
@ -85,14 +93,16 @@ const nextScreenshotKeyboardListener = (e) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let currentScreenshotGroup = '';
|
let currentScreenshotGroup = "";
|
||||||
let currentScreenshotIndex = 0;
|
let currentScreenshotIndex = 0;
|
||||||
let screenshots = {};
|
let screenshots = {};
|
||||||
Array.from(document.getElementsByClassName('screenshots')).forEach((sg) => {
|
Array.from(document.getElementsByClassName("screenshots")).forEach((sg) => {
|
||||||
const group = sg.id;
|
const group = sg.id;
|
||||||
screenshots[group] = [...sg.querySelectorAll('a')];
|
screenshots[group] = [...sg.querySelectorAll("a")];
|
||||||
screenshots[group].forEach((el, index) => {
|
screenshots[group].forEach((el, index) => {
|
||||||
el.onclick = (e) => { return showScreenshotOverlay(e, el, group, index); };
|
el.onclick = (e) => {
|
||||||
|
return showScreenshotOverlay(e, el, group, index);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Subscribe via API
|
# 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),
|
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).
|
check out the page that describes how to [publish messages](../publish.md).
|
||||||
|
@ -7,21 +8,24 @@ You can consume the subscription API as either a **[simple HTTP stream (JSON, SS
|
||||||
**[via WebSockets](#websockets)**. Both are incredibly simple to use.
|
**[via WebSockets](#websockets)**. Both are incredibly simple to use.
|
||||||
|
|
||||||
## HTTP stream
|
## 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 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:
|
only differ in the response format:
|
||||||
|
|
||||||
* [JSON stream](#subscribe-as-json-stream): `<topic>/json` returns a JSON stream, with one JSON message object per line
|
- [JSON stream](#subscribe-as-json-stream): `<topic>/json` returns a JSON stream, with one JSON message object per line
|
||||||
* [SSE stream](#subscribe-as-sse-stream): `<topic>/sse` returns messages as [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events), which
|
- [SSE stream](#subscribe-as-sse-stream): `<topic>/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)
|
can be used with [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
|
||||||
* [Raw stream](#subscribe-as-raw-stream): `<topic>/raw` returns messages as raw text, with one line per message
|
- [Raw stream](#subscribe-as-raw-stream): `<topic>/raw` returns messages as raw text, with one line per message
|
||||||
|
|
||||||
### Subscribe as JSON stream
|
### Subscribe as JSON stream
|
||||||
|
|
||||||
Here are a few examples of how to consume the JSON endpoint (`<topic>/json`). For almost all languages, **this is the
|
Here are a few examples of how to consume the JSON endpoint (`<topic>/json`). For almost all languages, **this is the
|
||||||
recommended way to subscribe to a topic**. The notable exception is JavaScript, for which 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.
|
[SSE/EventSource stream](#subscribe-as-sse-stream) is much easier to work with.
|
||||||
|
|
||||||
=== "Command line (curl)"
|
=== "Command line (curl)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -s ntfy.sh/disk-alerts/json
|
$ curl -s ntfy.sh/disk-alerts/json
|
||||||
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
|
{"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 CLI"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ntfy subcribe disk-alerts
|
$ ntfy subcribe disk-alerts
|
||||||
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
|
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
|
||||||
|
@ -38,6 +43,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /disk-alerts/json HTTP/1.1
|
GET /disk-alerts/json HTTP/1.1
|
||||||
Host: ntfy.sh
|
Host: ntfy.sh
|
||||||
|
@ -53,6 +59,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Go"
|
=== "Go"
|
||||||
|
|
||||||
```go
|
```go
|
||||||
resp, err := http.Get("https://ntfy.sh/disk-alerts/json")
|
resp, err := http.Get("https://ntfy.sh/disk-alerts/json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -66,6 +73,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
|
|
||||||
```python
|
```python
|
||||||
resp = requests.get("https://ntfy.sh/disk-alerts/json", stream=True)
|
resp = requests.get("https://ntfy.sh/disk-alerts/json", stream=True)
|
||||||
for line in resp.iter_lines():
|
for line in resp.iter_lines():
|
||||||
|
@ -74,6 +82,7 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "PHP"
|
=== "PHP"
|
||||||
|
|
||||||
```php-inline
|
```php-inline
|
||||||
$fp = fopen('https://ntfy.sh/disk-alerts/json', 'r');
|
$fp = fopen('https://ntfy.sh/disk-alerts/json', 'r');
|
||||||
if (!$fp) die('cannot open stream');
|
if (!$fp) die('cannot open stream');
|
||||||
|
@ -85,11 +94,13 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
||||||
```
|
```
|
||||||
|
|
||||||
### Subscribe as SSE stream
|
### Subscribe as SSE stream
|
||||||
|
|
||||||
Using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) in JavaScript, you can consume
|
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).
|
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)"
|
=== "Command line (curl)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -s ntfy.sh/mytopic/sse
|
$ curl -s ntfy.sh/mytopic/sse
|
||||||
event: open
|
event: open
|
||||||
|
@ -103,6 +114,7 @@ easy to use. Here's what it looks like. You may also want to check out the [full
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /mytopic/sse HTTP/1.1
|
GET /mytopic/sse HTTP/1.1
|
||||||
Host: ntfy.sh
|
Host: ntfy.sh
|
||||||
|
@ -122,6 +134,7 @@ easy to use. Here's what it looks like. You may also want to check out the [full
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JavaScript"
|
=== "JavaScript"
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');
|
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');
|
||||||
eventSource.onmessage = (e) => {
|
eventSource.onmessage = (e) => {
|
||||||
|
@ -130,12 +143,14 @@ easy to use. Here's what it looks like. You may also want to check out the [full
|
||||||
```
|
```
|
||||||
|
|
||||||
### Subscribe as raw stream
|
### 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
|
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),
|
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
|
[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.
|
format. Keepalive messages are sent as empty lines.
|
||||||
|
|
||||||
=== "Command line (curl)"
|
=== "Command line (curl)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -s ntfy.sh/disk-alerts/raw
|
$ curl -s ntfy.sh/disk-alerts/raw
|
||||||
|
|
||||||
|
@ -144,6 +159,7 @@ format. Keepalive messages are sent as empty lines.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /disk-alerts/raw HTTP/1.1
|
GET /disk-alerts/raw HTTP/1.1
|
||||||
Host: ntfy.sh
|
Host: ntfy.sh
|
||||||
|
@ -157,6 +173,7 @@ format. Keepalive messages are sent as empty lines.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Go"
|
=== "Go"
|
||||||
|
|
||||||
```go
|
```go
|
||||||
resp, err := http.Get("https://ntfy.sh/disk-alerts/raw")
|
resp, err := http.Get("https://ntfy.sh/disk-alerts/raw")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -170,6 +187,7 @@ format. Keepalive messages are sent as empty lines.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python"
|
=== "Python"
|
||||||
|
|
||||||
```python
|
```python
|
||||||
resp = requests.get("https://ntfy.sh/disk-alerts/raw", stream=True)
|
resp = requests.get("https://ntfy.sh/disk-alerts/raw", stream=True)
|
||||||
for line in resp.iter_lines():
|
for line in resp.iter_lines():
|
||||||
|
@ -178,6 +196,7 @@ format. Keepalive messages are sent as empty lines.
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "PHP"
|
=== "PHP"
|
||||||
|
|
||||||
```php-inline
|
```php-inline
|
||||||
$fp = fopen('https://ntfy.sh/disk-alerts/raw', 'r');
|
$fp = fopen('https://ntfy.sh/disk-alerts/raw', 'r');
|
||||||
if (!$fp) die('cannot open stream');
|
if (!$fp) die('cannot open stream');
|
||||||
|
@ -189,6 +208,7 @@ format. Keepalive messages are sent as empty lines.
|
||||||
```
|
```
|
||||||
|
|
||||||
## WebSockets
|
## WebSockets
|
||||||
|
|
||||||
You may also subscribe to topics via [WebSockets](https://en.wikipedia.org/wiki/WebSocket), which is also widely
|
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,
|
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
|
I recommend [websocat](https://github.com/vi/websocat), a fantastic tool similar to `socat` or `curl`, but specifically
|
||||||
|
@ -198,6 +218,7 @@ The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSO
|
||||||
[JSON stream endpoint](#subscribe-as-json-stream).
|
[JSON stream endpoint](#subscribe-as-json-stream).
|
||||||
|
|
||||||
=== "Command line (websocat)"
|
=== "Command line (websocat)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ websocat wss://ntfy.sh/mytopic/ws
|
$ websocat wss://ntfy.sh/mytopic/ws
|
||||||
{"id":"qRHUCCvjj8","time":1642307388,"event":"open","topic":"mytopic"}
|
{"id":"qRHUCCvjj8","time":1642307388,"event":"open","topic":"mytopic"}
|
||||||
|
@ -205,6 +226,7 @@ The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSO
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "HTTP"
|
=== "HTTP"
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /disk-alerts/ws HTTP/1.1
|
GET /disk-alerts/ws HTTP/1.1
|
||||||
Host: ntfy.sh
|
Host: ntfy.sh
|
||||||
|
@ -218,6 +240,7 @@ The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSO
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Go"
|
=== "Go"
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/gorilla/websocket"
|
import "github.com/gorilla/websocket"
|
||||||
ws, _, _ := websocket.DefaultDialer.Dial("wss://ntfy.sh/mytopic/ws", nil)
|
ws, _, _ := websocket.DefaultDialer.Dial("wss://ntfy.sh/mytopic/ws", nil)
|
||||||
|
@ -226,6 +249,7 @@ The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSO
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JavaScript"
|
=== "JavaScript"
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const socket = new WebSocket('wss://ntfy.sh/mytopic/ws');
|
const socket = new WebSocket('wss://ntfy.sh/mytopic/ws');
|
||||||
socket.addEventListener('message', function (event) {
|
socket.addEventListener('message', function (event) {
|
||||||
|
@ -236,6 +260,7 @@ The WebSockets endpoint is available at `<topic>/ws` and returns messages as JSO
|
||||||
## Advanced features
|
## Advanced features
|
||||||
|
|
||||||
### Poll for messages
|
### Poll for messages
|
||||||
|
|
||||||
You can also just poll for messages if you don't like the long-standing connection using the `poll=1`
|
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
|
query parameter. The connection will end after all available messages have been read. This parameter can be
|
||||||
combined with `since=` (defaults to `since=all`).
|
combined with `since=` (defaults to `since=all`).
|
||||||
|
@ -245,6 +270,7 @@ curl -s "ntfy.sh/mytopic/json?poll=1"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fetch cached messages
|
### Fetch cached messages
|
||||||
|
|
||||||
Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network
|
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`),
|
the `since=` query parameter. It takes a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`),
|
||||||
|
@ -257,6 +283,7 @@ curl -s "ntfy.sh/mytopic/json?since=nFS3knfcQ1xe"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fetch scheduled messages
|
### Fetch scheduled messages
|
||||||
|
|
||||||
Messages that are [scheduled to be delivered](../publish.md#scheduled-delivery) at a later date are not typically
|
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
|
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`)
|
delivered yet. To also return scheduled messages from the API, you can use the `scheduled=1` (alias: `sched=1`)
|
||||||
|
@ -267,6 +294,7 @@ curl -s "ntfy.sh/mytopic/json?poll=1&sched=1"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Filter messages
|
### Filter messages
|
||||||
|
|
||||||
You can filter which messages are returned based on the well-known message fields `id`, `message`, `title`, `priority` and
|
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
|
`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.
|
"zfs-error" and "error". Note that the `priority` filter is a logical OR and the `tags` filter is a logical AND.
|
||||||
|
@ -281,14 +309,15 @@ $ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error"
|
||||||
Available filters (all case-insensitive):
|
Available filters (all case-insensitive):
|
||||||
|
|
||||||
| Filter variable | Alias | Example | Description |
|
| 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 |
|
| `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 |
|
| `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 |
|
| `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) |
|
| `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) |
|
| `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
|
### 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:
|
in the URL. This allows you to reduce the number of connections you have to maintain:
|
||||||
|
|
||||||
|
@ -300,49 +329,52 @@ $ curl -s ntfy.sh/mytopic1,mytopic2/json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
|
|
||||||
Depending on whether the server is configured to support [access control](../config.md#access-control), some topics
|
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.
|
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 [basic auth](../publish.md#basic-auth), e.g. `Authorization: Basic dGVzdHVzZXI6ZmFrZXBhc3N3b3Jk`
|
- 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`
|
- 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.
|
Please refer to the [publishing documentation](../publish.md#authentication) for additional details.
|
||||||
|
|
||||||
## JSON message format
|
## JSON message format
|
||||||
|
|
||||||
Both the [`/json` endpoint](#subscribe-as-json-stream) and the [`/sse` endpoint](#subscribe-as-sse-stream) return a JSON
|
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:
|
format of the message. It's very straight forward:
|
||||||
|
|
||||||
**Message**:
|
**Message**:
|
||||||
|
|
||||||
| Field | Required | Type | Example | Description |
|
| Field | Required | Type | Example | Description |
|
||||||
|--------------|----------|---------------------------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
| ------------ | -------- | ------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
|
| `id` | ✔️ | _string_ | `hwQ2YpKdmg` | Randomly chosen message identifier |
|
||||||
| `time` | ✔️ | *number* | `1635528741` | Message date time, as Unix time stamp |
|
| `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 |
|
| `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` |
|
| `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 |
|
| `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 |
|
| `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/<topic>` |
|
| `title` | - | _string_ | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>` |
|
||||||
| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](../publish.md#tags-emojis) that may or not map to emojis |
|
| `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 |
|
| `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) |
|
| `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 |
|
| `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` | - | _JSON object_ | _see below_ | Details about an attachment (name, URL, size, ...) |
|
||||||
|
|
||||||
**Attachment** (part of the message, see [attachments](../publish.md#attachments) for details):
|
**Attachment** (part of the message, see [attachments](../publish.md#attachments) for details):
|
||||||
|
|
||||||
| Field | Required | Type | Example | Description |
|
| Field | Required | Type | Example | Description |
|
||||||
|-----------|----------|-------------|--------------------------------|-----------------------------------------------------------------------------------------------------------|
|
| --------- | -------- | ----------- | ------------------------------ | --------------------------------------------------------------------------------------------------------- |
|
||||||
| `name` | ✔️ | *string* | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) |
|
| `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 |
|
| `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 |
|
| `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 |
|
| `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 |
|
| `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:
|
Here's an example for each message type:
|
||||||
|
|
||||||
=== "Notification message"
|
=== "Notification message"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "sPs71M8A2T",
|
"id": "sPs71M8A2T",
|
||||||
|
@ -368,8 +400,8 @@ Here's an example for each message type:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
=== "Notification message (minimal)"
|
=== "Notification message (minimal)"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "wze9zgqK41",
|
"id": "wze9zgqK41",
|
||||||
|
@ -382,6 +414,7 @@ Here's an example for each message type:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Open message"
|
=== "Open message"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "2pgIAaGrQ8",
|
"id": "2pgIAaGrQ8",
|
||||||
|
@ -392,6 +425,7 @@ Here's an example for each message type:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Keepalive message"
|
=== "Keepalive message"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "371sevb0pD",
|
"id": "371sevb0pD",
|
||||||
|
@ -402,6 +436,7 @@ Here's an example for each message type:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Poll request message"
|
=== "Poll request message"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "371sevb0pD",
|
"id": "371sevb0pD",
|
||||||
|
@ -412,16 +447,17 @@ Here's an example for each message type:
|
||||||
```
|
```
|
||||||
|
|
||||||
## List of all parameters
|
## 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**,
|
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.
|
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 |
|
| Parameter | Aliases (case-insensitive) | Description |
|
||||||
|-------------|----------------------------|---------------------------------------------------------------------------------|
|
| ----------- | -------------------------- | ------------------------------------------------------------------------------- |
|
||||||
| `poll` | `X-Poll`, `po` | Return cached messages and close connection |
|
| `poll` | `X-Poll`, `po` | Return cached messages and close connection |
|
||||||
| `since` | `X-Since`, `si` | Return cached messages since timestamp, duration or message ID |
|
| `since` | `X-Since`, `si` | Return cached messages since timestamp, duration or message ID |
|
||||||
| `scheduled` | `X-Scheduled`, `sched` | Include scheduled/delayed messages in message list |
|
| `scheduled` | `X-Scheduled`, `sched` | Include scheduled/delayed messages in message list |
|
||||||
| `id` | `X-ID` | Filter: Only return messages that match this exact message ID |
|
| `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 |
|
| `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 |
|
| `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) |
|
| `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) |
|
| `tags` | `X-Tags`, `tag`, `ta` | Filter: Only return messages that match _all listed tags_ (comma-separated) |
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Subscribe via ntfy CLI
|
# 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
|
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).
|
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).
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ to topics via the ntfy CLI. The CLI is included in the same `ntfy` binary that c
|
||||||
your own script. It all depends on the use case. 😀
|
your own script. It all depends on the use case. 😀
|
||||||
|
|
||||||
## Install + configure
|
## Install + configure
|
||||||
|
|
||||||
To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and
|
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
|
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
|
by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You
|
||||||
|
@ -24,19 +26,22 @@ default-host: https://ntfy.myhost.com
|
||||||
```
|
```
|
||||||
|
|
||||||
## Publish messages
|
## 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
|
`trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few
|
||||||
quick ones:
|
quick ones:
|
||||||
|
|
||||||
=== "Simple send"
|
=== "Simple send"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy publish mytopic This is a message
|
ntfy publish mytopic This is a message
|
||||||
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"
|
=== "Send with title, priority, and tags"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy publish \
|
ntfy publish \
|
||||||
--title="Thing sold on eBay" \
|
--title="Thing sold on eBay" \
|
||||||
--priority=high \
|
--priority=high \
|
||||||
|
@ -46,20 +51,23 @@ quick ones:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Send at 8:30am"
|
=== "Send at 8:30am"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy pub --at=8:30am delayed_topic Laterzz
|
ntfy pub --at=8:30am delayed_topic Laterzz
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Triggering a webhook"
|
=== "Triggering a webhook"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy trigger mywebhook
|
ntfy trigger mywebhook
|
||||||
ntfy pub mywebhook
|
ntfy pub mywebhook
|
||||||
```
|
```
|
||||||
|
|
||||||
### Attaching a local file
|
### Attaching a local file
|
||||||
|
|
||||||
You can easily upload and attach a local file to a notification:
|
You can easily upload and attach a local file to a notification:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ ntfy pub --file README.md mytopic | jq .
|
$ ntfy pub --file README.md mytopic | jq .
|
||||||
{
|
{
|
||||||
"id": "meIlClVLABJQ",
|
"id": "meIlClVLABJQ",
|
||||||
|
@ -78,13 +86,14 @@ $ ntfy pub --file README.md mytopic | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wait for PID/command
|
### 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
|
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`).
|
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 ...`):
|
Run a command and wait for it to complete (here: `rsync ...`):
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ ntfy pub --wait-cmd mytopic rsync -av ./ root@example.com:/backups/ | jq .
|
$ ntfy pub --wait-cmd mytopic rsync -av ./ root@example.com:/backups/ | jq .
|
||||||
{
|
{
|
||||||
"id": "Re0rWXZQM8WB",
|
"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:
|
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"
|
=== "Using a PID directly"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy pub --wait-pid 8458 mytopic | jq .
|
$ ntfy pub --wait-pid 8458 mytopic | jq .
|
||||||
{
|
{
|
||||||
"id": "orM6hJKNYkWb",
|
"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`"
|
=== "Using a `pidof`"
|
||||||
```
|
|
||||||
|
```sh
|
||||||
$ ntfy pub --wait-pid $(pidof rsync) mytopic | jq .
|
$ ntfy pub --wait-pid $(pidof rsync) mytopic | jq .
|
||||||
{
|
{
|
||||||
"id": "orM6hJKNYkWb",
|
"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
|
## Subscribe to topics
|
||||||
|
|
||||||
You can subscribe to topics using `ntfy subscribe`. Depending on how it is called, this command
|
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:
|
in which the command can be run:
|
||||||
|
|
||||||
### Stream messages as JSON
|
### Stream messages as JSON
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy subscribe TOPIC
|
ntfy subscribe TOPIC
|
||||||
```
|
```
|
||||||
|
|
||||||
If you run the command like this, it prints the JSON representation of every incoming message. This is useful
|
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
|
when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command
|
||||||
stays open forever.
|
stays open forever.
|
||||||
|
|
||||||
```
|
```sh
|
||||||
$ ntfy sub mytopic
|
$ ntfy sub mytopic
|
||||||
{"id":"nZ8PjH5oox","time":1639971913,"event":"message","topic":"mytopic","message":"hi there"}
|
{"id":"nZ8PjH5oox","time":1639971913,"event":"message","topic":"mytopic","message":"hi there"}
|
||||||
{"id":"sekSLWTujn","time":1639972063,"event":"message","topic":"mytopic",priority:5,"message":"Oh no!"}
|
{"id":"sekSLWTujn","time":1639972063,"event":"message","topic":"mytopic",priority:5,"message":"Oh no!"}
|
||||||
|
@ -147,13 +161,15 @@ $ ntfy sub mytopic
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
### Run command for every message
|
### Run command for every message
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy subscribe TOPIC COMMAND
|
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
|
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:
|
environment variables. Here are a few examples:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
ntfy sub mytopic 'notify-send "$m"'
|
ntfy sub mytopic 'notify-send "$m"'
|
||||||
ntfy sub topic1 /my/script.sh
|
ntfy sub topic1 /my/script.sh
|
||||||
ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had priority $p'
|
ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had priority $p'
|
||||||
|
@ -169,7 +185,7 @@ these are environment variables, you typically don't have to worry about quoting
|
||||||
in double-quotes, you should be fine:
|
in double-quotes, you should be fine:
|
||||||
|
|
||||||
| Variable | Aliases | Description |
|
| Variable | Aliases | Description |
|
||||||
|------------------|----------------------------|----------------------------------------|
|
| ---------------- | -------------------------- | -------------------------------------- |
|
||||||
| `$NTFY_ID` | `$id` | Unique message ID |
|
| `$NTFY_ID` | `$id` | Unique message ID |
|
||||||
| `$NTFY_TIME` | `$time` | Unix timestamp of the message delivery |
|
| `$NTFY_TIME` | `$time` | Unix timestamp of the message delivery |
|
||||||
| `$NTFY_TOPIC` | `$topic` | Topic name |
|
| `$NTFY_TOPIC` | `$topic` | Topic name |
|
||||||
|
@ -180,15 +196,18 @@ in double-quotes, you should be fine:
|
||||||
| `$NTFY_RAW` | `$raw` | Raw JSON message |
|
| `$NTFY_RAW` | `$raw` | Raw JSON message |
|
||||||
|
|
||||||
### Subscribe to multiple topics
|
### Subscribe to multiple topics
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy subscribe --from-config
|
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`,
|
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).
|
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:
|
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)"
|
=== "~/.config/ntfy/client.yml (Linux)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
subscribe:
|
subscribe:
|
||||||
- topic: echo-this
|
- topic: echo-this
|
||||||
|
@ -210,8 +229,8 @@ Here's an example config file that subscribes to three different topics, executi
|
||||||
fi
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
=== "~/Library/Application Support/ntfy/client.yml (macOS)"
|
=== "~/Library/Application Support/ntfy/client.yml (macOS)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
subscribe:
|
subscribe:
|
||||||
- topic: echo-this
|
- 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)"
|
=== "%AppData%\ntfy\client.yml (Windows)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
subscribe:
|
subscribe:
|
||||||
- topic: echo-this
|
- 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:
|
In this example, when `ntfy subscribe --from-config` is executed:
|
||||||
|
|
||||||
* Messages to `echo-this` simply echos to standard out
|
- 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),
|
- 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)
|
[notifu](https://www.paralint.com/projects/notifu/) (Windows) or `osascript` (macOS)
|
||||||
* Messages to `calc` open the calculator 😀 (*because, why not*)
|
- 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 `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:
|
I hope this shows how powerful this command is. Here's a short video that demonstrates the above example:
|
||||||
|
|
||||||
|
@ -263,6 +283,7 @@ will be used, otherwise, the subscription settings will override the defaults.
|
||||||
require authentication), be sure that the servers/topics you subscribe to use HTTPS to prevent leaking the username and password.
|
require authentication), be sure that the servers/topics you subscribe to use HTTPS to prevent leaking the username and password.
|
||||||
|
|
||||||
### Using the systemd service
|
### 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))
|
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)
|
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`.
|
if you install the deb/rpm package. To configure it, simply edit `/etc/ntfy/client.yml` and run `sudo systemctl restart ntfy-client`.
|
||||||
|
@ -280,15 +301,17 @@ You can either manually override these systemd service entries with `sudo system
|
||||||
after editing the service file:
|
after editing the service file:
|
||||||
|
|
||||||
=== "/etc/systemd/system/ntfy-client.service.d/override.conf"
|
=== "/etc/systemd/system/ntfy-client.service.d/override.conf"
|
||||||
```
|
|
||||||
|
```ini
|
||||||
[Service]
|
[Service]
|
||||||
User=phil
|
User=phil
|
||||||
Group=phil
|
Group=phil
|
||||||
Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
|
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:
|
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' <<EOF
|
sudo sh -c 'cat > /etc/systemd/system/ntfy-client.service.d/override.conf' <<EOF
|
||||||
[Service]
|
[Service]
|
||||||
User=$USER
|
User=$USER
|
||||||
|
@ -300,8 +323,8 @@ sudo systemctl daemon-reload
|
||||||
sudo systemctl restart ntfy-client
|
sudo systemctl restart ntfy-client
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
|
|
||||||
Depending on whether the server is configured to support [access control](../config.md#access-control), some topics
|
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.
|
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](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
To publish/subscribe to protected topics, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
||||||
|
@ -310,6 +333,7 @@ your password.
|
||||||
|
|
||||||
You can either add your username and password to the configuration file:
|
You can either add your username and password to the configuration file:
|
||||||
=== "~/.config/ntfy/client.yml"
|
=== "~/.config/ntfy/client.yml"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- topic: secret
|
- topic: secret
|
||||||
command: 'notify-send "$m"'
|
command: 'notify-send "$m"'
|
||||||
|
@ -318,7 +342,8 @@ You can either add your username and password to the configuration file:
|
||||||
```
|
```
|
||||||
|
|
||||||
Or with the `ntfy subscibe` command:
|
Or with the `ntfy subscibe` command:
|
||||||
```
|
|
||||||
|
```sh
|
||||||
ntfy subscribe \
|
ntfy subscribe \
|
||||||
-u phil:mypass \
|
-u phil:mypass \
|
||||||
ntfy.example.com/mysecrets
|
ntfy.example.com/mysecrets
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Subscribe from your phone
|
# Subscribe from your phone
|
||||||
|
|
||||||
You can use the ntfy [Android App](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [iOS app](https://apps.apple.com/us/app/ntfy/id1625396347)
|
You can use the ntfy [Android App](https://play.google.com/store/apps/details?id=io.heckel.ntfy) or [iOS app](https://apps.apple.com/us/app/ntfy/id1625396347)
|
||||||
to receive notifications directly on your phone. Just like the server, this app is also open source, and the code is available
|
to receive notifications directly on your phone. Just like the server, this app is also open source, and the code is available
|
||||||
on GitHub ([Android](https://github.com/binwiederhier/ntfy-android), [iOS](https://github.com/binwiederhier/ntfy-ios)). Feel free to
|
on GitHub ([Android](https://github.com/binwiederhier/ntfy-android), [iOS](https://github.com/binwiederhier/ntfy-ios)). Feel free to
|
||||||
|
@ -13,6 +14,7 @@ from [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/). Both are largel
|
||||||
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).
|
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
|
## Overview
|
||||||
|
|
||||||
A picture is worth a thousand words. Here are a few screenshots showing what the app looks like. It's all pretty
|
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.
|
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:
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
## Message priority
|
## Message priority
|
||||||
|
|
||||||
_Supported on:_ :material-android: :material-apple:
|
_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
|
When you [publish messages](../publish.md#message-priority) to a topic, you can **define a priority**. This priority defines
|
||||||
|
@ -63,6 +66,7 @@ setting, and other settings such as popover or notification dot:
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
## Instant delivery
|
## Instant delivery
|
||||||
|
|
||||||
_Supported on:_ :material-android:
|
_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.
|
Instant delivery allows you to receive messages on your phone instantly, **even when your phone is in doze mode**, i.e.
|
||||||
|
@ -88,13 +92,14 @@ To do so, long-press on the foreground notification (screenshot above) and navig
|
||||||
suddenly had 10 messages that were sent long before you know what I'm talking about.
|
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
|
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
|
_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.
|
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.
|
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.
|
It won't use Firebase for any self-hosted servers, and not at all in the the F-Droid flavor.
|
||||||
|
|
||||||
## Share to topic
|
## Share to topic
|
||||||
|
|
||||||
_Supported on:_ :material-android:
|
_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
|
You can share files to a topic using Android's "Share" feature. This works in almost any app that supports sharing files
|
||||||
|
@ -109,6 +114,7 @@ The feature is pretty self-explanatory, and one picture says more than a thousan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## ntfy:// links
|
## ntfy:// links
|
||||||
|
|
||||||
_Supported on:_ :material-android:
|
_Supported on:_ :material-android:
|
||||||
|
|
||||||
The ntfy Android app supports deep linking directly to topics. This is useful when integrating with [automation apps](#automation-apps)
|
The ntfy Android app supports deep linking directly to topics. This is useful when integrating with [automation apps](#automation-apps)
|
||||||
|
@ -122,13 +128,14 @@ or to simply directly link to a topic from a mobile website.
|
||||||
**Supported link formats:**
|
**Supported link formats:**
|
||||||
|
|
||||||
| Link format | Example | Description |
|
| Link format | Example | Description |
|
||||||
|-------------------------------------------------------------------------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
| ----------------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| <span style="white-space: nowrap">`ntfy://<host>/<topic>`</span> | `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!) |
|
| <span style="white-space: nowrap">`ntfy://<host>/<topic>`</span> | `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!) |
|
||||||
| <span style="white-space: nowrap">`ntfy://<host>/<topic>?secure=false`</span> | `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!) |
|
| <span style="white-space: nowrap">`ntfy://<host>/<topic>?secure=false`</span> | `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
|
## Integrations
|
||||||
|
|
||||||
### UnifiedPush
|
### UnifiedPush
|
||||||
|
|
||||||
_Supported on:_ :material-android:
|
_Supported on:_ :material-android:
|
||||||
|
|
||||||
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
|
[UnifiedPush](https://unifiedpush.org) is a standard for receiving push notifications without using the Google-owned
|
||||||
|
@ -146,6 +153,7 @@ to handle messages. Here's an example with [FluffyChat](https://fluffychat.im/):
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Automation apps
|
### Automation apps
|
||||||
|
|
||||||
_Supported on:_ :material-android:
|
_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)
|
The ntfy Android app integrates nicely with automation apps such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
|
||||||
|
@ -153,6 +161,7 @@ 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**, as well as **send messages**.
|
||||||
|
|
||||||
#### React to incoming 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
|
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)).
|
[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)
|
Here's an example using [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
|
||||||
|
@ -181,28 +190,29 @@ notification popups:
|
||||||
Here's a list of extras you can access. Most likely, you'll want to filter for `topic` and react on `message`:
|
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 |
|
| Extra name | Type | Example | Description |
|
||||||
|----------------------|------------------------------|------------------------------------------|------------------------------------------------------------------------------------|
|
| -------------------- | ---------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||||
| `id` | *String* | `bP8dMjO8ig` | Randomly chosen message identifier (likely not very useful for task automation) |
|
| `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 |
|
| `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** |
|
| `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` | _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` |
|
| `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 |
|
| `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 |
|
| `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` ❤️ | _String_ | `Some message` | Message body; **this is likely what you're interested in** |
|
||||||
| `message_bytes` | *ByteArray* | `(binary data)` | Message body as binary data |
|
| `message_bytes` | _ByteArray_ | `(binary data)` | Message body as binary data |
|
||||||
| `encoding`️ | *String* | - | Message encoding (empty or "base64") |
|
| `encoding`️ | _String_ | - | Message encoding (empty or "base64") |
|
||||||
| `tags` | *String* | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
|
| `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 |
|
| `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 |
|
| `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 |
|
| `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_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_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_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_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 |
|
| `attachment_url` | _String_ | `https://ntfy.sh/file/afUbjadfl7ErP.jpg` | URL of the attachment; may be empty if not set |
|
||||||
|
|
||||||
#### Send messages using intents
|
#### Send messages using intents
|
||||||
|
|
||||||
To send messages from other apps (such as [MacroDroid](https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid)
|
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
|
broadcast an intent with the `io.heckel.ntfy.SEND_MESSAGE` action. The ntfy Android app will forward the intent as a HTTP
|
||||||
|
@ -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:
|
The following intent extras are supported when for the intent with the `io.heckel.ntfy.SEND_MESSAGE` action:
|
||||||
|
|
||||||
| Extra name | Required | Type | Example | Description |
|
| 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` |
|
| `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** |
|
| `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 |
|
| `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** |
|
| `message` ❤️ | ✔ | _String_ | `Some message` | Message body; **you must set this** |
|
||||||
| `tags` | - | *String* | `tag1,tag2,..` | Comma-separated list of [tags](../publish.md#tags-emojis) |
|
| `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 |
|
| `priority` | - | _String or Int (between 1-5)_ | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Subscribe from the Web UI
|
# 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
|
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.
|
keep a connection open and listen for incoming notifications.
|
||||||
|
|
||||||
To learn how to send messages, check out the [publishing page](../publish.md).
|
To learn how to send messages, check out the [publishing page](../publish.md).
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
# Troubleshooting
|
# 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)
|
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.
|
and ask there. We're happy to help.
|
||||||
|
|
||||||
## ntfy server
|
## 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
|
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
|
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:
|
boils down to setting `log-level: debug` or `log-level: trace` in the `server.yml` file:
|
||||||
|
|
||||||
=== "server.yml (debug)"
|
=== "server.yml (debug)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
log-level: debug
|
log-level: debug
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "server.yml (trace)"
|
=== "server.yml (trace)"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
log-level: trace
|
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:
|
the logs using `journalctl -u ntfy -f`. The logs will look something like this:
|
||||||
|
|
||||||
=== "Example logs (debug)"
|
=== "Example logs (debug)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ntfy serve --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)
|
2023/03/20 14:45:38 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is DEBUG (tag=startup)
|
||||||
|
@ -37,6 +42,7 @@ the logs using `journalctl -u ntfy -f`. The logs will look something like this:
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Example logs (trace)"
|
=== "Example logs (trace)"
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ntfy serve --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)
|
2023/03/20 14:40:42 INFO Listening on :2586[http] :1025[smtp], ntfy 2.1.2, log level is TRACE (tag=startup)
|
||||||
|
@ -65,6 +71,7 @@ the logs using `journalctl -u ntfy -f`. The logs will look something like this:
|
||||||
```
|
```
|
||||||
|
|
||||||
## Android app
|
## Android app
|
||||||
|
|
||||||
On Android, you can turn on logging in the settings under **Settings → Record logs**. This will store up to 1,000 log
|
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.
|
||||||
|
|
||||||
|
@ -119,6 +126,7 @@ adb -s 192.168.1.137:39539 logcat --pid=$(adb -s 192.168.1.137:39539 shell pidof
|
||||||
```
|
```
|
||||||
|
|
||||||
## Web app
|
## 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.
|
keyboard.
|
||||||
|
|
||||||
|
@ -128,4 +136,5 @@ keyboard.
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
## iOS app
|
## 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.
|
Sorry, there is no way to debug or get the logs from the iOS app (yet), outside of running the app in Xcode.
|
||||||
|
|
|
@ -114,9 +114,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -175,9 +173,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -236,9 +232,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -302,9 +296,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -364,9 +356,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -426,9 +416,7 @@
|
||||||
"justifyMode": "auto",
|
"justifyMode": "auto",
|
||||||
"orientation": "auto",
|
"orientation": "auto",
|
||||||
"reduceOptions": {
|
"reduceOptions": {
|
||||||
"calcs": [
|
"calcs": ["last"],
|
||||||
"last"
|
|
||||||
],
|
|
||||||
"fields": "",
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
|
@ -1083,9 +1071,7 @@
|
||||||
"id": 41,
|
"id": 41,
|
||||||
"options": {
|
"options": {
|
||||||
"legend": {
|
"legend": {
|
||||||
"calcs": [
|
"calcs": ["mean"],
|
||||||
"mean"
|
|
||||||
],
|
|
||||||
"displayMode": "table",
|
"displayMode": "table",
|
||||||
"placement": "right",
|
"placement": "right",
|
||||||
"showLegend": true,
|
"showLegend": true,
|
||||||
|
@ -1179,9 +1165,7 @@
|
||||||
"id": 16,
|
"id": 16,
|
||||||
"options": {
|
"options": {
|
||||||
"legend": {
|
"legend": {
|
||||||
"calcs": [
|
"calcs": ["mean"],
|
||||||
"mean"
|
|
||||||
],
|
|
||||||
"displayMode": "table",
|
"displayMode": "table",
|
||||||
"placement": "right",
|
"placement": "right",
|
||||||
"showLegend": true,
|
"showLegend": true,
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>ntfy.sh: EventSource Example</title>
|
<title>ntfy.sh: EventSource Example</title>
|
||||||
<meta name="robots" content="noindex, nofollow" />
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
<style>
|
<style>
|
||||||
body { font-size: 1.2em; line-height: 130%; }
|
body {
|
||||||
#events { font-family: monospace; }
|
font-size: 1.2em;
|
||||||
|
line-height: 130%;
|
||||||
|
}
|
||||||
|
#events {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>ntfy.sh: EventSource Example</h1>
|
<h1>ntfy.sh: EventSource Example</h1>
|
||||||
<p>
|
<p>
|
||||||
This is an example showing how to use <a href="https://ntfy.sh">ntfy.sh</a> with
|
This is an example showing how to use
|
||||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource</a>.<br/>
|
<a href="https://ntfy.sh">ntfy.sh</a> with
|
||||||
This example doesn't need a server. You can just save the HTML page and run it from anywhere.
|
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource"
|
||||||
|
>EventSource</a
|
||||||
|
>.<br />
|
||||||
|
This example doesn't need a server. You can just save the HTML page and
|
||||||
|
run it from anywhere.
|
||||||
</p>
|
</p>
|
||||||
<button id="publishButton">Send test notification</button>
|
<button id="publishButton">Send test notification</button>
|
||||||
<p><b>Log:</b></p>
|
<p><b>Log:</b></p>
|
||||||
|
@ -23,34 +32,33 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
const publishURL = `https://ntfy.sh/example`;
|
const publishURL = `https://ntfy.sh/example`;
|
||||||
const subscribeURL = `https://ntfy.sh/example/sse`;
|
const subscribeURL = `https://ntfy.sh/example/sse`;
|
||||||
const events = document.getElementById('events');
|
const events = document.getElementById("events");
|
||||||
const eventSource = new EventSource(subscribeURL);
|
const eventSource = new EventSource(subscribeURL);
|
||||||
|
|
||||||
// Publish button
|
// Publish button
|
||||||
document.getElementById("publishButton").onclick = () => {
|
document.getElementById("publishButton").onclick = () => {
|
||||||
fetch(publishURL, {
|
fetch(publishURL, {
|
||||||
method: 'POST', // works with PUT as well, though that sends an OPTIONS request too!
|
method: "POST", // works with PUT as well, though that sends an OPTIONS request too!
|
||||||
body: `It is ${new Date().toString()}. This is a test.`
|
body: `It is ${new Date().toString()}. This is a test.`,
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Incoming events
|
// Incoming events
|
||||||
eventSource.onopen = () => {
|
eventSource.onopen = () => {
|
||||||
let event = document.createElement('div');
|
let event = document.createElement("div");
|
||||||
event.innerHTML = `EventSource connected to ${subscribeURL}`;
|
event.innerHTML = `EventSource connected to ${subscribeURL}`;
|
||||||
events.appendChild(event);
|
events.appendChild(event);
|
||||||
};
|
};
|
||||||
eventSource.onerror = (e) => {
|
eventSource.onerror = (e) => {
|
||||||
let event = document.createElement('div');
|
let event = document.createElement("div");
|
||||||
event.innerHTML = `EventSource error: Failed to connect to ${subscribeURL}`;
|
event.innerHTML = `EventSource error: Failed to connect to ${subscribeURL}`;
|
||||||
events.appendChild(event);
|
events.appendChild(event);
|
||||||
};
|
};
|
||||||
eventSource.onmessage = (e) => {
|
eventSource.onmessage = (e) => {
|
||||||
let event = document.createElement('div');
|
let event = document.createElement("div");
|
||||||
event.innerHTML = e.data;
|
event.innerHTML = e.data;
|
||||||
events.appendChild(event);
|
events.appendChild(event);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -98,5 +98,3 @@ nav:
|
||||||
- "Deprecation notices": deprecations.md
|
- "Deprecation notices": deprecations.md
|
||||||
- "Development": develop.md
|
- "Development": develop.md
|
||||||
- "Privacy policy": privacy.md
|
- "Privacy policy": privacy.md
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
# fbsend
|
# fbsend
|
||||||
|
|
||||||
fbsend is a tiny tool to send data messages to Firebase. It's only used for testing.
|
fbsend is a tiny tool to send data messages to Firebase. It's only used for testing.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue