fix(plex): advertise the plex.direct name, not the bare VIP (server vanished from the plex.tv account)
gate / gate (pull_request) Successful in 1m48s
gate / conformance (pull_request) Has been skipped

customConnections held two hand-typed URLs and neither could ever complete, so
Plex had nothing publishable and the server disappeared from the account:

  - https://192.168.2.24:32400 -- the server's cert is
    *.130072f20c334d6c8f63d0dfef87309b.plex.direct with NO IP SAN, so bare-IP
    https fails TLS for every client. Measured: a continuous storm of
    "CERT: incomplete TLS handshake ... certificate unknown" from real LAN
    clients arriving through the plex-l4-tcp VIP.
  - https://plex.home.keithjackson.dev:32400 -- nothing listens; the Gateway
    serves that host on 443 (measured http=000 against 192.168.2.20:32400).

With no completable connection plex.tv published nothing ("Mapped - Not
Published"), Plex fell back to Relay, and clients reported "not authorized".

Fix: advertise <dashed-ip>.<serverhash>.plex.direct -- public DNS that resolves
to the embedded address, so it points at the LAN VIP and matches the wildcard
cert. Verified with full TLS validation (no curl -k): 200 + verify OK, where
the bare-IP form fails to connect.

Declared as ADVERTISE_IP so git owns the value instead of a web form: the
image's 40-plex-first-run writes it into customConnections on every pod start,
outside the claim guard.

Does NOT fix off-LAN access -- the advertised address is RFC1918 and the WAN
tcp/32400 forward remains unverified. ManualPortMappingMode=1 with an absent
port is left as-is (no GitOps path exists for it).

Touches clusters/** -> sensitive paths -> needs the operator's
/approve-override, deliberately not self-posted (CLAUDE.md 1).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
jakman85andClaude Opus 5 committed 2026-10-04 02:53:01 -05:00
1 parent c95b1c7121
commit 1f4552d409
5 files changed
+226 -9

No files matched your search

+48 -8
View File
@@ -72,14 +72,54 @@ env:
secretKeyRef:
name: plex-claim
key: PLEX_CLAIM
# ADVERTISE_IP ("Custom server access URLs") is DEFERRED, not accidentally omitted. It tells Plex
# which URL to advertise to plex.tv for REMOTE clients. The only candidate is
# https://plex.home.keithjackson.dev, but that host resolves via split-horizon DNS to the INTERNAL
# Gateway VIP (conformance/tests/l2-behavioral/dns-internal-resolution), and both its public
# reachability and whether the TLS-terminating Cilium Gateway proxies Plex's 32400 API correctly for
# remote access are UNVERIFIED. Advertising a wrong/internal-only URL breaks remote access for ALL
# clients, so per "prefer safety over completeness" it is left unset. FOLLOW-UP: once remote
# reachability through the Gateway is confirmed, set ADVERTISE_IP: "https://plex.home.keithjackson.dev:443".
# ADVERTISE_IP ("Custom server access URLs") — NOW SET. This replaces a DEFERRAL note that stood
# here until 2026-10-04, and the deferral's premise has changed: it weighed only ONE candidate,
# `https://plex.home.keithjackson.dev` through the L7 Gateway. The operator chose the NATIVE L4
# path instead on 2026-10-03 (apps/wave-0/plex-remote.yaml) so streams go straight to
# ${PLEX_L4_VIP}:32400 and bypass the Envoy hop. What was still missing was a URL whose TLS
# CERTIFICATE validates — and getting that wrong is what took the service down.
#
# THE VALUE IS A `plex.direct` NAME, NOT THE RAW VIP, AND THAT IS THE WHOLE POINT. Plex serves
# 32400 with its own certificate; measured live 2026-10-04 it carries exactly one name:
# CN = *.<serverhash>.plex.direct (one SAN, no IP SANs at all)
# so `https://<ip>:32400` can NEVER validate. `<dashed-ip>.<serverhash>.plex.direct` is Plex's own
# mechanism for this: it is PUBLIC DNS that resolves to the embedded address, so the name points at
# the LAN VIP while the wildcard cert above matches it. Measured 2026-10-04 with FULL verification
# (no `curl -k`):
# https://192-168-2-24.<hash>.plex.direct:32400/identity -> 200, TLS verify OK
# https://192.168.2.24:32400/identity -> 000, cert validation FAILED
#
# THIS FIELD EXISTS BECAUSE AUTO-DISCOVERY CANNOT WORK HERE. Left empty, Plex publishes the
# addresses it can see itself — which from a pod is the overlay IP (`10.0.2.136`), useless to a LAN
# client. The VIP has to be advertised explicitly; there is no "just clear it" fix.
#
# WHAT WENT WRONG, recorded so it is not re-introduced by hand. customConnections OVERRIDES Plex's
# own publishing, and on 2026-10-04 it held two hand-typed URLs, both uncompletable:
# - `https://192.168.2.24:32400` -> cert cannot cover an IP. Measured: a storm of
# `CERT: incomplete TLS handshake ... sslv3 alert certificate unknown` in Plex's log every few
# seconds, from REAL LAN clients arriving through the VIP.
# - `https://plex.home.keithjackson.dev:32400` -> nothing listens. The Gateway serves this host on
# 443; measured `http=000` against 192.168.2.20:32400.
# With every advertised connection dead, plex.tv had nothing publishable, sat at
# `mapping state 'Mapped - Not Published'`, fell back to Plex Relay, and THE SERVER DISAPPEARED
# FROM THE ACCOUNT — clients reported "not authorized".
#
# DECLARING IT HERE rather than in the web UI is the durable half of the fix. The image's
# /etc/cont-init.d/40-plex-first-run runs `setPref "customConnections" "${ADVERTISE_IP}"` (line 127)
# OUTSIDE the PLEX_CLAIM/PlexOnlineToken guard, and its `/.firstRunComplete` marker sits on the
# container's OVERLAY fs, not the /config PVC — so this is re-applied on EVERY pod start and git,
# not a form field, owns the value. Editing this env rolls the Deployment, which is what applies it.
#
# TWO LIMITS, stated rather than discovered later:
# - THE HASH IS SERVER IDENTITY, which is why the whole URL is a cluster-var and not built from
# ${PLEX_L4_VIP}: envsubst cannot dash an IP, and the hash is not derivable from anything in
# this tree. It is not a secret (it ships in the cert and in the published connection list), but
# if Plex reissues under a new hash this URL goes stale and must be re-read from the live cert.
# - THIS RESTORES LAN CLIENTS AND THE ACCOUNT LISTING, NOT WAN. Remote clients still need the
# off-repo tcp/32400 port-forward (runbooks/plex-remote-access.md). Once that exists, the WAN
# twin of this URL can be appended comma-separated — customConnections takes a list.
- name: ADVERTISE_IP
value: ${PLEX_ADVERTISE_URL}
# HARDWARE TRANSCODING — the host iGPU's render device (schema 1.8.0 `hardware`; R-PLAT-02).
# INTENT ONLY, AND THE MECHANISM DELIBERATELY DOES NOT LIVE HERE. This says "this workload needs an
# Intel Quick Sync render device"; it does NOT name a device path and it does NOT name a resource.