116 lines
3.5 KiB
Markdown
116 lines
3.5 KiB
Markdown
# Letting people off-site watch
|
|||
|
|
|
||
|
|
**Optional.** Everything works on the building's WiFi without any of this. Read
|
||
|
|
on only if you want people on cell data, or watching from home, to follow along.
|
||
|
|
|
||
|
|
Because each campus runs its own copy, this is a per-campus decision — you can
|
||
|
|
publish one campus and not another.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## The easy way: Cloudflare Tunnel
|
||
|
|
|
||
|
|
Free, needs no port forwarding, no firewall changes, no certificate, and no
|
||
|
|
static IP. It runs on the same Mac as the app.
|
||
|
|
|
||
|
|
1. **Install cloudflared**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
brew install cloudflared
|
||
|
|
```
|
||
|
|
|
||
|
|
No Homebrew on that Mac? Download the `cloudflared-darwin-arm64.tgz` binary
|
||
|
|
from Cloudflare's releases page and drop it in `/usr/local/bin`.
|
||
|
|
|
||
|
|
2. **Log in and create the tunnel**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cloudflared tunnel login
|
||
|
|
cloudflared tunnel create translate-main
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Point a hostname at the app**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cloudflared tunnel route dns translate-main translate.watersmedia.org
|
||
|
|
```
|
||
|
|
|
||
|
|
4. **Run it**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cloudflared tunnel run --url http://127.0.0.1:3100 translate-main
|
||
|
|
```
|
||
|
|
|
||
|
|
To keep it running after a reboot, `sudo cloudflared service install`.
|
||
|
|
|
||
|
|
5. **Tell the app its public name**
|
||
|
|
|
||
|
|
Operator page → **Public address** → `https://translate.watersmedia.org` →
|
||
|
|
Save. That is what the QR code encodes, so it must be the public name or the
|
||
|
|
code only works for people already on your WiFi.
|
||
|
|
|
||
|
|
WebSockets pass through Cloudflare tunnels with nothing extra to configure,
|
||
|
|
which is the main reason this is the lower-risk option.
|
||
|
|
|
||
|
|
For a second campus, repeat with its own name — `translate-north`,
|
||
|
|
`north.translate.watersmedia.org`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## The other way: your existing nginx proxy
|
||
|
|
|
||
|
|
You already run a reverse proxy at `10.1.1.4` fronting `check.watersmedia.org`,
|
||
|
|
with split-horizon DNS. It can front this too, though it means the traffic goes
|
||
|
|
through the NAS network to reach the booth Mac.
|
||
|
|
|
||
|
|
Add a DNS record for `translate.watersmedia.org` — public to your WAN address,
|
||
|
|
internal to `10.1.1.4` — and a server block. Copy the one that already serves
|
||
|
|
the checklist app, change the name, and point it at the **booth Mac**, not the
|
||
|
|
NAS:
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
server {
|
||
|
|
listen 443 ssl http2;
|
||
|
|
server_name translate.watersmedia.org;
|
||
|
|
|
||
|
|
ssl_certificate /path/to/fullchain.pem;
|
||
|
|
ssl_certificate_key /path/to/privkey.pem;
|
||
|
|
|
||
|
|
location / {
|
||
|
|
proxy_pass http://10.6.3.222:3100; # the booth Mac
|
||
|
|
|
||
|
|
proxy_set_header Host $host;
|
||
|
|
proxy_set_header X-Real-IP $remote_addr;
|
||
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
|
proxy_set_header X-Forwarded-Host $host;
|
||
|
|
|
||
|
|
# ---- required: captions ride a WebSocket ----
|
||
|
|
proxy_http_version 1.1;
|
||
|
|
proxy_set_header Upgrade $http_upgrade;
|
||
|
|
proxy_set_header Connection "upgrade";
|
||
|
|
|
||
|
|
# A sermon is long and mostly silent between sentences. Without this the
|
||
|
|
# proxy closes the caption socket after 60s of quiet and every phone in
|
||
|
|
# the room reconnects at once.
|
||
|
|
proxy_read_timeout 3600s;
|
||
|
|
proxy_send_timeout 3600s;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
This has one real drawback the tunnel does not: the booth Mac needs a fixed
|
||
|
|
address on the network, or the proxy breaks the next time DHCP moves it.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Checking it worked
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s https://translate.watersmedia.org/healthz
|
||
|
|
```
|
||
|
|
|
||
|
|
Should return `{"ok":true,…}`. Then open the page on a phone **with WiFi turned
|
||
|
|
off** — that is the real test. If the page loads but captions never appear, the
|
||
|
|
WebSocket headers are missing.
|