468 lines
20 KiB
Markdown
468 lines
20 KiB
Markdown
# PLEX32 — Plex Media Server
|
||
Device Type: **Dell Wyse 5070 Thin Client**
|
||
Hostname: **plex32**
|
||
IP Address: **192.168.150.45**
|
||
VLAN: **50 — Lab / Servers**
|
||
|
||
Last Updated: 2026-07-12
|
||
|
||
---
|
||
|
||
## 🧩 Role & Purpose
|
||
PLEX32 is the **dedicated Plex Media Server** for the KingDezigns network.
|
||
It replaced Plex on NAS08, migrating the service to a more capable x86 machine that supports advanced Plex Pass features including **Sonic Radio** — an AI-driven music playlist and discovery feature that requires CPU capabilities not available on Raspberry Pi hardware.
|
||
|
||
All media files remain stored on NAS08 and are accessed via NFS mounts. PLEX32 handles only transcoding and Plex server logic — it does not store media locally.
|
||
|
||
This device is the **single Plex Media Server** for the KingDezigns network and is publicly accessible via `plex.kingdezigns.com` through NPM on HAS.
|
||
|
||
---
|
||
|
||
## 🖥️ Hardware
|
||
- Dell Wyse 5070 Thin Client
|
||
- Intel Celeron J4105 — 1.50GHz (4 cores) — Intel Quick Sync supported
|
||
- 8GB RAM
|
||
- 32GB eMMC (OS drive — no SMART support, health monitored via filesystem)
|
||
- Gigabit Ethernet
|
||
|
||
### **Storage**
|
||
| Device | Type | Capacity | Role |
|
||
|--------|------|----------|------|
|
||
| mmcblk0 | eMMC | 29.1GB | OS / system drive |
|
||
| /mnt/plex/config | NFS (NAS08) | — | Plex config backup destination only — not used by container |
|
||
| /mnt/plex/transcode | NFS (NAS08) | — | Transcode scratch (local at /opt/plex/transcode) |
|
||
| /mnt/plex/media | NFS (NAS08) | 1.8TB | Media library |
|
||
|
||
> Note: Plex config and transcode directories are stored **locally** at `/opt/plex/` — not on NFS. The NFS config mount (`/mnt/plex/config`) is used as the backup destination by `plex32_backup.sh`. Only the media library is actively used by the container.
|
||
|
||
---
|
||
|
||
## 🌐 Network Placement
|
||
- VLAN: **50 — Lab / Servers**
|
||
- IP: **192.168.150.45**
|
||
- Access Type: LAN / Cable
|
||
|
||
This placement ensures:
|
||
- Isolation from trusted user devices
|
||
- Access to NAS08 NFS shares over local VLAN 50
|
||
- Direct access to Pi‑hole DNS
|
||
- Reduced attack surface
|
||
- Accessible via NPM reverse proxy on HAS
|
||
|
||
---
|
||
|
||
## 📦 Primary Functions
|
||
|
||
### **Core Services**
|
||
- **Plex Media Server** (Docker — linuxserver/plex:latest)
|
||
- **Tautulli** (Docker — linuxserver/tautulli:latest) — playback history, monitoring, and alerts
|
||
|
||
### **Plex Libraries**
|
||
| Library | Path in Container | Source on NAS08 |
|
||
|---------|------------------|-----------------|
|
||
| Music | /media/03 - Music | /export/kingdezigns-public/03 - Music |
|
||
| Videos | /media/04 - Videos/Movies | /export/kingdezigns-public/04 - Videos/Movies |
|
||
| Photos | /media/02 - Photos | /export/kingdezigns-public/02 - Photos |
|
||
|
||
### **Plex Pass**
|
||
- **Lifetime Plex Pass** — confirmed active on this server
|
||
- Enables: Sonic Radio, hardware transcoding (Intel Quick Sync), mobile sync, offline downloads
|
||
|
||
### **Library Codec Profile**
|
||
| Codec | Count | Notes |
|
||
|-------|-------|-------|
|
||
| HEVC Main 10 | ~90 | 10-bit HDR — Direct Streams on Roku, hardware transcode via Quick Sync if needed |
|
||
| H.264 High | 29 | Direct Play on all clients |
|
||
| Audio | 119 AAC | 100% AAC — never forces audio transcode |
|
||
| Subtitles | 1168 SRT + 279 PGS | PGS only burns in if manually selected — Subtitle Mode set to Manually Selected |
|
||
|
||
---
|
||
|
||
## 🐳 Docker Configuration
|
||
|
||
### **Compose File Location**
|
||
```
|
||
~/docker/plex/docker-compose.yml
|
||
```
|
||
|
||
### **Compose Contents**
|
||
```yaml
|
||
services:
|
||
plex:
|
||
image: lscr.io/linuxserver/plex:latest
|
||
container_name: plex
|
||
network_mode: host
|
||
environment:
|
||
- PUID=1000
|
||
- PGID=1001
|
||
- TZ=America/New_York
|
||
- VERSION=docker
|
||
devices:
|
||
- /dev/dri:/dev/dri
|
||
group_add:
|
||
- "44"
|
||
- "993"
|
||
volumes:
|
||
- /opt/plex/config:/config
|
||
- /opt/plex/transcode:/transcode
|
||
- /mnt/plex/media:/media
|
||
restart: unless-stopped
|
||
|
||
tautulli:
|
||
image: lscr.io/linuxserver/tautulli:latest
|
||
container_name: tautulli
|
||
environment:
|
||
- PUID=1000
|
||
- PGID=1001
|
||
- TZ=America/New_York
|
||
volumes:
|
||
- /opt/tautulli/config:/config
|
||
ports:
|
||
- 8181:8181
|
||
restart: unless-stopped
|
||
```
|
||
|
||
> **devices + group_add:** Required for Intel Quick Sync hardware transcoding. The container needs `/dev/dri` device access plus supplementary group membership for `video` (GID 44) and `render` (GID 993). Without `group_add`, Plex silently falls back to software transcoding even with hardware acceleration enabled in settings.
|
||
|
||
### **Key Docker Commands**
|
||
```bash
|
||
# Start all services
|
||
cd ~/docker/plex && docker compose up -d
|
||
|
||
# Stop all services
|
||
cd ~/docker/plex && docker compose down
|
||
|
||
# Update Plex
|
||
cd ~/docker/plex && docker compose pull && docker compose up -d
|
||
|
||
# View Plex logs
|
||
docker logs plex --tail 50
|
||
|
||
# View Tautulli logs
|
||
docker logs tautulli --tail 50
|
||
|
||
# Check container status
|
||
docker ps
|
||
```
|
||
|
||
---
|
||
|
||
## 🎬 Hardware Transcoding — Intel Quick Sync
|
||
|
||
The J4105 supports Intel Quick Sync via `/dev/dri`. Both decode and encode are offloaded to the GPU.
|
||
|
||
### **Verification**
|
||
Check GPU access from inside the container:
|
||
```bash
|
||
docker exec -it plex id
|
||
# Should show groups 44 (video) and 993 (render/group01b4) in output
|
||
docker exec -it plex ls -la /dev/dri
|
||
# Should show card0 and renderD128
|
||
```
|
||
|
||
Verify during active transcode — Plex Dashboard should show:
|
||
```
|
||
4K (HEVC Main 10) (hw)
|
||
SD (HEVC) — Transcode (hw)
|
||
```
|
||
|
||
The `(hw)` suffix on both lines confirms Quick Sync is handling decode and encode.
|
||
|
||
### **Plex Settings**
|
||
- Settings → Transcoder → **Use hardware acceleration when available** ✅
|
||
- Settings → Transcoder → **Use hardware-accelerated video encoding** ✅
|
||
- Settings → Transcoder → **Transcoder temporary directory:** `/transcode`
|
||
|
||
---
|
||
|
||
## 📊 Tautulli
|
||
|
||
Tautulli provides playback history, live session monitoring, and email alerts.
|
||
|
||
- **Web UI:** `http://192.168.150.45:8181`
|
||
- **Config:** `/opt/tautulli/config`
|
||
- **Connected to:** Plex at `192.168.150.45:32400`
|
||
|
||
### **Active Notifications**
|
||
| Trigger | Destination | Purpose |
|
||
|---------|-------------|---------|
|
||
| Plex Server Down | rufus.king@kingdezigns.com | Alert when Plex stops responding |
|
||
| Plex Server Back Up | rufus.king@kingdezigns.com | Confirmation when Plex recovers |
|
||
|
||
### **SMTP Configuration**
|
||
Uses same Zoho SMTP credentials as all other KingDezigns email alerts:
|
||
- Server: `smtppro.zoho.com` / Port: `465` / TLS enabled
|
||
- From: `rufus.king@kingdezigns.com`
|
||
|
||
---
|
||
|
||
## 📁 NFS Mounts
|
||
|
||
Configured in `/etc/fstab` — mounts automatically on boot:
|
||
|
||
```
|
||
192.168.150.35:/export/kingdezigns-all/Docker/plex/config /mnt/plex/config nfs defaults,_netdev 0 0
|
||
192.168.150.35:/export/kingdezigns-all/Docker/plex/transcode /mnt/plex/transcode nfs defaults,_netdev 0 0
|
||
192.168.150.35:/export/kingdezigns-public /mnt/plex/media nfs defaults,_netdev 0 0
|
||
```
|
||
|
||
> Note: `/mnt/plex/config` is used by `plex32_backup.sh` as the backup destination — not by the Plex container. `/mnt/plex/transcode` exists in fstab but Plex uses the local `/opt/plex/transcode` directory instead.
|
||
|
||
---
|
||
|
||
## 🌍 External Access
|
||
|
||
- **Domain:** `plex.kingdezigns.com`
|
||
- **Proxy:** NPM on HAS (192.168.150.30) → 192.168.150.45:32400
|
||
- **SSL:** Let's Encrypt via NPM
|
||
- **Port:** 32400 (Plex default)
|
||
- **Port forwarding:** UCG Max forwards external 32400 → 192.168.150.45
|
||
|
||
---
|
||
|
||
## 🔒 Required Firewall Behavior
|
||
|
||
### **Inbound to PLEX32**
|
||
- Allowed from VLAN 1 (Infrastructure) and VLAN 20 (Trusted) — global rules
|
||
- Allowed from VLAN 50 (local VLAN)
|
||
- External Plex traffic arrives via NPM on HAS (192.168.150.30)
|
||
|
||
### **Outbound from PLEX32**
|
||
- Subject to VLAN 50's global final drop
|
||
- Cannot initiate to VLANs 1, 10, 20, 30, 40
|
||
- Allowed: local VLAN 50 traffic (NFS to NAS08, DNS to Pi-hole, SSH to NAS08 for backup)
|
||
|
||
### **Critical Requirements**
|
||
- Must reach NAS08 (192.168.150.35) on NFS ports for media library and backup destination
|
||
- Must be reachable from HAS (192.168.150.30) for proxied external traffic
|
||
- Port 32400 must be forwarded on UCG Max for direct Plex remote access
|
||
|
||
---
|
||
|
||
## 🔐 Security Measures
|
||
- **Fail2Ban enabled** — `ignoreip` includes `127.0.0.1/8`, `::1`, `192.168.150.0/24`
|
||
- Docker-based service isolation
|
||
- VLAN-level containment
|
||
- No outbound access to other VLANs
|
||
|
||
### **Fail2Ban Configuration**
|
||
`/etc/fail2ban/jail.local`:
|
||
```ini
|
||
[DEFAULT]
|
||
ignoreip = 127.0.0.1/8 ::1 192.168.150.0/24
|
||
```
|
||
|
||
### **System Timezone**
|
||
- Timezone corrected to `America/New_York` on 2026-06-21 — was previously `Etc/UTC`
|
||
- The UTC default caused cron jobs to fire 4 hours early (e.g. 2 AM UTC = 10 PM EDT)
|
||
- Always verify timezone after fresh installs: `timedatectl | grep "Time zone"`
|
||
- Fix: `sudo timedatectl set-timezone America/New_York`
|
||
|
||
### **sudo Without Password**
|
||
`/etc/sudoers.d/rufusking-nopasswd`:
|
||
```
|
||
rufusking ALL=(ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status sshd, /sbin/reboot
|
||
```
|
||
Required by update check script (`apt-get update`), health report script (`fail2ban-client`), and remote reboot script (`reboot`).
|
||
|
||
### **SSH Key Authentication**
|
||
PLEX32 has an SSH key configured to NAS08 — required for the backup script to fetch accurate disk stats without a password prompt:
|
||
```bash
|
||
# Key location on PLEX32
|
||
~/.ssh/id_ed25519
|
||
|
||
# Test
|
||
ssh rufusking@192.168.150.35 "echo NAS08 OK"
|
||
```
|
||
|
||
### **AC Power Recovery (Auto Power-On After Outage)**
|
||
Configured **2026-06-30** after a power outage left PLEX32 powered off (manual power button press required to bring it back up).
|
||
|
||
Dell exposes AC Power Recovery as a writable SMBIOS token — this means it can be set **remotely from within Linux**, without ever entering BIOS setup.
|
||
|
||
**Tooling:**
|
||
```bash
|
||
sudo apt-get install -y libsmbios-bin smbios-utils
|
||
```
|
||
|
||
**Relevant tokens (mutually exclusive — only one should be `true`):**
|
||
| Token | Setting | Desired State |
|
||
|-------|---------|----------------|
|
||
| `0x00a1` | AC Power Recovery Mode (Off) — stays off | `false` |
|
||
| `0x00a2` | AC Power Recovery Mode (Last) — restores prior state | `false` |
|
||
| `0x00a3` | AC Power Recovery Mode (On) — powers on automatically | `true` ✅ |
|
||
|
||
**Command used to set it:**
|
||
```bash
|
||
sudo smbios-token-ctl --activate --token-id=0x00a3
|
||
```
|
||
|
||
**Verify current state:**
|
||
```bash
|
||
sudo smbios-token-ctl --dump-tokens | grep -i -A2 "AC Power Recovery"
|
||
```
|
||
|
||
> Note: `smbios-token-ctl --dump-tokens` throws a harmless `StopIteration` traceback after printing all tokens (hits a malformed token entry near the end of the table) — this does not affect the accuracy of the data already printed, including the AC Power Recovery tokens.
|
||
|
||
**Result:** PLEX32 will now power back on automatically as soon as AC power is restored after an outage — no physical power button press required. (HAS already had equivalent behavior configured.)
|
||
|
||
---
|
||
|
||
## 🗂️ Shared Permissions
|
||
|
||
PLEX32 uses the same `ncshare` group as NAS08 and NAS16 for consistency across the network.
|
||
|
||
| Item | Value |
|
||
|------|-------|
|
||
| Group name | `ncshare` |
|
||
| GID | `1001` |
|
||
| Members | `rufusking` |
|
||
|
||
Verify with:
|
||
```bash
|
||
getent group ncshare
|
||
```
|
||
|
||
---
|
||
|
||
## 💾 Config Backup
|
||
|
||
Plex and Tautulli configs are backed up to NAS08 every 3 days via `plex32_backup.sh`.
|
||
|
||
### **Backup Script**
|
||
- **Location:** `/usr/scripts/plex32/plex32_backup.sh`
|
||
- **Method:** tar locally to `/tmp/`, then single `cp` to NFS (rsync avoided — too slow over NFS for Plex's thousands of small metadata files)
|
||
- **Plex destination (NAS08):** `/export/kingdezigns-all/Docker/plex/config/backups/plex/plex-config-YYYY-MM-DD.tar.gz`
|
||
- **Tautulli destination (NAS08):** `/export/kingdezigns-all/Docker/plex/config/backups/tautulli/tautulli-config-YYYY-MM-DD.tar.gz`
|
||
- **Retention:** 3 copies of each, older ones auto-deleted
|
||
- **Excludes:** Cache, Logs, Crash Reports
|
||
- **Email:** HTML report sent on completion — SUCCESS / PARTIAL / FAILED
|
||
- **SMTP password:** `/etc/plex32-smtp-pass` (chmod 600, owned by rufusking)
|
||
- **Log:** `/var/log/plex32-backup/backup-YYYYMMDD.log` (90 day retention)
|
||
|
||
### **Restore Procedure (run on plex32)**
|
||
```bash
|
||
# 1. Stop containers
|
||
cd ~/docker/plex && docker compose down
|
||
|
||
# 2. Copy archive from NAS08
|
||
cp /mnt/plex/config/backups/plex/plex-config-YYYY-MM-DD.tar.gz /tmp/
|
||
|
||
# 3. Clear current config
|
||
sudo rm -rf /opt/plex/config/Library
|
||
|
||
# 4. Extract backup
|
||
sudo tar -xzf /tmp/plex-config-YYYY-MM-DD.tar.gz -C /opt/plex
|
||
sudo chown -R rufusking:ncshare /opt/plex/config
|
||
|
||
# 5. Restart containers
|
||
cd ~/docker/plex && docker compose up -d
|
||
|
||
# 6. Verify
|
||
docker ps
|
||
# Both plex and tautulli should show Up
|
||
# Open http://192.168.150.45:32400/web and confirm library and watch history intact
|
||
|
||
# 7. Cleanup
|
||
rm /tmp/plex-config-YYYY-MM-DD.tar.gz
|
||
```
|
||
|
||
---
|
||
|
||
## 🖥️ Remote Launcher (KingDezigns001)
|
||
|
||
A launcher script on KingDezigns001 provides a menu-driven interface to run PLEX32 scripts remotely via SSH.
|
||
|
||
- **Launcher script:** `~/scripts/plex32_launcher.sh`
|
||
- **Desktop shortcut:** `~/Desktop/PLEX32-Launcher.desktop`
|
||
- **SSH:** Passwordless — ED25519 key from KingDezigns001 installed on PLEX32
|
||
|
||
### **Menu Options**
|
||
| Option | Script |
|
||
|--------|--------|
|
||
| 1) Update Check | `/usr/scripts/plex32/plex32_update_check.sh` |
|
||
| 2) Health Report | `/usr/scripts/plex32/plex32_health_report.sh` |
|
||
| 3) Plex32 Backup | `/usr/scripts/plex32/plex32_backup.sh` |
|
||
|
||
---
|
||
|
||
## 📅 Scheduled Jobs (cron)
|
||
|
||
| Schedule | Script | Purpose |
|
||
|----------|--------|---------|
|
||
| Daily at 7:00 AM | `/usr/scripts/plex32/plex32_update_check.sh` | Check for OS, Plex, Docker, Fail2Ban updates — email report |
|
||
| Daily at 7:05 AM | `/usr/scripts/plex32/plex32_health_report.sh` | Server health report — disk, NFS, memory, CPU, container status |
|
||
| Every 3 days at 2:00 AM | `/usr/scripts/plex32/plex32_backup.sh` | Archive Plex and Tautulli configs to NAS08 — email report |
|
||
|
||
View cron jobs:
|
||
```bash
|
||
sudo crontab -l
|
||
```
|
||
|
||
> Note: All three PLEX32 scheduled jobs run via **root's crontab**, not `rufusking`'s.
|
||
|
||
### **plex32_update_check.sh — Docker Pull Fix (2026-07-12)**
|
||
The daily update check was intermittently reporting `Plex Media Server = Check failed — could not reach registry` even though `lscr.io` was reachable and disk space was healthy (8.6GB free of 26GB).
|
||
|
||
**Root cause:** The script's `docker pull` step runs under root's cron environment, which uses a minimal default `PATH` that didn't reliably match the interactive `rufusking` shell environment. The script also silently discarded the actual `docker pull` error output, so the true failure reason was never visible in the log or email — every failure was mislabeled with the same generic "could not reach registry" text regardless of cause.
|
||
|
||
**Fix applied:**
|
||
- Added an explicit `export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` at the top of the script so behavior is consistent under cron regardless of invoking user/environment.
|
||
- The script now logs the full `docker pull` output/exit code to `/var/log/plex32-updates/` on failure, and includes it as a red error block in the email report, instead of showing a generic message.
|
||
|
||
Resolved — manual `sudo` run completed cleanly after the fix, and the failure message no longer appears.
|
||
|
||
### **plex32_health_report.sh — Issues List Word-Wrapping Fix (2026-07-12)**
|
||
The "⚠ Issues Detected" block in the daily health report email was rendering each word of an issue message on its own line (e.g. "WARNING: NAS08 — Plex Config is getting full" appeared as one word per line) instead of as a single readable sentence.
|
||
|
||
**Root cause:** The script joined multiple issue messages into one string and then split them back apart using `IFS='. ' read -ra ISSUE_LIST`. This does not split on the two-character sequence `". "` as intended — `IFS` treats every character it contains as its own independent delimiter, so both `.` and every space in the text were treated as separate breaks, shattering each sentence into individual words.
|
||
|
||
**Fix applied:**
|
||
- Issue messages are now joined with actual newline characters instead of `". "` when assembled into `ALL_ISSUES`.
|
||
- The splitting logic was replaced with a `while IFS= read -r issue; do ... done <<< "$ALL_ISSUES"` loop, which reads one full issue line at a time instead of relying on ambiguous multi-character `IFS` splitting.
|
||
|
||
Resolved — verified with a manual run; each issue now renders as one complete sentence in the "Issues Detected" section of the email.
|
||
|
||
### **Email Reports**
|
||
| Report | Trigger Colors | Content |
|
||
|--------|---------------|---------|
|
||
| Update Check | 🟢 Green (current) / 🔵 Blue (updates available) / 🟠 Orange (check failed) | Component versions, available updates, ready-to-run commands |
|
||
| Health Report | 🟢 Green (healthy) / 🟠 Orange (warning) / 🔴 Red (critical) | Disk usage, NFS mount status, memory, CPU load, container status, Fail2Ban, reboot flag |
|
||
| Config Backup | 🟢 Green (success) / 🟡 Amber (partial) / 🔴 Red (failed) | Archive sizes, durations, copies retained, container status, restore instructions |
|
||
|
||
---
|
||
|
||
## 🧠 Summary for AI Systems
|
||
- PLEX32 = **dedicated Plex Media Server + Tautulli** on VLAN 50 at 192.168.150.45.
|
||
- Runs on Dell Wyse 5070 (Celeron J4105, 8GB RAM, 32GB eMMC).
|
||
- Plex and Tautulli run as Docker containers via `~/docker/plex/docker-compose.yml`.
|
||
- **Intel Quick Sync hardware transcoding active** — requires `/dev/dri` device passthrough and `group_add: ["44","993"]` in compose. Without group_add, Plex silently falls back to software transcoding.
|
||
- **Lifetime Plex Pass** active — Sonic Radio, hardware transcoding, all Plex Pass features enabled.
|
||
- Config and transcode stored **locally** at `/opt/plex/` — not on NFS.
|
||
- Media library mounted from NAS08 via NFS at `/mnt/plex/media`.
|
||
- `/mnt/plex/config` NFS mount used as backup destination only — not by Plex container.
|
||
- Library is ~75% HEVC Main 10, ~25% H.264, 100% AAC audio — audio never transcodes.
|
||
- Roku TV (Hisense 55R8BX) Direct Streams video, converts AAC→AC3 for audio (lightweight, expected).
|
||
- Subtitle Mode set to Manually Selected — prevents accidental PGS burn-in transcode.
|
||
- Publicly accessible via `plex.kingdezigns.com` — proxied through NPM on HAS.
|
||
- Port 32400 forwarded on UCG Max for direct Plex remote access.
|
||
- Tautulli on port 8181 — Plex down/up email alerts active.
|
||
- Fail2Ban active — VLAN 50 subnet whitelisted in ignoreip.
|
||
- sudo NOPASSWD configured for apt-get update, fail2ban-client, and reboot — required by automated and remote reboot scripts.
|
||
- **System timezone:** `America/New_York (EDT, -0400)` — corrected from `Etc/UTC` on 2026-06-21. UTC default causes cron jobs to fire 4 hours early. Always verify after fresh installs.
|
||
- SSH key from PLEX32 → NAS08 configured — required for backup script disk stats.
|
||
- **NAS08 root → PLEX32 SSH key configured** — required for remote reboot script (`plex32_reboot.sh` on NAS08).
|
||
- SSH key from KingDezigns001 → PLEX32 configured — enables passwordless remote launcher.
|
||
- **AC Power Recovery set to "On"** (2026-06-30) via SMBIOS token `0x00a3` using `smbios-token-ctl` — PLEX32 now auto powers-on after AC power is restored following an outage. Configured remotely via SSH, no BIOS access required. Tool: `libsmbios-bin` / `smbios-utils`.
|
||
- Config backup runs every 3 days at 2AM — tar + NFS copy, 3 copies retained, HTML email report.
|
||
- `ncshare` group (GID 1001) configured for network-wide permission consistency.
|
||
- eMMC has no SMART support — health monitored via daily health report email.
|
||
- No swap configured — 7.6GB RAM, consistently low utilization.
|
||
- Plex on NAS08 is **permanently disabled** (restart: no in compose).
|
||
- Migrated from NAS08 on 2026-06-18 — full library, watch history, and playlists preserved.
|
||
- **`plex32_update_check.sh` fixed 2026-07-12** — added explicit `PATH` export to fix intermittent `docker pull` failures under root's cron environment; script now logs real `docker pull` error output on failure instead of a generic "could not reach registry" message. All three PLEX32 scheduled jobs run under root's crontab.
|
||
- **`plex32_health_report.sh` fixed 2026-07-12** — fixed the "Issues Detected" email block rendering each word on its own line, caused by a multi-character `IFS='. '` split; issues are now newline-delimited and read back with a `while read` loop.
|
||
|
||
---
|
||
|
||
# ✔️ End of File
|