The guest network blocks private ranges twice: a zone default on the gateway, and the guest hotspot's Post-Authorization Restrictions, which the access points enforce on their own. With only a firewall allow, a phone on Waters Guest worked for about two minutes and then timed out. docs/examples/waters-church-na/ gains the three scripts used to fix it: zone-allow-policy.py (allow Hotspot -> 10.1.1.4 on 80/443), guest-restrictions.py (drop 10.0.0.0/8 from the restriction list via the legacy guest_access setting, since system policies cannot be edited through the Integration API) and wifi-broadcast-devices.py (put the Waters Guest SSID on the Auditorium, Main Lobby and Offices APs). The runbook gets a section on all three, and PUBLIC-ACCESS.md points at it from the troubleshooting notes. Confirmed on site: translate.watersmedia.org loads on Waters Guest and stays up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
120 lines
6.9 KiB
Markdown
120 lines
6.9 KiB
Markdown
# translate.watersmedia.org — local DNS and reverse proxy
|
|
|
|
Puts the Church Translate congregation page on a church hostname inside the
|
|
Apollo Beach and North Attleboro networks. LAN only, plain HTTP, no WAN access.
|
|
The app's own requirements are in [PUBLIC-ACCESS.md](../../PUBLIC-ACCESS.md). This
|
|
was done on 2026-10-15 against app 3.23.2 build 121.
|
|
|
|
| What | Value |
|
|
| --- | --- |
|
|
| App host | Translate Mac, North Attleboro LAN `10.1.7.39` |
|
|
| App port | TCP 3100, plain HTTP + WebSocket on `/ws` (the only port to expose) |
|
|
| Reverse proxy | Boba-Fett (Synology DSM 7.0.1), `10.1.1.4`, `ssh boba-fett` (port 202, user Michael) |
|
|
| Hostname | `translate.watersmedia.org` |
|
|
| Local DNS | A record on the AB and NA UDM Pro consoles → `10.1.1.4`, TTL 300 |
|
|
| HTTPS | no certificate; `https://translate.watersmedia.org` answers 301 to `http://` |
|
|
|
|
`curl -s http://10.1.7.39:3100/healthz` should return `{"ok":true,"live":true,...}`
|
|
before anything below is tested.
|
|
|
|
## 1. Local DNS on UniFi (AB and NA) — done 2026-10-15
|
|
|
|
Each console has its own Network API key saved as
|
|
`~/.config/unifi/<site>-network-api-key` (created in Settings → Control Plane →
|
|
Integrations → Create API Key; all five sites are saved on Michael's Mac). The
|
|
record was created with:
|
|
|
|
```bash
|
|
python3 docs/examples/waters-church-na/unifi-dns-record.py translate.watersmedia.org 10.1.1.4 --sites apollo-beach,north-attleboro
|
|
```
|
|
|
|
Resulting policy ids: AB `379f868d-a956-4ec1-acef-13557153ff3f`, NA
|
|
`16bf7109-ec68-41f9-9c16-fa6a62471430`. Both gateways answer `10.1.1.4`.
|
|
`--list` shows every DNS policy per console; `--dry-run` previews.
|
|
|
|
Why Boba-Fett and not the Mac: the proxy owns the hostname so the port never
|
|
appears in the URL, and AB clients reach `10.1.1.4` over the site-to-site link
|
|
exactly as they already do for `chronicles-na.waterschurch.org`.
|
|
|
|
## 2. Reverse proxy on Boba-Fett — done 2026-10-15
|
|
|
|
[boba-fett-translate-proxy.sh](boba-fett-translate-proxy.sh) does the whole
|
|
job and is idempotent. It was run on 2026-10-15; afterwards `/healthz`,
|
|
`/api/languages`, the `/ws` upgrade (101) and the HTTPS 301 all checked out
|
|
from both the AB and NA LANs, and `/operator` returned 404 as designed. A copy lives at `~/translate-proxy.sh` on Boba-Fett
|
|
(Michael's home). DSM's reverse-proxy API and nginx reload both need root, and
|
|
sudo there asks for Michael's password, so run it interactively:
|
|
|
|
```bash
|
|
ssh -t boba-fett sudo bash translate-proxy.sh
|
|
```
|
|
|
|
What it creates:
|
|
|
|
| Piece | Where | Content |
|
|
| --- | --- | --- |
|
|
| DSM reverse proxy rule | Control Panel → Login Portal → Advanced → Reverse Proxy, "translate.watersmedia.org" | HTTP `translate.watersmedia.org:80` → HTTP `10.1.7.39:3100`; custom headers `Upgrade: $http_upgrade`, `Connection: $connection_upgrade` (WebSocket), `X-Forwarded-Host: $http_host`; read timeout 3600 s; HTTP/1.1 |
|
|
| HTTPS redirect | `/usr/local/etc/nginx/sites-enabled/translate-redirect.conf` | `server { listen 443 ssl; server_name translate.watersmedia.org; return 301 http://translate.watersmedia.org$request_uri; }` |
|
|
|
|
DSM already sends `Host`, `X-Real-IP`, `X-Forwarded-For` and
|
|
`X-Forwarded-Proto` on every rule. The whole host lands on `/`, which the app
|
|
requires. `/operator` returning 404 through the proxy is intended; staff use
|
|
`http://10.1.7.39:3100/operator` on the LAN.
|
|
|
|
To undo: delete the rule in the DSM Reverse Proxy list, remove the redirect
|
|
file, and `sudo synosystemctl reload nginx`.
|
|
|
|
Known limits:
|
|
|
|
- The HTTPS redirect only runs after a TLS handshake with Boba-Fett's default
|
|
certificate, so a browser shows a certificate warning first. A trusted
|
|
certificate for this name would need DNS-01 validation against the
|
|
watersmedia.org zone (cPanel), which is not set up.
|
|
- DSM's reverse proxy cannot turn `proxy_buffering` off. HLS segments under
|
|
`/live/` are small discrete files and the WebSocket is a tunnel after upgrade,
|
|
so the effect is minor; if audio lag is reported, that is the first thing to
|
|
revisit with a hand-written nginx include.
|
|
|
|
## 3. Waters Guest WiFi at North Attleboro — done 2026-10-15
|
|
|
|
The Guest network (VLAN 25, 192.168.16.0/24) is in the UniFi **Hotspot** zone.
|
|
Two things stood between a phone on Waters Guest and `10.1.1.4`:
|
|
|
|
| Blocker | Fix |
|
|
| --- | --- |
|
|
| Zone default "Block All Traffic" Hotspot → Internal | User policy "Guest to translate.watersmedia.org (Boba-Fett web)", ALLOW Hotspot → Internal, destination `10.1.1.4` TCP 80 and 443, index 10000 (evaluated first). Created with [`zone-allow-policy.py`](zone-allow-policy.py). |
|
|
| Guest "Post-Authorization Restrictions" listed 10.0.0.0/8. The list is enforced twice: as system policies on the gateway (index 30001, which the allow rule sits above) **and on the access points**, which no gateway policy can override. Symptom: a fresh guest client worked for about two minutes, then timed out even to `http://10.1.1.4/`. | Removed 10.0.0.0/8 from the list with [`guest-restrictions.py`](guest-restrictions.py). The Integration API refuses to edit the system policies; the script edits the legacy `guest_access` setting (`restricted_subnet_1..3`) and the four gateway policies regenerate from it. 192.168.0.0/16 and 172.16.0.0/12 stay. Guests are still cut off from every other 10.x host by the zone default block. |
|
|
| The Waters Guest SSID only broadcast from the AP "The Vault" | Added Auditorium Left, Auditorium Right, Main Lobby Entrance, Admin Offices - U7 and Creative Offices - U7 with [`wifi-broadcast-devices.py`](wifi-broadcast-devices.py). |
|
|
|
|
Guest clients get DNS from the gateway (DHCP hands out no custom DNS), so the
|
|
local record resolves for them. The SSID keeps client isolation on, which only
|
|
separates guest devices from each other, not from the gateway.
|
|
|
|
```bash
|
|
python3 docs/examples/waters-church-na/zone-allow-policy.py north-attleboro Hotspot 10.1.1.4 80,443 --name "Guest to translate.watersmedia.org (Boba-Fett web)" --apply
|
|
python3 docs/examples/waters-church-na/guest-restrictions.py north-attleboro --remove 10.0.0.0/8 --apply
|
|
python3 docs/examples/waters-church-na/wifi-broadcast-devices.py north-attleboro "Waters Guest" --list
|
|
```
|
|
|
|
To undo: delete the allow policy in Settings → Policy Engine (or Firewall) on
|
|
the NA console, put 10.0.0.0/8 back under the guest hotspot's
|
|
Post-Authorization Restrictions, and remove the APs with
|
|
`wifi-broadcast-devices.py --remove`.
|
|
|
|
## 4. After the proxy answers
|
|
|
|
1. On the NA LAN open `http://10.1.7.39:3100/operator`, enter the operator PIN,
|
|
and set **Public address** to `http://translate.watersmedia.org` (no trailing
|
|
slash). Otherwise the QR code and poster keep advertising `10.1.7.39:3100`.
|
|
2. Verify from a machine at AB and one at NA:
|
|
|
|
```bash
|
|
curl -s http://translate.watersmedia.org/healthz
|
|
```
|
|
|
|
It must return the same JSON as the direct `10.1.7.39:3100` check.
|
|
3. Open the page on a phone on guest wifi and confirm captions appear
|
|
(WebSocket) and spoken audio plays (`/live/`). If phones cannot connect at
|
|
all, look at client isolation on the guest network and the guest → `10.1.1.4`
|
|
firewall rule before anything else.
|