- runtime rows: podman quadlet under the systemd user generator, pinned image digests, in-place bind mounts, identity model, appnet aliases - cutover/rollback section on Plex.md (mask-native-unit lever, decommission gate); drop the false 'updates are apt-only' and 'snap refresh' gotchas - update path is now deploy.sh dankserver --service plex|tautulli
3.8 KiB
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 | UsernsMode=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(neverdisable— on these hostsdisabledeletes the unit file), then starts the quadlet; the deployer blocks until/identityanswers 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
:32400exposure to the LAN is unauthenticated by design (Plex owns its own auth via claim tokens).
Gotchas
- 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.
- Updates are commit-driven, not apt. The OS package is retired at
cutover; upgrading PMS means pinning a new
-lstag in the unit file and redeploying — never run:latest. - 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 inPreferences.xmlinside the RW data bind, preserved by the migration.