Merge pull request 'docs(ntfy): ntfy publishes a host port for the external reverse proxy' (#37) from fix/ntfy-published-port into main
Reviewed-on: #37 Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
@@ -169,9 +169,12 @@ none (keeps §11's zero-interaction promise).
|
|||||||
registration and every publish validate it is HTTPS and its origin is in the shard's ntfy
|
registration and every publish validate it is HTTPS and its origin is in the shard's ntfy
|
||||||
allow-set (`NTFY_BASE_URL` / `NTFY_ALLOWED_ORIGINS`), rejecting loopback/private hosts.
|
allow-set (`NTFY_BASE_URL` / `NTFY_ALLOWED_ORIGINS`), rejecting loopback/private hosts.
|
||||||
- **ntfy** added to `website/docker-compose.yml` as a pinned upstream image with a committed
|
- **ntfy** added to `website/docker-compose.yml` as a pinned upstream image with a committed
|
||||||
declarative `./ntfy/server.yml` and named volume, **no published host port** (reached via the
|
declarative `./ntfy/server.yml` and named volume, **published on a host port** (`NTFY_HOST_PORT`,
|
||||||
reverse proxy; internal-only for the publisher), anonymous read-write to unguessable topics (no
|
default `2586` → container `:80`) so the public reverse proxy — which runs *outside* the compose
|
||||||
per-user accounts — safe because tickles are content-free).
|
network — can forward the notification subdomain to it, anonymous read-write to unguessable topics
|
||||||
|
(no per-user accounts — safe because tickles are content-free). Both the app (SSE subscribe) and the
|
||||||
|
backend (POSTing tickles to registered device endpoints) reach ntfy on that public origin, so all
|
||||||
|
ntfy traffic transits the proxy — there is no separate internal publish port.
|
||||||
|
|
||||||
**Part 2 — the Android app — ✅ LANDED** (2026-07-20, `RunicGateway/Android-app#15` + a small
|
**Part 2 — the Android app — ✅ LANDED** (2026-07-20, `RunicGateway/Android-app#15` + a small
|
||||||
`RunicGateway/website#79` settings addition + this docs PR). Built exactly to the plan below, with
|
`RunicGateway/website#79` settings addition + this docs PR). Built exactly to the plan below, with
|
||||||
@@ -911,8 +914,11 @@ first release. Users **opt in per stream**: nothing is pushed unless subscribed.
|
|||||||
path/tag at implementation.
|
path/tag at implementation.
|
||||||
- **All config is declarative** — a committed `ntfy` config file and/or `NTFY_*` env vars baked into
|
- **All config is declarative** — a committed `ntfy` config file and/or `NTFY_*` env vars baked into
|
||||||
compose. No `docker exec`, no interactive `ntfy user add`, no post-deploy manual steps. Bringing the
|
compose. No `docker exec`, no interactive `ntfy user add`, no post-deploy manual steps. Bringing the
|
||||||
stack up provisions a working push relay. Reachable to devices via the existing reverse proxy on its
|
stack up provisions a working push relay. Reachable via the existing reverse proxy on its own
|
||||||
own hostname/path; internal-only for the backend publisher.
|
hostname/path — the container publishes `:80` on a host port (`NTFY_HOST_PORT`, default `2586`)
|
||||||
|
because the proxy runs *outside* the compose network and can only reach a service through a
|
||||||
|
published host port (the same reason `app` publishes `3000`). Both devices and the backend publisher
|
||||||
|
reach ntfy on that public origin.
|
||||||
- **No per-user ntfy accounts to administer.** The security model (below) removes the need for ntfy ACL
|
- **No per-user ntfy accounts to administer.** The security model (below) removes the need for ntfy ACL
|
||||||
provisioning, which is exactly what keeps setup interaction-free. ntfy topics are the random,
|
provisioning, which is exactly what keeps setup interaction-free. ntfy topics are the random,
|
||||||
unguessable endpoints UnifiedPush hands out; the backend treats ntfy as an **untrusted relay**.
|
unguessable endpoints UnifiedPush hands out; the backend treats ntfy as an **untrusted relay**.
|
||||||
@@ -1002,8 +1008,10 @@ it is a UX convenience, not a v1 requirement — deferred at M3, descoped at M6;
|
|||||||
See [`APP_LINKS.md`](./APP_LINKS.md).
|
See [`APP_LINKS.md`](./APP_LINKS.md).
|
||||||
- ntfy: exact upstream image + pinned tag (Part-1 landed the compose service — confirm the tag), and
|
- ntfy: exact upstream image + pinned tag (Part-1 landed the compose service — confirm the tag), and
|
||||||
its reverse-proxy hostname/path. The hostname must land in `NTFY_ALLOWED_ORIGINS` before M7 Part 2 is
|
its reverse-proxy hostname/path. The hostname must land in `NTFY_ALLOWED_ORIGINS` before M7 Part 2 is
|
||||||
end-to-end testable (the app registers an endpoint on that origin; the SSRF guard rejects others). No
|
end-to-end testable (the app registers an endpoint on that origin; the SSRF guard rejects others). The
|
||||||
backend publish token — **decided** (the content-free-tickle design does not require one; optional
|
reverse proxy forwards that hostname to the ntfy container's published host port (`NTFY_HOST_PORT`,
|
||||||
|
default `2586`) — the container publishes `:80` because the proxy runs outside the compose network.
|
||||||
|
No backend publish token — **decided** (the content-free-tickle design does not require one; optional
|
||||||
`NTFY_PUBLISH_TOKEN` is honored if ever set).
|
`NTFY_PUBLISH_TOKEN` is honored if ever set).
|
||||||
- FCM flavor: build it for the Play release or ship Play on UnifiedPush too? Decide at M8. (The M7
|
- FCM flavor: build it for the Play release or ship Play on UnifiedPush too? Decide at M8. (The M7
|
||||||
Part 2 `PushTransport` seam keeps this swap cheap.)
|
Part 2 `PushTransport` seam keeps this swap cheap.)
|
||||||
|
|||||||
@@ -511,11 +511,13 @@ subsystem (`[server]`, `[http]`, `[db]`, `[auth]`, `[admin]`, `[ratelimit]`, …
|
|||||||
`env_file: .env`, `DB_HOST=db`, `depends_on: db (healthy)`, volume `uploads:/app/uploads`,
|
`env_file: .env`, `DB_HOST=db`, `depends_on: db (healthy)`, volume `uploads:/app/uploads`,
|
||||||
`ports: "3000:3000"` — **binds 0.0.0.0** (no `127.0.0.1:` prefix) so Pangolin reaches it.
|
`ports: "3000:3000"` — **binds 0.0.0.0** (no `127.0.0.1:` prefix) so Pangolin reaches it.
|
||||||
- `ntfy` (M7): pinned upstream `binwiederhier/ntfy` image, declarative config only
|
- `ntfy` (M7): pinned upstream `binwiederhier/ntfy` image, declarative config only
|
||||||
(`./ntfy/server.yml` mounted `:ro` + `NTFY_BASE_URL`), volume `ntfydata:/var/lib/ntfy`, **no
|
(`./ntfy/server.yml` mounted `:ro` + `NTFY_BASE_URL`), volume `ntfydata:/var/lib/ntfy`,
|
||||||
published host port** — devices reach it via the reverse proxy; the backend publisher reaches it
|
**publishes `:80` on a host port** (`${NTFY_HOST_PORT:-2586}:80`, binds 0.0.0.0) so Pangolin — which
|
||||||
over the private compose network. Anonymous read-write to unguessable topics (no accounts to
|
runs outside the compose network — can forward the notification subdomain to it, the same reason
|
||||||
provision) — safe because pushes are content-free tickles. Bringing the stack up provisions a
|
`app` publishes `3000`. Both devices (SSE subscribe) and the backend publisher (POSTing tickles to
|
||||||
working push relay with **zero interactive setup**.
|
registered device endpoints) reach ntfy on that public origin. Anonymous read-write to unguessable
|
||||||
|
topics (no accounts to provision) — safe because pushes are content-free tickles. Bringing the stack
|
||||||
|
up provisions a working push relay with **zero interactive setup**.
|
||||||
- Volumes: `dbdata`, `uploads`, `ntfydata`.
|
- Volumes: `dbdata`, `uploads`, `ntfydata`.
|
||||||
|
|
||||||
Express listens on `0.0.0.0:${PORT||3000}`. Pangolin terminates TLS and proxies to `app`.
|
Express listens on `0.0.0.0:${PORT||3000}`. Pangolin terminates TLS and proxies to `app`.
|
||||||
@@ -548,6 +550,9 @@ NTFY_BASE_URL=https://ntfy.example.com
|
|||||||
# shows push as unavailable for the shard.
|
# shows push as unavailable for the shard.
|
||||||
NTFY_PUBLIC_URL=https://ntfy.example.com
|
NTFY_PUBLIC_URL=https://ntfy.example.com
|
||||||
NTFY_ALLOWED_ORIGINS=https://ntfy.example.com
|
NTFY_ALLOWED_ORIGINS=https://ntfy.example.com
|
||||||
|
# Host port the ntfy container publishes :80 on (default 2586); the reverse proxy
|
||||||
|
# forwards the notification subdomain to host:NTFY_HOST_PORT. Change on a conflict.
|
||||||
|
NTFY_HOST_PORT=2586
|
||||||
```
|
```
|
||||||
|
|
||||||
`.gitignore`: `node_modules/`, `.env`, `_reference/`, `client/dist/`, `uploads/`.
|
`.gitignore`: `node_modules/`, `.env`, `_reference/`, `client/dist/`, `uploads/`.
|
||||||
|
|||||||
Reference in New Issue
Block a user