Files
church-translate/docs/examples/waters-church-na
michaelandClaude Opus 5.5 825a25b626 Document opening Waters Guest WiFi at North Attleboro to translate
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>
2026-10-15 16:15:46 -04:00
..

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. 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:

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 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:

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.
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. 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.

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.

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:
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.