podman 5.7 podman-user-generator on dankserver hard-fails the whole unit on
the unknown key ('unsupported key UsernsMode in group Container'), so the
first cutover attempt masked the native unit and then found no plex.service
at all. Swap both units to UserNS=host (same --userns=host flag), update the
ownership-contract seam test to pin the exact key, and correct both docs.
Pin the seam: the v1 generator rejects unknown Container keys silently at
deploy distance — the test now pins UserNS=, not the misspelled alias.
71 lines
3.8 KiB
Markdown
71 lines
3.8 KiB
Markdown
# Plex
|
|
|
|
Plex Media Server is the **containerized media server on Dankserver**: a
|
|
podman quadlet (`plex.service`) under the systemd **user** generator,
|
|
generated from `dankserver/plex/quadlet/plex.container`. It is the only media
|
|
server actually listening on this host. Jellyfin, by contrast, is a research
|
|
brief on this host, not a running service (see [[Jellyfin]]).
|
|
|
|
**Host:** Dankserver — **Ports:** 32400/tcp (PMS web + API), 32400 is the
|
|
only port PMS needs for client streaming; LAN clients connect directly,
|
|
public traffic can be fronted by Caddy like every other vhost.
|
|
|
|
## Facts
|
|
|
|
| Item | Value |
|
|
|------|-------|
|
|
| Runtime | podman quadlet, `plex.service` (user manager) — migrated from the native `plexmediaserver.service` OS-package unit (2026-09) |
|
|
| Image | `lscr.io/linuxserver/plex:1.43.3.10896-cb3ebc72d-ls322` (pinned; verified == the ghcr `latest` manifest digest at pin time) |
|
|
| Data root | `/var/lib/plexmediaserver` bind-mounted **in place** as `/config` (RW) — the migration moved zero bytes |
|
|
| Media | `/mnt/entropy` mounted at the same absolute path **read-only** — every library path in the PMS database stayed valid, zero re-scan |
|
|
| Identity | `UserNS=host` (quadlet key for `--userns=host`) + `PUID=997 PGID=984` — container writes land owned 997:984, byte-compatible with the former native unit |
|
|
| Port | `32400/tcp` published on `0.0.0.0` — zero client reconfiguration |
|
|
| Network | `dankserver_appnet`, alias `plex`; Tautulli reaches it at `http://plex:32400` |
|
|
| GPU | none by decision — CPU decode only; the RTX 3090 stays dedicated to `frank-default-small` |
|
|
| Deploy | `./scripts/deploy.sh dankserver --service plex` |
|
|
| Docs | https://support.plex.tv |
|
|
|
|
## Why in-place bind mounts
|
|
|
|
The migration moved zero bytes: the container bind-mounts the native data
|
|
root where it already lived, and the media archive re-mounts at
|
|
`/mnt/entropy` inside the container, so every absolute library path in the
|
|
PMS database keeps resolving. `UsernsMode=host` + `PUID=997/PGID=984` makes
|
|
the container's file identity indistinguishable from the old service's —
|
|
no chown, no re-scan. Rollback is byte-safe at any time before decommission.
|
|
|
|
## Cutover & rollback
|
|
|
|
- First deploy stops and **masks** `plexmediaserver.service` (never
|
|
`disable` — on these hosts `disable` deletes the unit file), then starts
|
|
the quadlet; the deployer blocks until `/identity` answers on 32400.
|
|
- Rollback lever while masked: `systemctl --user stop plex.service && sudo
|
|
systemctl unmask plexmediaserver.service && sudo systemctl start
|
|
plexmediaserver.service`.
|
|
- Decommission (`sudo apt-get -y purge plexmediaserver`) only after explicit
|
|
operator sign-off.
|
|
|
|
## Integration points
|
|
|
|
- **Caddy:** Plex is exempt from the Anubis bot challenge
|
|
(plain-HTTP legacy clients cannot solve JS challenges) — see
|
|
[[Anubis]] "Exempt by construction".
|
|
- **Tautulli** ([[Tautulli]]) is the companion: it polls PMS on the appnet
|
|
for statistics and notifications and makes no sense without Plex.
|
|
- **Auth wall:** if a public vhost is ever pointed at Plex, put the
|
|
Authentik outpost + Anubis chain in front of it like every other guarded
|
|
vhost ([[Authentik]], [[Caddy]]); direct `:32400` exposure to the LAN is
|
|
unauthenticated by design (Plex owns its own auth via claim tokens).
|
|
|
|
## Gotchas
|
|
|
|
1. **Do not benchmark on it blind.** Transcoding is CPU-only now but still
|
|
contends with the LLM fleet's host-RAM expert streaming; stop the service
|
|
before benchmark runs, per the Benchmarking Policy.
|
|
2. **Updates are commit-driven, not apt.** The OS package is retired at
|
|
cutover; upgrading PMS means pinning a new `-ls` tag in the unit file and
|
|
redeploying — never run `:latest`.
|
|
3. The claim token is the identity of this server; document it in the host
|
|
`.env`, never in this repo (secret rules apply). The token lives in
|
|
`Preferences.xml` inside the RW data bind, preserved by the migration.
|