> ## Documentation Index
> Fetch the complete documentation index at: https://docs.augustin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ntfy

Self-hosted [ntfy](https://ntfy.sh) push-notification server — a general-purpose notifier for the homelab. Any service publishes to a topic over HTTP; a subscribed phone or browser gets the alert. [riverbot](/riverbot) is the first consumer.

## Topology

* **Image:** `binwiederhier/ntfy`, swarm stack pinned to `debian-2` (lightweight node).
* **Ingress:** `https://ntfy.augustin.ai` via Traefik (port 80 on the overlay).
* **Internal publish:** other swarm services post to `http://ntfy/<topic>` directly on the `swarm` overlay — no round-trip through Cloudflare.
* **State:** `./data` holds the message cache (`NTFY_CACHE_DURATION=12h`) and attachments.

## Publishing

```bash theme={null}
# from any container on the swarm overlay
curl -d "a permit opened" \
  -H "Title: Middle Fork Salmon" \
  -H "Priority: 5" \
  -H "Tags: canoe,rotating_light" \
  -H "Click: https://www.recreation.gov/permits/234623" \
  http://ntfy/river-permits
```

Header values must be ASCII. Emoji go through `Tags` (ntfy renders matching shortcodes like `canoe` as 🛶); the message **body** is UTF-8 and takes anything.

## Subscribing

In the ntfy app (iOS/Android) or browser, add server `https://ntfy.augustin.ai` and the topic name (e.g. `river-permits`).

iOS instant delivery needs `NTFY_UPSTREAM_BASE_URL=https://ntfy.sh` (set in the compose file): self-hosted servers can't reach Apple's push network, so poll requests — topic name only, never message content — are forwarded through ntfy.sh, which triggers APNs. Android and desktop use the WebSocket connection and ignore this.

## Access control

Open by default — anyone who knows a topic name can read and write it. To lock down, add `NTFY_AUTH_FILE` with `NTFY_AUTH_DEFAULT_ACCESS=deny-all` and provision users via the `ntfy user`/`ntfy access` CLI.

## Monitoring

Health endpoint: `http://ntfy:80/v1/health`.
