Full rewrite for current infra state — StreamHoard consolidation, VoIP split out, dead references purged

- Replace all Jellyfin/MediaStack/WireGuard-CT110 references (destroyed 2026-07-23) with
  StreamHoard/CT104 throughout; add streamhoard.md covering the full consolidated stack,
  MSP360 backup setup, and migration incidents
- Split FusionPBX/SignalWire/landline content into its own voip.md (was scattered across
  jarvis.md and sites.md, and referenced the old destroyed DO droplet IP)
- Fix stale facts: JARVIS webhook port (:1972 -> 80/https), rotated registration key/GitHub
  PAT, FortiGate admin port (9443 not 443), current WAN-IP-drift/VIP gotchas
- Add reference.md for repo inventory notes, assistant hard limits, ZeroTraceGPT IQ, payments
  migration status
- Update gotchas.md with unprivileged-LXC mount limitations and MSP360 dpkg-repack gotcha
This commit is contained in:
Myron Blair
2026-07-25 22:47:31 -05:00
parent f5446d3208
commit 4fad312f87
8 changed files with 398 additions and 231 deletions
+74
View File
@@ -0,0 +1,74 @@
# VoIP Reference Card — FusionPBX / SignalWire / Landline
## FusionPBX server
- **Host:** VM130 on PVE1, `10.48.200.130` — moved on-prem from an old DO droplet (`134.209.72.226`, now **destroyed** — do not reference that IP anymore, any doc saying FusionPBX is at `134.209.72.226` is stale).
- **Web UI:** `https://fusion.orbishosting.com` (NPM proxies to `10.48.200.130:80`)
- **SSH:** `root@10.48.200.130` via PVE1 hop, password `Joker1974!!!` (no longer needs the old DO-relay hop)
- **DB:** PostgreSQL (not MySQL), `fusionpbx` / `fusionpbx` / `RSfAjzefyYmufVqtnrYpz90yHaQ`, `psql -U fusionpbx -h 127.0.0.1 -d fusionpbx`
- Timezone: America/Chicago
## SIP registration settings (for a device/softphone registering against this PBX)
| Setting | Value |
|---|---|
| SIP Server/Domain | `fusion.orbishosting.com` (or `10.48.200.130`) — **must be the domain name for some devices** (see FXO gotcha below), not always interchangeable with the IP |
| Port (LAN) | `5060` UDP/TCP |
| Port (WAN, per FortiGate forwards) | `5080` UDP or `5081` TCP/TLS |
| Auth username | extension number, e.g. `1000` |
| Auth password | per-extension, from `v_extensions.password` in the FusionPBX DB |
Example working extensions (query `select extension, password, effective_caller_id_name from v_extensions;` for current full list):
| Ext | Who |
|---|---|
| 1000 | Myron Blair (Desk) |
| 1001 | Myron Blair |
| 1002 | Tommy Ivy |
| 1003 | Kitchen |
| 1004 | Master Bedroom |
| 1050 | Landline FXO gateway (Grandstream ATA, see below) |
| 1091 | "Landline" ring group (rings all 8 phones) |
**Extension key/BLF provisioning:** category differs by phone model — T57W/T48S use `category=line` in `v_device_keys`, the AX86R WiFi phone only has a `programmable` keys section (no `line` section). Guessing wrong silently produces no key at all — check the actual Smarty templates at `/var/www/fusionpbx/resources/templates/provision/yealink/<model>/*.cfg` before assuming a key type.
## SignalWire outbound trunk (carrier side — separate from the extension/phone side above)
FusionPBX registers **to** SignalWire as a SIP gateway (this is the outbound carrier trunk, not something a phone registers against):
- Gateway UUID: `c0e12aab-2406-44ee-ac38-6602116eaf2f`, username `orbis`
- Realm: `orbis-hosting-0364f5f67488.sip.signalwire.com`
- Space: `orbis-hosting.signalwire.com`, Project ID `16fbbcfd-1c94-4827-869c-0364f5f67488`
- Check status: `fs_cli -x "sofia status"` on VM130 — should show `REGED` for `external::c0e12aab-...`
### SignalWire API gotchas (cost real debugging time — read before touching SignalWire)
1. **Credential types are NOT interchangeable.** The dashboard shows a `PSK_`-prefixed Signing Key at the top of the API Credentials page that looks like "the" token but gives a real 401 on classic REST calls. A `pat_`-prefixed Personal Access Token also 401s. **Only a named Project Token (`PT`-prefix, created in a separate table further down the same page) works** for REST Basic Auth (`ProjectID:PT...`) and the Relay SDK.
2. **Setting the SIP registration password requires the `relay` API, not the `Fabric` API.** `PUT /api/fabric/resources/sip_endpoints/{fabric_id}` returns HTTP 200 but does NOT affect registration auth. The correct call is `PUT https://{space}/api/relay/rest/endpoints/sip/{inner_sip_endpoint_id}` with `{"password":"..."}` — the inner sip_endpoint id is a *different* id than the Fabric resource id that wraps it. Symptom of using the wrong one: gateway stuck `FAIL_WAIT` with `[904] Operation has no matching challenge` even though the wire-level 401 challenge is valid.
3. **Outbound INVITE `From` header user-part must equal the digest auth username** (`orbis`), not the caller's DID/Caller ID. In FusionPBX this is `v_gateways.caller_id_in_from` — must be `false`. If wrong: INVITE gets 407, retries with Proxy-Authorization, gets ANOTHER 407 with the same nonce (looks like a FreeSWITCH bug, isn't).
4. **Destination must be full 11-digit E.164** (`+1` + 10 digits) — a dialplan bridge producing `+8172662022` (missing the `1`) gets `404`/`NO_ROUTE_DESTINATION`, easily misdiagnosed as "SignalWire doesn't recognize this number."
5. **Trial-tier gotcha:** even with the right token, sending SMS to an unverified number returns `422 integration_test_verified_caller_required`.
6. **FreeSWITCH `fs_cli chat` to a registered phone** needs the destination prefixed with the Sofia **profile name**: `chat sip|<from>@<domain>|internal/<ext>@<domain>|<body>` — just `user@domain` silently fails ("Invalid chat interface").
7. **Diagnostic method that actually works for SIP auth issues:** independently reconstruct the digest (MD5 HA1/HA2/response) in a standalone script using the exact nonce/realm/uri from a live packet capture, compare byte-for-byte to what FreeSWITCH sent. Proves credentials/computation bug (mismatch) vs. carrier-side policy rejection (match, still rejected) before chasing further theories.
## FortiGate SIP/RTP port forwards (VIPs, verify live via `show firewall vip` — the doc's static tables drift)
```
fusion-sip-5080 (udp), fusion-sip-5080-tcp, fusion-sip-5081-tcp, fusion-sip-5081-udp, fusion-rtp (udp 16384-32768)
→ all forward to 10.48.200.130 (FusionPBX)
```
**WAN IP drifts silently and semi-regularly** — when it does, all VIP `extip` fields need updating, or calls will connect at the signaling level but have one-way/no audio (RTP arriving at the *real* current WAN IP with no matching forward rule). Always `curl ifconfig.me` from any on-prem host to check the *actual* live WAN IP before trusting a documented value.
**FortiGate SIP ALG** (`default-voip-alg-mode`) must stay `proxy-based` (the default) — switching to `kernel-helper-based` breaks inbound call routing entirely (the inbound dialplan's `${sip_to_user}` handling is tuned around ALG being active).
**FusionPBX's sofia.conf is cached independently of FreeSWITCH's process** at `/var/cache/fusionpbx/<hostname>.configuration.sofia.conf` (Lua file cache) — any sofia profile/gateway DB or vars.xml change needs this file cleared too, not just a service/process restart.
## Landline/FXO integration (Grandstream ATA, working as of 2026-07-18)
Old Flyingvoice FTA5111 (`10.48.200.119`) is **retired — do not reuse without a firmware fix from the vendor.** It has a 100%-reproducible crash-on-save bug (firmware V3.20) confirmed via extensive testing; not a config mistake.
**Current device:** Grandstream HT8xx-family ATA at `10.48.200.45` (admin/Joker1974!!!), registered as **extension 1050**.
FXO config (`/cgi-bin/config_a2`, Advanced Settings → FXO Port):
- Primary SIP Server = `fusion.orbishosting.com`**must be the domain, not the IP** (extension 1050 is only provisioned under that domain name in FreeSWITCH's directory, even though `10.48.200.130` also technically exists as a domain).
- SIP User ID/Auth ID = `1050`, password = ext 1050's FusionPBX password.
- `PSTN Ring Thru FXS` = **No** (device defaults to Yes — rings a nonexistent local FXS phone instead of routing to SIP).
- Stage Method = default **2** (2-stage dialing) — gives the "landline button" real dial tone (SIP call seizes the line, ATA plays back real dial tone, DTMF passthrough).
**Inbound PSTN→VoIP routing is on a DIFFERENT page** — Basic Settings (`/cgi-bin/config2`), NOT the FXO Port page:
- `Unconditional Call Forward to VOIP`: User ID = `1091` (the "Landline" ring group, rings all 8 phones), Sip Server = `fusion.orbishosting.com`, port `5060`.
- Without this field, incoming landline calls have nowhere to go once FXS-thru is disabled — easy to miss since the FXO page itself has no inbound-destination field.
**Grandstream ATA web quirk:** login is `POST /cgi-bin/dologin`, but every subsequent settings-changing `POST /cgi-bin/update` needs a `session_token` hidden field (separate from login's `csrf_token`) scraped fresh from whatever config page you just loaded — omitting it silently bounces to a re-login page with the submission discarded, no error shown. Partial POSTs (only the fields you want changed) work fine.