Browse Source

WIP: Docs

Philipp Heckel 3 years ago
parent
commit
ae7bfb2c97
10 changed files with 480 additions and 1 deletions
  1. 1 0
      .gitignore
  2. 3 1
      config/config.yml
  3. 108 0
      docs/config.md
  4. 5 0
      docs/develop.md
  5. 1 0
      docs/examples.md
  6. 47 0
      docs/faq.md
  7. 10 0
      docs/index.md
  8. 94 0
      docs/install.md
  9. 207 0
      docs/publish/index.md
  10. 4 0
      docs/static/css/extra.css

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 dist/
 .idea/
+site/
 *.iml

+ 3 - 1
config/config.yml

@@ -6,7 +6,7 @@
 # listen-http: ":80"
 
 # 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 save battery when using the Android app.
 #
 # firebase-key-file: <filename>
 
@@ -23,6 +23,8 @@
 # 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: 30s
 
 # Interval in which the manager prunes old messages, deletes topics

+ 108 - 0
docs/config.md

@@ -0,0 +1,108 @@
+# Configuring the ntfy server
+The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/config.yml`, 
+see [config.yml](https://github.com/binwiederhier/ntfy/blob/main/config/config.yml)), via command line arguments 
+or using environment variables.
+
+## Quick start
+By default, simply running `ntfy` will start the server at port 80. No configuration needed. Batteries included ๐Ÿ˜€. 
+If everything works as it should, you'll see something like this:
+```
+$ ntfy                
+2021/11/30 19:59:08 Listening on :80
+```
+
+You can immediately start [publishing messages](publish/index.md), or subscribe via the [Android app](subscribe/phone.md),
+[the web UI](subscribe/web.md), or simply via [curl or your favorite HTTP client](subscribe/api.md). To configure 
+the server further, check out the [config options table](#config-options) or simply type `ntfy --help` to
+get a list of [command line options](#command-line-options).
+
+## Config options
+Each config options can be set in the config file `/etc/ntfy/config.yml` (e.g. `listen-http: :80`) or as a 
+CLI option (e.g. `--listen-http :80`. Here's a list of all available options. Alternatively, you can set an environment
+variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
+
+| Config option | Env variable | Format | Default | Description |
+|---|---|---|---|---|
+| `listen-http` | `NTFY_LISTEN_HTTP` | `[host]:port` | `:80` | Listen address for the HTTP web server |
+| `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. |
+| `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. |
+| `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. |
+| `keepalive-interval` | `NTFY_KEEPALIVE_INTERVAL` | *duration* | 30s | Interval in which keepalive messages are sent to the client. This is to prevent intermediaries closing the connection for inactivity. Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. |
+| `manager-interval` | `$NTFY_MANAGER_INTERVAL` | *duration* | 1m | Interval in which the manager prunes old messages, deletes topics and prints the stats. |
+| `global-topic-limit` | `NTFY_GLOBAL_TOPIC_LIMIT` | *number* | 5000 | Rate limiting: Total number of topics before the server rejects new topics. |
+| `visitor-subscription-limit` | `NTFY_VISITOR_SUBSCRIPTION_LIMIT` | *number* | 30 | Rate limiting: Number of subscriptions per visitor (IP address) |
+| `visitor-request-limit-burst` | `NTFY_VISITOR_REQUEST_LIMIT_BURST` | *number* | 60 | 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* | 10s | Strongly related to `visitor-request-limit-burst`: The rate at which the bucket is refilled |
+| `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. |
+
+The format for a *duration* is: `<number>(smh)`, e.g. 30s, 20m or 1h.
+
+## Firebase (FCM)
+!!! info
+    Using Firebase is **optional** and only works if you modify and build your own Android .apk.
+    For a self-hosted instance, it's easier to just not bother with FCM.
+
+[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) is the Google approved way to send
+push messages to Android devices. FCM is the only method that an Android app can receive messages without having to run a
+[foreground service](https://developer.android.com/guide/components/foreground-services). 
+
+For the main host [ntfy.sh](https://ntfy.sh), the [ntfy Android App](subscribe/phone.md) uses Firebase to send messages
+to the device. For other hosts, instant delivery is used and FCM is not involved.
+
+To configure FCM for your self-hosted instance of the ntfy server, follow these steps:
+
+1. Sign up for a [Firebase account](https://console.firebase.google.com/)
+2. Create an app and download the key file (e.g. `myapp-firebase-adminsdk-ahnce-....json`)
+3. Place the key file in `/etc/ntfy`, set the `firebase-key-file` in `config.yml` accordingly and restart the ntfy server
+4. Build your own Android .apk following [these instructions]()
+
+Example:
+```
+# 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).
+#
+firebase-key-file: "/etc/ntfy/ntfy-sh-firebase-adminsdk-ahnce-9f4d6f14b5.json"
+```
+
+## Behind a proxy (TLS, etc.)
+
+!! warn
+If you are behind a proxy, you must set the `behind-proxy` flag. Otherwise all visitors are rate limited
+as if they are one.
+
+
+## Rate limiting
+Rate limiting: Allowed GET/PUT/POST requests per second, per visitor:
+- visitor-request-limit-burst is the initial bucket of requests each visitor has
+- visitor-request-limit-replenish is the rate at which the bucket is refilled
+
+
+## Command line options
+```
+$ ntfy --help
+NAME:
+   ntfy - Simple pub-sub notification service
+
+USAGE:
+   ntfy [OPTION..]
+
+GLOBAL OPTIONS:
+   --config value, -c value                           config file (default: /etc/ntfy/config.yml) [$NTFY_CONFIG_FILE]
+   --listen-http value, -l value                      ip:port used to as listen address (default: ":80") [$NTFY_LISTEN_HTTP]
+   --firebase-key-file value, -F value                Firebase credentials file; if set additionally publish to FCM topic [$NTFY_FIREBASE_KEY_FILE]
+   --cache-file value, -C value                       cache file used for message caching [$NTFY_CACHE_FILE]
+   --cache-duration since, -b since                   buffer messages for this time to allow since requests (default: 12h0m0s) [$NTFY_CACHE_DURATION]
+   --keepalive-interval value, -k value               interval of keepalive messages (default: 30s) [$NTFY_KEEPALIVE_INTERVAL]
+   --manager-interval value, -m value                 interval of for message pruning and stats printing (default: 1m0s) [$NTFY_MANAGER_INTERVAL]
+   --global-topic-limit value, -T value               total number of topics allowed (default: 5000) [$NTFY_GLOBAL_TOPIC_LIMIT]
+   --visitor-subscription-limit value, -V value       number of subscriptions per visitor (default: 30) [$NTFY_VISITOR_SUBSCRIPTION_LIMIT]
+   --visitor-request-limit-burst value, -B value      initial limit of requests per visitor (default: 60) [$NTFY_VISITOR_REQUEST_LIMIT_BURST]
+   --visitor-request-limit-replenish value, -R value  interval at which burst limit is replenished (one per x) (default: 10s) [$NTFY_VISITOR_REQUEST_LIMIT_REPLENISH]
+   --behind-proxy, -P                                 if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting) (default: false) [$NTFY_BEHIND_PROXY]
+
+Try 'ntfy COMMAND --help' for more information.
+
+ntfy v1.4.8 (7b8185c), runtime go1.17, built at 1637872539
+Copyright (C) 2021 Philipp C. Heckel, distributed under the Apache License 2.0
+```
+

+ 5 - 0
docs/develop.md

@@ -0,0 +1,5 @@
+# Building
+
+## ntfy server
+
+## Android app

+ 1 - 0
docs/examples.md

@@ -0,0 +1 @@
+# Examples

+ 47 - 0
docs/faq.md

@@ -0,0 +1,47 @@
+# Frequently asked questions (FAQ)
+
+## Isn't this like ...?
+Who knows. I didn't do a lot of research before making this. It was fun making it.
+
+## Can I use this in my app? Will it stay free?
+Yes. As long as you don't abuse it, it'll be available and free of charge. I do not plan on monetizing
+the service.
+
+## What are the uptime guarantees?
+Best effort.
+
+## What happens if there are multiple subscribers to the same topic?
+As per usual with pub-sub, all subscribers receive notifications if they are
+subscribed to a topic.
+
+## Will you know what topics exist, can you spy on me?
+If you don't trust me or your messages are sensitive, run your own server. It's <a href="https://github.com/binwiederhier/ntfy">open source</a>.
+That said, the logs do not contain any topic names or other details about you.
+Messages are cached for the duration configured in `config.yml` (12h by default) to facilitate service restarts, message polling and to overcome
+client network disruptions.
+
+## Can I self-host it?
+Yes. The server (including this Web UI) can be self-hosted, and the Android app supports adding topics from
+your own server as well. There are <a href="https://github.com/binwiederhier/ntfy#installation">install instructions</a>
+on GitHub.
+
+## Why is Firebase used?
+In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
+published to Firebase Cloud Messaging (FCM) (if `FirebaseKeyFile` is set, which it is on ntfy.sh). This
+is to facilitate instant notifications on Android.
+    </p>
+
+## How much battery does the Android app use?
+If you use the ntfy.sh server and you don't use the <i>instant delivery</i> feature, the Android app uses no
+additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server, or you use
+<i>instant delivery</i>, the app has to maintain a constant connection to the server, which consumes about 4% of
+battery in 17h of use (on my phone). I use it and it makes no difference to me.
+
+## What is instant delivery?
+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 <a href="#battery-usage">additional battery</a>,
+but delivers notifications instantly.
+
+## Why is there no iOS app (yet)?
+I don't have an iPhone or a Mac, so I didn't make an iOS app yet. It'd be awesome if
+<a href="https://github.com/binwiederhier/ntfy/issues/4">someone else could help out</a>.

+ 10 - 0
docs/index.md

@@ -0,0 +1,10 @@
+# ntfy.sh | simple HTTP-based pub-sub
+
+**ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
+notification service. It allows you to send notifications to your phone or desktop via scripts from any computer,
+entirely **without signup, cost or setup**. It's also [open source](https://github.com/binwiederhier/ntfy) if you want 
+to run your own.
+
+(pub sub diagram)
+
+(screenshot / video / gif)

+ 94 - 0
docs/install.md

@@ -0,0 +1,94 @@
+# Install your own ntfy server
+The following steps are only required if you want to **self-host your own ntfy server**. If you just want to 
+[send messages using ntfy.sh](publish/index.md), you don't need to install anything. Just use `curl`
+or your favorite HTTP client.
+
+## General steps
+The ntfy server comes as a statically linked binary and is shipped as tarball, deb/rpm packages and as a Docker image.
+We support amd64, armv7 and arm64.
+
+1. Install ntfy using one of the methods described below
+2. Then (optionally) edit `/etc/ntfy/config.yml` (see [configuration](config.md))
+3. Then just run it with `ntfy` (or `systemctl start ntfy` when using the deb/rpm).
+
+
+## Binaries and packages
+Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
+deb/rpm packages.
+
+x86_64/amd64:
+```
+wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_x86_64.tar.gz
+sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
+```
+
+armv7:
+```
+wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.tar.gz
+sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
+```
+
+arm64/v8:
+```
+wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.tar.gz
+sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
+```
+
+## Debian/Ubuntu repository
+Installation via Debian repository:
+```bash
+curl -sSL https://archive.heckel.io/apt/pubkey.txt | sudo apt-key add -
+sudo apt install apt-transport-https
+sudo sh -c "echo 'deb [arch=amd64] https://archive.heckel.io/apt debian main' > /etc/apt/sources.list.d/archive.heckel.io.list"  
+sudo apt update
+sudo apt install ntfy
+```
+
+Manually installing the .deb file:
+```bash
+wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.deb
+dpkg -i ntfy_1.5.0_amd64.deb
+```
+
+## Fedora/RHEL/CentOS
+```bash
+rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.rpm
+```
+
+## Docker
+The ntfy server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent 
+message cache, you also need to map a volume to `/var/cache/ntfy`. To change other settings, you should map `/etc/ntfy`,
+so you can edit `/etc/ntfy/config.yml`.
+
+Basic usage (no cache or additional config):
+```
+docker run -p 80:80 -it binwiederhier/ntfy
+```
+
+With persistent cache (configured as command line arguments):
+```bash
+docker run \
+  -v /var/cache/ntfy:/var/cache/ntfy \
+  -p 80:80 \
+  -it \
+  binwiederhier/ntfy \
+    --cache-file /var/cache/ntfy/cache.db
+```
+
+With other config options (configured via `/etc/ntfy/config.yml`, see [configuration](config.md) for details):
+```bash
+docker run \
+  -v /etc/ntfy:/etc/ntfy \
+  -p 80:80 \
+  -it \
+  binwiederhier/ntfy
+```
+
+## Go
+To install via Go, simply run:
+```bash
+go install heckel.io/ntfy@latest
+```
+!!! info
+    Please [let me know](https://github.com/binwiederhier/ntfy/issues) if there are any issues with this installation
+    method. The SQLite bindings require CGO and it works for me, but I have the feeling it may not work for everyone.

+ 207 - 0
docs/publish/index.md

@@ -0,0 +1,207 @@
+# Publishing
+
+Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them.
+Because there is no sign-up, <b>the topic is essentially a password</b>, so pick something that's not easily guessable.
+
+Here's an example showing how to publish a simple message using a POST request:
+=== "Command line (curl)"
+    ```
+    curl -d "Backup successful ๐Ÿ˜€" ntfy.sh/mytopic
+    ```
+
+=== "HTTP"
+    ``` http
+    POST /mytopic HTTP/1.1
+    Host: ntfy.sh
+
+    Backup successful ๐Ÿ˜€
+    ```
+=== "JavaScript"
+    ``` javascript
+    fetch('https://ntfy.sh/mytopic', {
+      method: 'POST', // PUT works too
+      body: 'Backup successful ๐Ÿ˜€'
+    })
+    ```
+
+=== "Go"
+    ``` go
+    http.Post("https://ntfy.sh/mytopic", "text/plain",
+        strings.NewReader("Backup successful ๐Ÿ˜€"))
+    ```
+
+=== "PHP"
+    ``` php
+    file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
+        'http' => [
+            'method' => 'POST', // PUT also works
+            'header' => 'Content-Type: text/plain',
+            'content' => 'Backup successful ๐Ÿ˜€'
+        ]
+    ]));
+    ```
+
+If you have the [Android app](../subscribe/phone.md) installed on your phone, this will create a notification that looks like this:
+
+<figure markdown>
+  ![basic notification](../static/img/basic-notification.png){ width=500 }
+  <figcaption>Android notification</figcaption>
+</figure>
+
+There are more features related to publishing messages: You can set a [notification priority](#message-priority), 
+a [title](#message-title), and [tag messages](#tags-emojis) ๐Ÿฅณ ๐ŸŽ‰. Here's an example that uses all of them at once:
+
+=== "Command line (curl)"
+    ```
+    curl \
+      -H "Title: Unauthorized access detected" \
+      -H "Priority: urgent" \
+      -H "Tags: warning,skull" \
+      -d "Remote access to phils-laptop detected. Act right away." \
+      ntfy.sh/phil_alerts
+    ```
+
+=== "HTTP"
+    ``` http
+    POST /phil_alerts HTTP/1.1
+    Host: ntfy.sh
+    Title: Unauthorized access detected
+    Priority: urgent
+    Tags: warning,skull
+    
+    Remote access to phils-laptop detected. Act right away.
+    ```
+
+=== "JavaScript"
+    ``` javascript
+    fetch('https://ntfy.sh/phil_alerts', {
+        method: 'POST', // PUT works too
+        body: 'Remote access to phils-laptop detected. Act right away.',
+        headers: {
+            'Title': 'Unauthorized access detected',
+            'Priority': 'urgent',
+            'Tags': 'warning,skull'
+        }
+    })
+    ```
+
+=== "Go"
+    ``` go
+	req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts",
+		strings.NewReader("Remote access to phils-laptop detected. Act right away."))
+	req.Header.Set("Title", "Unauthorized access detected")
+	req.Header.Set("Priority", "urgent")
+	req.Header.Set("Tags", "warning,skull")
+	http.DefaultClient.Do(req)
+    ```
+
+=== "PHP"
+    ``` php
+    file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
+        'http' => [
+            'method' => 'POST', // PUT also works
+            'header' =>
+                "Content-Type: text/plain\r\n" .
+                "Title: Unauthorized access detected\r\n" .
+                "Priority: urgent\r\n" .
+                "Tags: warning,skull",
+            'content' => 'Remote access to phils-laptop detected. Act right away.'
+        ]
+    ]));
+    ```
+
+<figure markdown>
+  ![priority notification](../static/img/priority-notification.png){ width=500 }
+  <figcaption>Urgent notification with tags and title</figcaption>
+</figure>
+
+## Message priority
+All messages have a priority, which defines how urgently your phone notifies you. You can set custom
+notification sounds and vibration patterns on your phone to map to these priorities (see [Android config](../subscribe/phone.md)).
+
+The following priorities exist:
+
+| Priority | Icon | ID | Name | Description |
+|---|---|---|---|---|
+| Max priority | ![min priority](../static/img/priority-5.svg) | `5` | `max`/`urgent` | Really long vibration bursts, default notification sound with a pop-over notification. |
+| High priority | ![min priority](../static/img/priority-4.svg) | `4` | `high` | Long vibration burst, default notification sound with a pop-over notification. |
+| **Default priority** | *(none)* | `3` | `default` | Short default vibration and sound. Default notification behavior. |
+| Low priority | ![min priority](../static/img/priority-2.svg) |`2` | `low` | No vibration or sound. Notification will not visibly show up until notification drawer is pulled down. |
+| Min priority | ![min priority](../static/img/priority-1.svg) | `1` | `min` | No vibration or sound. The notification will be under the fold in "Other notifications". |
+
+You can set the priority with the header `X-Priority` (or any of its aliases: `Priority`, `prio`, or `p`).
+
+=== "Command line (curl)"
+    ```
+    curl -H "X-Priority: 5" -d "An urgent message" ntfy.sh/phil_alerts
+    curl -H "Priority: low" -d "Low priority message" ntfy.sh/phil_alerts
+    curl -H p:4 -d "A high priority message" ntfy.sh/phil_alerts
+    ```
+
+=== "HTTP"
+    ``` http
+    POST /phil_alerts HTTP/1.1
+    Host: ntfy.sh
+    Priority: 5
+
+    An urgent message
+    ```
+
+=== "JavaScript"
+    ``` javascript
+    fetch('https://ntfy.sh/phil_alerts', {
+        method: 'POST',
+        body: 'An urgent message',
+        headers: { 'Priority': '5' }
+    })
+    ```
+
+=== "Go"
+    ``` go
+    req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts", strings.NewReader("An urgent message"))
+    req.Header.Set("Priority", "5")
+    http.DefaultClient.Do(req)
+    ```
+
+=== "PHP"
+    ``` php
+    file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
+        'http' => [
+            'method' => 'POST',
+            'header' =>
+                "Content-Type: text/plain\r\n" .
+                "Priority: 5",
+            'content' => 'An urgent message'
+        ]
+    ]));
+    ```
+
+<figure markdown>
+  ![priority notification](../static/img/priority-detail-overview.png){ width=500 }
+  <figcaption>Detail view of priority notifications</figcaption>
+</figure>
+
+## Tags & emojis ๐Ÿฅณ ๐ŸŽ‰
+You can tag messages with emojis (or other relevant strings). If a tag matches a <a href="https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json">known emoji short code</a>,
+it will be converted to an emoji. If it doesn't match, it will be listed below the notification. This is useful
+for things like warnings and such (โš ๏ธ, ๏ธ๐Ÿšจ, or ๐Ÿšฉ), but also to simply tag messages otherwise (e.g. which script the
+message came from, ...).
+
+You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, or `ta`).
+Use <a href="https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json">this reference</a>
+to figure out what tags can be converted to emojis. In the example below, the tag "warning" matches the emoji โš ๏ธ,
+the tag "ssh-login" doesn't match and will be displayed below the message.
+
+```
+$ curl -H "Tags: warning,ssh-login" -d "Unauthorized SSH access" ntfy.sh/mytopic
+{"id":"ZEIwjfHlSS",...,"tags":["warning","ssh-login"],"message":"Unauthorized SSH access"}
+```
+
+## Message title
+The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`.
+To override it, you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
+
+```
+curl -H "Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/mytopic<
+```
+        

+ 4 - 0
docs/static/css/extra.css

@@ -0,0 +1,4 @@
+figure img {
+    border-radius: 7px;
+    filter: drop-shadow(3px 3px 5px #ccc);
+}

Some files were not shown because too many files changed in this diff