Almost read to publish

This commit is contained in:
Philipp Heckel 2021-12-05 15:57:37 -05:00
parent 4fcb3891a2
commit 0f495b881a
25 changed files with 229 additions and 70 deletions

View file

@ -21,7 +21,7 @@ If desired, ntfy can temporarily keep notifications in an in-memory or an on-dis
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.
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).
@ -29,7 +29,7 @@ restart**. You can override this behavior using the following config settings:
* `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`)
Subscribers can retrieve cached messaging using the [`poll=1` parameter](subscribe/api.md#polling), as well as the Subscribers can retrieve cached messaging using the [`poll=1` parameter](subscribe/api.md#polling), as well as the
[`since=` parameter](subscribe/api.md#since). [`since=` parameter](subscribe/api.md#fetching-cached-messages).
## Behind a proxy (TLS, etc.) ## Behind a proxy (TLS, etc.)
@ -42,27 +42,27 @@ flag. This will instruct the [rate limiting](#rate-limiting) logic to use the `X
identifier for a visitor, as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will identifier for a visitor, as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will
be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address. be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address.
**TLS/SSL:** ntfy supports HTTPS/TLS by setting the `listen-https` config option. However, if you are behind a proxy, it is **TLS/SSL:** ntfy supports HTTPS/TLS by setting the `listen-https` [config option](#config-options). However, if you
recommended that TLS/SSL termination is done by the proxy itself. are behind a proxy, it is recommended that TLS/SSL termination is done by the proxy itself.
## Firebase (FCM) ## Firebase (FCM)
!!! info !!! info
Using Firebase is **optional** and only works if you modify and build your own Android .apk. 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.
[Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging) is the Google approved way to send [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 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). [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 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 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: 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/) 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`) 2. Create a Firebase app and download the key file (e.g. `myapp-firebase-adminsdk-...json`)
3. Place the key file in `/etc/ntfy`, set the `firebase-key-file` in `config.yml` accordingly and restart the ntfy server 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]() 4. Build your own Android .apk following [these instructions](develop.md#android-app)
Example: Example:
``` ```
@ -100,7 +100,7 @@ During normal usage, you shouldn't encounter this limit at all, and even if you
reconnect after a connection drop), it shouldn't have any effect. reconnect after a connection drop), it shouldn't have any effect.
## Config 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 Each config option 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 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`).
@ -110,8 +110,8 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
| `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`. |
| `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. | | `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. | | `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. | | `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. | | `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. | | `manager-interval` | `$NTFY_MANAGER_INTERVAL` | *duration* | 1m | Interval in which the manager prunes old messages, deletes topics and prints the stats. |

View file

@ -18,7 +18,7 @@ rsync -a root@laptop /backups/laptop \
## Server-sent messages in your web app ## Server-sent messages in your web app
Just as you can [subscribe to topics in the Web UI](subscribe/web.md), you can use ntfy in your own Just as you can [subscribe to topics in the Web UI](subscribe/web.md), you can use ntfy in your own
web application. Check out the <a href="example.html">live example</a> or just look the source of this page. web application. Check out the <a href="/example.html">live example</a> or just look the source of this page.
## Notify on SSH login ## Notify on SSH login
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

View file

@ -22,23 +22,24 @@ 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 app supports adding topics from 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> your own server as well. Check out the [install instructions](install.md).
on GitHub.
## Why is Firebase used? ## Why 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 instant notifications on Android. is to facilitate notifications on Android.
</p>
If you do not care for Firebase, I suggest you install the [F-Droid version](https://f-droid.org/en/packages/io.heckel.ntfy/)
of the app and [self-host your own ntfy server](install.md).
## How much battery does the Android app use? ## 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 If you use the ntfy.sh server and you don't use the [instant delivery](subscribe/phone.md#instant-delivery) feature,
additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server, or you use the Android app uses no additional battery, since Firebase Cloud Messaging (FCM) is used. If you use your own server,
<i>instant delivery</i>, the app has to maintain a constant connection to the server, which consumes about 4% of or you use *instant delivery*, 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. battery in 17h of use (on my phone). I use it, and it makes no difference to me.
## What is instant delivery? ## What is instant delivery?
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 <a href="#battery-usage">additional battery</a>, server and listens for incoming notifications. This consumes <a href="#battery-usage">additional battery</a>,
but delivers notifications instantly. but delivers notifications instantly.

View file

@ -1,8 +1,79 @@
# Getting started # Getting started
ntfy lets you **send push notifications to your phone or desktop via scripts from any computer**, using simple HTTP PUT
or POST requests. I use it to notify myself when scripts fail, or long-running commands complete.
**ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) ## Step 1: Get the app
notification service. It allows you to **send push notifications to your phone or desktop via scripts from any computer**, <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
entirely **without signup, cost or setup**. It's [open source](https://github.com/binwiederhier/ntfy) if you want to run your own. <a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
<a href="https://github.com/binwiederhier/ntfy/issues/4"><img src="../../static/img/badge-appstore.png"></a>
To [receive notifications on your phone](subscribe/phone.md), install the app, either via Google Play or F-Droid.
Once installed, open it and subscribe to a topic of your choosing. Topics don't have to explicitly be created, so just
pick a name and use it later when you [publish a message](publish.md). Note that **topic names are public, so it's wise
to choose something that cannot be guessed easily.**
For this guide, we'll just use `mytopic` as our topic name:
<figure markdown>
![adding a topic](static/img/getting-started-add.png){ width=500 }
<figcaption>Creating/adding your first topic</figcaption>
</figure>
That's it. After you tap "Subscribe", the app is listening for new messages on that topic.
## Step 2: Send a message
Now let's [send a message](publish.md) to our topic. It's easy in every language, since we're just using HTTP PUT or POST. The message
is in the request body. Here's an example showing how to publish a simple message using a POST request:
=== "Command line (curl)"
```
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-inline
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 😀'
]
]));
```
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>
That's it. You're all set. Go play and read the rest of the docs. I highly recommend reading at least the page on
[publishing messages](publish.md), as well as the detailed page on the [Android app](subscribe/phone.md).
Here's another video showing the entire process:
<figure> <figure>
<video controls muted autoplay loop width="650" src="static/img/overview.mp4"></video> <video controls muted autoplay loop width="650" src="static/img/overview.mp4"></video>

View file

@ -1,7 +1,10 @@
# Install your own ntfy server # 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 **Self-hosting your own ntfy server** is pretty straight forward. Just install the binary, package or Docker image, then
[send messages using ntfy.sh](publish.md), you don't need to install anything. Just use `curl` configure it and run it. Just like any other software. No fuzz.
or your favorite HTTP client.
!!! info
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.md), you don't need to install anything.
## 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.
@ -129,7 +132,7 @@ The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for a
straight forward to use. straight forward to use.
The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent
message cache, you also need to map a volume to `/var/cache/ntfy`. To change other settings, you should map `/etc/ntfy`, [message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings, you should map `/etc/ntfy`,
so you can edit `/etc/ntfy/config.yml`. so you can edit `/etc/ntfy/config.yml`.
Basic usage (no cache or additional config): Basic usage (no cache or additional config):

View file

@ -1,7 +1,7 @@
# Privacy policy # Privacy policy
I love free software, and I'm doing this because it's fun. I have no bad intentions, and I will I love free software, and I'm doing this because it's fun. I have no bad intentions, and **I will
never monetize or sell your information. This service will always stay free and open. never monetize or sell your information, and this service and software will always stay free and open.**
Neither the server nor the app record any personal information, or share any of the messages and topics with Neither the server nor the app record any personal information, or share any of the messages and topics with
any outside service. All data is exclusively used to make the service function properly. The only external service any outside service. All data is exclusively used to make the service function properly. The only external service

View file

@ -6,9 +6,14 @@ article {
padding-bottom: 50px; padding-bottom: 50px;
} }
figure img { figure iframe, figure img, figure video {
filter: drop-shadow(3px 3px 3px #ccc);
border-radius: 7px; border-radius: 7px;
filter: drop-shadow(3px 3px 5px #ccc); }
figure video {
width: 100%;
max-height: 450px;
} }
.remove-md-box { .remove-md-box {

BIN
docs/static/img/getting-started-add.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
docs/static/img/web-pin.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -168,12 +168,12 @@ format of the message. It's very straight forward:
| 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` | ✔️ | *int* | 1635528741 | Message date time, as Unix time stamp | | `time` | ✔️ | *int* | `1635528741` | Message date time, as Unix time stamp |
| `event` | ✔️ | `open`, `keepalive` or `message` | `message` | Message type, typically you'd be only interested in `message` | | `event` | ✔️ | `open`, `keepalive` or `message` | `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 |
Here's an example for each message type: Here's an example for each message type:

View file

@ -51,7 +51,7 @@ the settings (and custom sounds or vibration) for each of the priorities:
</figure> </figure>
### Instant delivery ### Instant delivery
Instant delivery is 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.
when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which when the screen turns off, and you leave it on the desk for a while. This is achieved with a foreground service, which
you'll see as a permanent notification that looks like this: you'll see as a permanent notification that looks like this:

View file

@ -11,4 +11,10 @@ To learn how to send messages, check out the [publishing page](../publish.md).
<a href="../../static/img/web-detail.png"><img src="../../static/img/web-detail.png"/></a> <a href="../../static/img/web-detail.png"><img src="../../static/img/web-detail.png"/></a>
</div> </div>
To keep receiving desktop notifications from ntfy, you need to keep the website open. What I do, and what I highly recommend,
is to pin the tab so that it's always open, but sort of out of the way:
<figure markdown>
![pinned](../static/img/web-pin.png){ width=500 }
<figcaption>Pin web app to move it out of the way</figcaption>
</figure>

View file

@ -4,7 +4,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>ntfy.sh | PUT/POST push notifications to your phone</title> <title>ntfy.sh | Send push notifications to your phone via PUT/POST</title>
<link rel="stylesheet" href="static/css/app.css" type="text/css"> <link rel="stylesheet" href="static/css/app.css" type="text/css">
<!-- Mobile view --> <!-- Mobile view -->
@ -24,7 +24,7 @@
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="ntfy.sh" /> <meta property="og:site_name" content="ntfy.sh" />
<meta property="og:title" content="ntfy.sh | send push notifications to your phone or desktop via PUT/POST" /> <meta property="og:title" content="ntfy.sh | Send push notifications to your phone or desktop via PUT/POST" />
<meta property="og:description" content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." /> <meta property="og:description" content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." />
<meta property="og:image" content="/static/img/ntfy.png" /> <meta property="og:image" content="/static/img/ntfy.png" />
<meta property="og:url" content="https://ntfy.sh" /> <meta property="og:url" content="https://ntfy.sh" />
@ -38,12 +38,13 @@
<nav id="header"> <nav id="header">
<div id="headerBox"> <div id="headerBox">
<img id="logo" src="static/img/ntfy.png" alt="logo"/> <img id="logo" src="static/img/ntfy.png" alt="logo"/>
<div id="name">ntfy.sh</div> <div id="name">ntfy</div>
<ol> <ol>
<li><a href="docs/">Getting started</a></li> <li><a href="docs/">Getting started</a></li>
<li><a href="docs/subscribe/phone/">Android/iOS</a></li> <li><a href="docs/subscribe/phone/">Android/iOS</a></li>
<li><a href="docs/publish/">API</a></li> <li><a href="docs/publish/">API</a></li>
<li><a href="docs/install/">Self-hosting</a></li> <li><a href="docs/install/">Self-hosting</a></li>
<li><a href="https://github.com/binwiederhier/ntfy">GitHub</a></li>
</ol> </ol>
</div> </div>
</nav> </nav>
@ -63,14 +64,10 @@
<a href="static/img/screenshot-phone-notification.jpg"><img src="static/img/screenshot-phone-notification.jpg"/></a> <a href="static/img/screenshot-phone-notification.jpg"><img src="static/img/screenshot-phone-notification.jpg"/></a>
</span> </span>
</div> </div>
<p>
There are many ways to use it: Notify yourself when a build finishes, when an rsync is done or a backup fails,
or know when somebody logs into your server. There are <a href="#examples">many more examples</a>, endless possibilities 😀.
</p>
<h2 id="publish" class="anchor">Publishing messages</h2> <h2 id="publish" class="anchor">Publishing messages</h2>
<p> <p>
Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. <a href="docs/publish/">Publishing messages</a> 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. Because there is no sign-up, <b>the topic is essentially a password</b>, so pick something that's not easily guessable.
</p> </p>
<p class="smallMarginBottom"> <p class="smallMarginBottom">
@ -81,8 +78,8 @@
</code> </code>
<p class="smallMarginBottom"> <p class="smallMarginBottom">
There are <a href="docs/publish/">more features</a> related to publishing messages: You can set a There are <a href="docs/publish/">more features</a> related to publishing messages: You can set a
<a href="#docs/publish/#message-priority">notification priority</a>, a <a href="docs/publish/#message-title">title</a>, <a href="docs/publish/#message-priority">notification priority</a>, a <a href="docs/publish/#message-title">title</a>,
and <a href="docs/publish/#tags--emojis--">tag messages</a>. and <a href="docs/publish/#tags-emojis">tag messages</a>.
Here's an example using all of them: Here's an example using all of them:
</p> </p>
<code> <code>
@ -93,6 +90,13 @@
&nbsp;&nbsp;-d "Remote access to $(hostname) detected. Act right away." \<br/> &nbsp;&nbsp;-d "Remote access to $(hostname) detected. Act right away." \<br/>
&nbsp;&nbsp;<span class="ntfyUrl">ntfy.sh</span>/mytopic &nbsp;&nbsp;<span class="ntfyUrl">ntfy.sh</span>/mytopic
</code> </code>
<p>
Here's what that looks like in the <a href="docs/subscribe/phone/">Android app</a>:
</p>
<figure>
<img src="static/img/priority-notification.png" style="max-height: 200px"/>
<figcaption>Urgent notification with pop-over</figcaption>
</figure>
<h2 id="subscribe" class="anchor">Subscribe to a topic</h2> <h2 id="subscribe" class="anchor">Subscribe to a topic</h2>
<p> <p>
@ -110,9 +114,11 @@
<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://github.com/binwiederhier/ntfy/issues/4"><img src="static/img/badge-appstore.png"></a> <a href="https://github.com/binwiederhier/ntfy/issues/4"><img src="static/img/badge-appstore.png"></a>
</p> </p>
<p>
Here's a video showing the app in action:
</p>
<figure> <figure>
<video controls muted autoplay loop width="650" src="static/img/android-video-overview.mp4"></video> <video controls muted autoplay loop src="static/img/android-video-overview.mp4" style="max-width: 650px"></video>
<figcaption>Sending push notifications to your Android phone</figcaption> <figcaption>Sending push notifications to your Android phone</figcaption>
</figure> </figure>
@ -143,7 +149,7 @@
as well as a <a href="docs/subscribe/api/#subscribe-as-raw-stream">plain text stream</a>. as well as a <a href="docs/subscribe/api/#subscribe-as-raw-stream">plain text stream</a>.
</p> </p>
<p class="smallMarginBottom"> <p class="smallMarginBottom">
Here's an example for JSON. Note that <b>the connection stays open</b>, so you can retrieve messages as they come in: Here's an example for JSON. The <b>connection stays open</b>, so you can retrieve messages as they come in:
</p> </p>
<code> <code>
$ curl -s <span class="ntfyUrl">ntfy.sh</span>/mytopic/json<br/> $ curl -s <span class="ntfyUrl">ntfy.sh</span>/mytopic/json<br/>
@ -152,24 +158,30 @@
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}<br/> {"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}<br/>
... ...
</code> </code>
<p> <p>
<script id="asciicast-453771" src="https://asciinema.org/a/453771.js" async></script> Here's a short video demonstrating it in action:
</p> </p>
<figure>
<video controls muted autoplay loop src="static/img/android-video-subscribe-api.mp4" style="max-width: 650px"></video>
<figcaption>Subscribing to the JSON stream with <tt>curl</tt></figcaption>
</figure>
<h3 id="more" class="anchor">More, more, more!</h3> <h3 id="docs" class="anchor">Check out the docs!</h3>
<p> <p>
ntfy has so <a href="docs/">many more features</a> and you can learn about all of them <a href="docs/">in the documentation</a> ntfy has so many more features and you can learn about all of them <a href="docs/">in the documentation</a>
(I tried my very best to make it the best docs ever 😉, not sure if I succeeded, hehe). (I tried my very best to make it the best docs ever 😉, not sure if I succeeded, hehe).
</p> </p>
<figure>
<a href="docs/"><img width="100%" src="static/img/screenshot-docs.png"/></a> <a href="docs/"><img width="100%" src="static/img/screenshot-docs.png"/></a>
<figcaption>Check out the documentation</figcaption>
</figure>
<h3 id="free-software" class="anchor">Forever free, forever 100% free software</h3> <h3 id="free-software" class="anchor">100% open source &amp; forever free</h3>
<p> <p>
I love free software, and I'm doing this because it's fun. I have no bad intentions, and I will I love free software, and I'm doing this because it's fun. I have no bad intentions, and I will
never monetize or sell your information. This service will always stay free and open. You can never monetize or sell your information. This service will always stay
read more in the <a href="docs/faq/">FAQs</a> and in the <a href="docs/privacy/">privacy policy</a>. <a href="https://github.com/binwiederhier/ntfy">free and open</a>.
You can read more in the <a href="docs/faq/">FAQs</a> and in the <a href="docs/privacy/">privacy policy</a>.
</p> </p>
<center id="ironicCenterTagDontFreakOut"><i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i></center> <center id="ironicCenterTagDontFreakOut"><i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i></center>

View file

@ -1,9 +1,10 @@
/* general styling */ /* general styling */
html, body { html, body {
font-family: 'Lato', sans-serif; font-family: 'Roboto', sans-serif;
color: #333; font-weight: 400;
font-size: 1.1em; font-size: 1.1em;
color: #444;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -29,31 +30,41 @@ h1 {
font-size: 2.5em; font-size: 2.5em;
word-wrap: break-word; /* For very long topics */ word-wrap: break-word; /* For very long topics */
padding-right: 40px; /* For the X on the detail page */ padding-right: 40px; /* For the X on the detail page */
font-weight: 300;
color: #666;
} }
h2 { h2 {
margin-top: 30px; margin-top: 30px;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 1.8em; font-size: 1.8em;
font-weight: 300;
color: #333;
} }
h3 { h3 {
margin-top: 25px; margin-top: 25px;
margin-bottom: 5px; margin-bottom: 5px;
font-size: 1.3em; font-size: 1.3em;
font-weight: 300;
color: #333;
} }
p { p {
margin-top: 10px; margin-top: 10px;
margin-bottom: 20px; margin-bottom: 20px;
font-size: 1.1em; line-height: 160%;
line-height: 140%; font-weight: 400;
} }
p.smallMarginBottom { p.smallMarginBottom {
margin-bottom: 10px; margin-bottom: 10px;
} }
b {
font-weight: 500;
}
tt { tt {
background: #eee; background: #eee;
padding: 2px 7px; padding: 2px 7px;
@ -72,16 +83,36 @@ code {
white-space: nowrap; white-space: nowrap;
} }
/* Lato font (OFL), https://fonts.google.com/specimen/Lato#about, /* Roboto font, embedded with the help of https://google-webfonts-helper.herokuapp.com/fonts/roboto?subsets=latin */
embedded with the help of https://google-webfonts-helper.herokuapp.com/fonts/lato?subsets=latin */
/* roboto-300 - latin */
@font-face { @font-face {
font-family: 'Lato'; font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local(''),
url('../font/roboto-v29-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../font/roboto-v29-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-regular - latin */
@font-face {
font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: local(''), src: local(''),
url('../font/lato-v17-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ url('../font/roboto-v29-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../font/lato-v17-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ url('../font/roboto-v29-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-500 - latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local(''),
url('../font/roboto-v29-latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../font/roboto-v29-latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
} }
/* Main page */ /* Main page */
@ -119,6 +150,29 @@ code {
visibility: visible; visibility: visible;
} }
/* Figures */
figure {
text-align: center;
}
figure img, figure video {
filter: drop-shadow(3px 3px 3px #ccc);
border-radius: 7px;
max-width: 100%;
}
figure video {
width: 100%;
max-height: 450px;
}
figcaption {
text-align: center;
font-style: italic;
padding-top: 10px;
}
/* Screenshots */ /* Screenshots */
#screenshots { #screenshots {
@ -218,21 +272,20 @@ code {
float: left; float: left;
color: white; color: white;
font-size: 2.6em; font-size: 2.6em;
font-weight: bold; font-weight: 300;
margin: 35px 0 0 20px; margin: 35px 0 0 20px;
} }
#header ol { #header ol {
list-style-type: none; list-style-type: none;
float:right; float: right;
margin-top: 80px; margin-top: 80px;
} }
#header ol li { #header ol li {
display: inline-block; display: inline-block;
margin: 0 10px; margin: 0 10px;
font-weight: bold; font-weight: 400;
} }
#header ol li a, nav ol li a:visited { #header ol li a, nav ol li a:visited {
@ -273,6 +326,14 @@ li {
font-size: 0.9em; font-size: 0.9em;
} }
/* Hide top menu SMALL SCREEN */
@media only screen and (max-width: 780px) {
#header ol {
display: none;
}
}
/* Subscribe box SMALL SCREEN */ /* Subscribe box SMALL SCREEN */
@media only screen and (max-width: 1599px) { @media only screen and (max-width: 1599px) {
#subscribeBox #subscribeForm { #subscribeBox #subscribeForm {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB