Migrate Plex from ESXi VM to Docker container
Plex ran on a dedicated Debian 11 VM at 10.100.0.24 until that OS reached LTS EOL on 2026-08-31 and apt security updates started 404ing. It now runs as a host-networked container on the Docker host at 10.100.0.35. Adds plex-docker-migration.md: the decision record and the executed procedure. The two choices worth knowing about are that media is bind mounted at the paths the library DB already stores (/mnt/nfs/*) so the migration rewrote none of its 32,262 absolute paths, and that the container runs on host networking so Plex still sees real client source IPs and does not throttle LAN playback as remote. Preferences.xml was carried across, so the server kept machine identifier 7aa65063599874eac3d9a2f62df74c1816400c88 and Tautulli, seerr and existing clients continued working without reconfiguration. Verified after cutover: libraries 1959/421/146 and 11,481 history entries, all matching the pre-migration baseline exactly. Rewrites plex.md for the container, adds plex to docker.md, and updates the component list in CLAUDE.md. The old VM is retained powered on with plexmediaserver stopped and disabled as rollback, so docs for ESXi and Veeam are deliberately left describing it until decommission. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,66 +1,58 @@
|
||||
# Plex Media Server
|
||||
|
||||
> **Migrated to Docker 2026-09-16.** Plex ran on a dedicated Debian 11 VM at 10.100.0.24 until that OS reached LTS EOL (2026-08-31). It now runs as a container on the [Docker host](docker.md). The old VM still exists, powered on but with `plexmediaserver` stopped and disabled, as rollback. Full procedure: [plex-docker-migration.md](plex-docker-migration.md).
|
||||
|
||||
## Access
|
||||
|
||||
- **Hostname**: plex
|
||||
- **FQDN**: plex.lan.dohertylan.com
|
||||
- **IP**: 10.100.0.24 (LAN_100) / 10.50.0.31 (DATA_50)
|
||||
- **OS**: Debian 11 (Bullseye), kernel 5.10.0-11-amd64
|
||||
- **SSH**: `ssh dohertj2@10.100.0.24` (passwordless)
|
||||
- **Web UI**: http://10.100.0.24:32400/web
|
||||
- **Host**: DOCKER (10.100.0.35), container `plex`
|
||||
- **Web UI (LAN)**: http://10.100.0.35:32400/web
|
||||
- **Remote access**: WAN TCP 32400 port-forwarded on UDM Pro → **10.100.0.35**:32400 (rule `PLEX`, id `67ebfaef41b7da3e559ab08d`). Public IP 208.161.27.232. Also reachable at https://plex.dohertylan.com (Traefik + Authelia SSO), but Plex does not advertise that URL (`customConnections` unset), so clients use the `:32400` path.
|
||||
- **Shell**: `docker exec -it plex bash` (no separate SSH host any more)
|
||||
|
||||
## Hardware (VM on ESXi)
|
||||
## Container
|
||||
|
||||
- **CPU**: 8 vCPUs (Intel Xeon E5-2697 v4 @ 2.30GHz)
|
||||
- **RAM**: 7.8 GB
|
||||
- **Disk**: /dev/sda1 125 GB ext4 (80 GB free)
|
||||
- **Image**: `lscr.io/linuxserver/plex:latest` (running `1.43.4.10903-e5521bd8c-ls324`)
|
||||
- **Compose**: `/opt/plex/docker-compose.yml`, rendered by the `plex` Ansible role
|
||||
- **Networking**: `network_mode: host` — needed for GDM discovery (32410-32414/udp) and real client source IPs, so LAN clients are not misclassified as remote
|
||||
- **PUID/PGID**: 1000/1000
|
||||
- **`VERSION=docker`**: pins Plex to the image tag and disables the in-container self-updater
|
||||
|
||||
## Network
|
||||
### Volumes
|
||||
|
||||
| Interface | MAC | IP | MTU | Port Group |
|
||||
|-----------|-----|-----|-----|------------|
|
||||
| ens192 | 00:0c:29:4a:ef:3d | 10.100.0.24/24 | 1500 | LAN_100 |
|
||||
| ens224 | 00:0c:29:4a:ef:47 | 10.50.0.31/24 | 9000 | DATA_50 |
|
||||
| Host | Container | Notes |
|
||||
|---|---|---|
|
||||
| `/opt/plex/config` | `/config` | 32 GB library (metadata, thumbnails, DBs) |
|
||||
| `/opt/plex/transcode` | `/transcode` | Local-disk scratch, never NFS |
|
||||
| `/mnt/share/Media/Movies` | `/mnt/nfs/Movies` | Legacy path — matches the library DB |
|
||||
| `/mnt/share/Media/TV` | `/mnt/nfs/TV` | ″ |
|
||||
| `/mnt/share/Media/Anime` | `/mnt/nfs/Anime` | ″ |
|
||||
|
||||
- **Default gateway**: 10.100.0.1 (via ens192)
|
||||
- **DNS**: 10.100.0.1
|
||||
- **Domain**: lan.dohertylan.com
|
||||
> **Why the `/mnt/nfs/*` container paths look odd:** the Plex library DB stores 32,262 absolute media paths from the old VM. Mounting the media at those exact paths inside the container meant the migration touched zero DB rows and could not trigger a library rematch. Do not "tidy" these to `/data/*` without rewriting `section_locations`, `media_parts` **and** `media_streams`.
|
||||
|
||||
## Plex Media Server
|
||||
## Identity
|
||||
|
||||
- **Version**: 1.43.0.10492-121068a07
|
||||
- **Service**: `plexmediaserver.service` — enabled, active (running)
|
||||
- **Run user**: plex
|
||||
- **Data dir**: `/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/`
|
||||
- **MachineIdentifier**: `7aa65063599874eac3d9a2f62df74c1816400c88` (preserved across the migration — Tautulli, seerr and all clients kept working)
|
||||
- **No Plex Pass** (`PlexOnlineHome="0"`) — software transcoding only; there is no usable hardware encoder on this host (VMware SVGA / `vmwgfx`)
|
||||
|
||||
## Auto Updates
|
||||
## Libraries
|
||||
|
||||
Plex is updated automatically via the **official Plex apt repository** and Debian's built-in `apt-daily-upgrade.timer`.
|
||||
| ID | Name | Root path | Items (2026-09-16) |
|
||||
|---|---|---|---|
|
||||
| 1 | Movies | `/mnt/nfs/Movies` | 1,959 |
|
||||
| 2 | TV Shows | `/mnt/nfs/TV` | 421 |
|
||||
| 4 | Anime | `/mnt/nfs/Anime` | 146 |
|
||||
|
||||
- **Repo**: `deb [signed-by=/etc/apt/keyrings/plexmediaserver.v2.gpg] https://repo.plex.tv/deb/ public main`
|
||||
- **Sources list**: `/etc/apt/sources.list.d/plexmediaserver.list`
|
||||
- **GPG key**: `/etc/apt/keyrings/plexmediaserver.v2.gpg` (PlexSign.v2.key)
|
||||
- **Update mechanism**: `apt-daily.timer` fetches package lists, `apt-daily-upgrade.timer` installs upgrades (both run daily via systemd)
|
||||
## Updates
|
||||
|
||||
Previously used the third-party [plexupdate](https://github.com/mrworf/plexupdate) script (`/opt/plexupdate/plexupdate.sh` via `/etc/cron.daily/plexupdate`), which downloaded `.deb` files directly from plex.tv. This was removed on 2026-03-13 in favor of the official apt repo after Plex announced deprecation of the old update method.
|
||||
Managed by Ansible, not by Plex. `ansible-playbook update.yml -e only=plex` pulls the latest image and recreates the container; the full `update.yml` pass includes it. The in-container updater is disabled via `VERSION=docker`.
|
||||
|
||||
## NFS Media Mounts (via TrueNAS DATA_50 network)
|
||||
## Integrations pointing at this server
|
||||
|
||||
All mounts use NFS 4.2 with `nconnect=4,async,_netdev,nofail,x-systemd.automount`.
|
||||
|
||||
| Mount Point | NFS Export |
|
||||
|-------------|-----------|
|
||||
| /mnt/nfs/Movies | truenas-nfs:/mnt/mypool/share/Media/Movies |
|
||||
| /mnt/nfs/TV | truenas-nfs:/mnt/mypool/share/Media/TV |
|
||||
| /mnt/nfs/Anime | truenas-nfs:/mnt/mypool/share/Media/Anime |
|
||||
|
||||
`truenas-nfs` resolves via `/etc/hosts` to multiple TrueNAS DATA_50 IPs (10.50.0.25–28) for NFS multipathing.
|
||||
|
||||
## Host Aliases (/etc/hosts)
|
||||
|
||||
| IP | Hostname |
|
||||
|----|----------|
|
||||
| 10.50.0.25 | nfs1, truenas-nfs |
|
||||
| 10.50.0.26 | nfs2, truenas-nfs |
|
||||
| 10.50.0.27 | nfs3, truenas-nfs |
|
||||
| 10.50.0.28 | nfs4, truenas-nfs |
|
||||
| Service | Where configured |
|
||||
|---|---|
|
||||
| Sonarr / Radarr | "Plex Media Server" connection (id 2), `updateLibrary: true` — stored in `sonarr.db`/`radarr.db`, **not** templated by Ansible |
|
||||
| Tautulli | `/opt/tautulli/config.ini` (`pms_ip`, `pms_url`) |
|
||||
| seerr | `/opt/seerr/settings.json` (`plex.ip`) |
|
||||
| Uptime Kuma | monitor id 17 in `/opt/uptime_kuma/data/kuma.db` |
|
||||
| Homepage | `/opt/homepage/config/services.yaml` |
|
||||
| Traefik | `/opt/traefik/traefik/rules/external-services.yml` (file provider) |
|
||||
|
||||
Reference in New Issue
Block a user